This understands parentheses, and works on the regexp live (i.e. not parsed first)
#define C char
#define M m(s,o
m(C*s,C*o,C*S,C*p,C*P,C T){C*n=P-1,*q=s,h=*P==41,c=1;for(;h*c;c-=*n--==40)c+=*n==41;
c=*P-42;c=p-P?c-82?T&&c&~1&&c-21?h?2:*S==*P&s<S?M,S-1,p,n,2)||(T&4&&M,S-1,p,P,T|1)):
4:M,T?S:o,p,P-1,T?c&~1?3:7-c:0):T&&s==S||M,o,p,P-1,2):T&&s==S;if(c==2)for(c=4;q<=S;q
++)c|=m(q,S,S,n+h,P-h,2)?M,q,p,n,2)||q<S&T/4&&M,q,p,P,T&6):0;return
c&4?c&1?:T&1&&M,S,p,n,2)||M,o,p,n,0):c;}main(C*w,C**v){C*u;for(w=*++v;*++v;)puts(m(*v
-1,u,u=index(*v,0)-1,w-1,index(w,0)-1,2)?"true":"false");}
compiling with -Wall complains about argc being char. Will crash on illegal patterns.
This parses regexp and string from right to left, saving a few chars.
input on argv, output in reverse normal order:
$ ./a.out ab*a aa abba abab b
true
true
false
false
$ ./a.out "0*1|10" 1 10 0110 00001
true
true
false
true
$ ./a.out "0*(1|1+0)" 1 10 0110 00001
true
true
true
true
$ ./a.out "a?b+|(a+b|b+a?)+" abb babab aaa aabba a b
true
true
false
true
false
true
$ ./a.out "((A|B|C)+(a|(bbbbb)|bb|c)+)+" ABCABCaccabbbbbaACBbbb
false
$ ./a.out "((A|B|C)+(a|(bbbbb)|bb|c)+)+" ABCABCaccabbbbbaACBbbbb
true
GolfScript - 254 chars
n%([]:B:$:_"()"@*{:I"()*+|?"[{}/]?[{[[0B$,+:B))\;)]_]+}{B)):ß;:B;qß(:ß;}{8q}{[[0ß0$,)]]+}:8{[[0B-1=:ß)]]+:$q}{ß>$ß<\([0+$,+]\++}:q{[[I$,:ß)]]+}]=~:$}/;{n+[0]:3\{:c;;3:1_:3;{,}{)[$=]_*2/{~\.{c={3|:3}*;}{;.1|1,\:1,<{+0}*;}if}/}/;}/;1$,?)"true""false"if n}%
Somewhat straightforwardly, the first loop converts the regex into an NFA, which the second loop runs.
Sun Aug 22 00:58:24 EST 2010
(271→266) changed variable names to remove spacesSun Aug 22 01:07:11 EST 2010
(266→265) made []
a variableSun Aug 22 07:05:50 EST 2010
(265→259) made null state transitions inlineSun Aug 22 07:19:21 EST 2010
(259→256) final state made implicitMon Feb 7 19:24:19 EST 2011
(256→254) using "()""str"*
$ echo "ab*a aa abba abab b"|tr " " "\n"|golfscript regex.gs
true
true
false
false
$ echo "0*1|10 1 10 0110 00001"|tr " " "\n"|golfscript regex.gs
true
true
false
true
$ echo "0*(1|1+0) 1 10 0110 00001"|tr " " "\n"|golfscript regex.gs
true
true
true
true
$ echo "a?b+|(a+b|b+a?)+ abb babab aaa aabba a b"|tr " " "\n"|golfscript regex.gs
true
true
false
true
false
true
$ echo "((A|B|C)+(a|(bbbbb)|bb|c)+)+ ABCABCaccabbbbbaACBbbb ABCABCaccabbbbbaACBbbbb"|tr " " "\n"|golfscript regex.gs
false
true
This is not fully golfed to the bare minimum yet, but I wanted to try and see if parsing the regexp first would make a difference to interpreting it live. It does, because it costs more, although both parsing and matching are easier to write/understand.
#define Q struct q
#define C char
#define R return
Q{Q*u,*n,*a;C c,m};Q*P(C*p,C*e){Q*r=calloc(99,1);C*n=p+1,c=1,w;if(p==e)R
r;if(*p==40){for(;c;)c+=(*n==40)-(*n++==41);r->u=P(p+1,n-1);}else
if(*p=='|'){r->a=P(p+1,e);R r;}else r->c=*p;if(n<e){if(*n==43)*n=42,r->n=P(p,e);else
w=*n==42|*n==63,r->n=P(n+w,e),r->m=w?*n:0;r->a=r->n->a;}R r;}M(Q*r,C*s,C*o,C*z){C*p,
e;e=r?r->m==63|r->m==42&&M(r->n,s,o,z)?:*s&&r->c==*s?M(r->m==42?r:r->n,s+1,o,z):2:s
==z;if(e-2)R e;for(p=s,e=0;!r->c&p<=z;p++)e|=M(r->u,s,s,p)&(r->m!=42|p>s)&&M(r->m==
42?r:r->n,p,p,z);R e||r->a&&M(r->a,o,o,z);}main(C
c,C**v){for(;--c>1;)puts(M(P(v[1],index(v[1],0)),v[c],v[c],index(v[c],0))?"true":"false");}
it parses a regexp into a struct, where each struct has:
*
or ?
-- (pat)+
is parsed into (pat)(pat)*
right away which makes matching far easiermain=getLine>>=f.words
d=reverse
u=0<1
j=[]
f(r:s)=mapM_(print.any null.c(d$b$'(':r++")"))s
c%(x,y)=(c:x,y)
s _ _ _[]=(j,j)
s n a b (x:y)|n<1&&x==a=(j,x:y)|x==a=f(-1)|x==b=f 1|u=f 0where f k=x%s(n+k)a b y
b r|m==j=r|u=b$d(o++"(("++x)++")("++z++")/)"++w where(c,m)=s 0'|''!'r;_:v=m;(o,_:x)=s 0'('')'$d c;(z,_:w)=s 0')''('v
(!)g f x=f x>>=g
c[]=(:j)
c r=f!c s where(s,f)=i r
p q@(r:s)|r=='('=(s,(:j))|u=(a,f!g)where(w,f)=i q;(a,g)=p w
_?[]=j
c?(h:r)|c==h=[r]|u=j
i(r:q)=maybe(q,(r?))id$lookup r$zip")/*+?"$p q:zip[e,w,w,w][\s->f s++g s,\s->s:l s,l,\s->s:f s]where(w,f)=i q;(e,g)=i w;l s|f s==j=j|u=f s++(f s>>=l)
import Control.Monad
import Data.List
-- (aa|bb|cc) --> )|)cc()|)bb()aa(((
testRegex = "a?b+|(a+b|b+a?)+"
interpret regex = any null . interpret' regex
interpret' regex = compile (rewrite regex)
mapFst f (x, y) = (f x, y)
splitWhileBalanced _ _ _ "" = ("", "")
splitWhileBalanced n b1 b2 (x:xs)
| n < 1 && x == b1 = ("", x:xs)
| x == b1 = f (-1)
| x == b2 = f 1
| otherwise = f 0
where
f k = mapFst (x:) $ splitWhileBalanced (n+k) b1 b2 xs
rewrite regex = reverse $ moveBars $ '(' : regex ++ ")"
moveBars regex
| mtBar == "" = regex
| otherwise = moveBars $ reverse (hOpen ++ "((" ++ tOpen) ++ ")(" ++ hClose ++ ")/)" ++ tClose
where
(hBar, mtBar) = splitWhileBalanced 0 '|' '!' regex -- '!' is a dummy character
b:tBar = mtBar
(hOpen, o:tOpen) = splitWhileBalanced 0 '(' ')' $ reverse hBar
(hClose, c:tClose) = splitWhileBalanced 0 ')' '(' $ tBar
compile "" = \x -> [x]
compile rs = f <=< compile rs'
where
(rs', f) = compile' rs
paren regex@(r:rs0)
| r == '(' = (rs0, \x -> [x])
| otherwise = (rs2, f <=< g)
where
(rs1, f) = compile' regex
(rs2, g) = paren rs1
compile' (r:rs0) = case r of
'/' -> (rs2, bar)
'*' -> (rs1, star)
'+' -> (rs1, plus)
'?' -> (rs1, mark)
')' -> paren rs0
_ -> (rs0, lit)
where
(rs1, f) = compile' rs0
(rs2, g) = compile' rs1
bar str = f str ++ g str
plus str
| null (f str) = []
| otherwise = f str ++ (f str >>= plus)
star str = str : plus str
mark str = str : f str
lit = maybe [] (\x -> [x]) . stripPrefix [r]
Modifies |
to a suffix form and then reverses the entire regex. Now the operators are in prefix form, making it easy to parse. The program parses the regex like this. The list monad is used for nondeterminism.
> runghc Regex.hs
a?b+|(a+b|b+a?)+ abb babab aaa aabba a b
True
True
False
True
False
True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With