123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112letall?(pos=0)?lenres:_Seq.t=ifpos<0theninvalid_arg"Re.all";(* index of the first position we do not consider.
!pos < limit is an invariant *)letlimit=matchlenwith|None->String.lengths|Somel->ifl<0||pos+l>String.lengthstheninvalid_arg"Re.all";pos+lin(* iterate on matches. When a match is found, search for the next
one just after its end *)letrecauxposon_match()=ifpos>limitthenSeq.Nil(* no more matches *)else(matchCompile.match_str~groups:true~partial:falseres~pos~len:(limit-pos)with|Matchsubstr->letp1,p2=Group.offsetsubstr0inifon_match&&p1=pos&&p1=p2then(* skip empty match right after a match *)aux(pos+1)false()else(letpos=ifp1=p2thenp2+1elsep2inSeq.Cons(substr,auxpos(p1<>p2)))|Running_|Failed->Seq.Nil)inauxposfalse;;letmatches?pos?lenres:_Seq.t=all?pos?lenres|>Seq.map(funsub->Group.getsub0);;letsplit_full?(pos=0)?lenres:_Seq.t=ifpos<0theninvalid_arg"Re.split";letlimit=matchlenwith|None->String.lengths|Somel->ifl<0||pos+l>String.lengthstheninvalid_arg"Re.split";pos+lin(* i: start of delimited string
pos: first position after last match of [re]
limit: first index we ignore (!pos < limit is an invariant) *)letpos0=posinletrecauxstateipos()=matchstatewith|`Idlewhenpos>limit->(* We had an empty match at the end of the string *)assert(i=limit);Seq.Nil|`Idle->(matchCompile.match_str~groups:true~partial:falseres~pos~len:(limit-pos)with|Matchsubstr->letp1,p2=Group.offsetsubstr0inletpos=ifp1=p2thenp2+1elsep2inletold_i=iinleti=p2inifold_i=p1&&p1=p2&&p1>pos0then(* Skip empty match right after a delimiter *)auxstateipos()elseifp1>pos0then((* string does not start by a delimiter *)lettext=String.subsold_i(p1-old_i)inletstate=`Yield(`Delimsubstr)inSeq.Cons(`Texttext,auxstateipos))elseSeq.Cons(`Delimsubstr,auxstateipos)|Running_->Seq.Nil|Failed->ifi<limitthen(lettext=String.subsi(limit-i)in(* yield last string *)Seq.Cons(`Texttext,auxstatelimitpos))elseSeq.Nil)|`Yieldx->Seq.Cons(x,aux`Idleipos)inaux`Idlepospos;;letsplit?pos?lenres:_Seq.t=letseq=split_full?pos?lenresinletrecfilterseq()=matchseq()with|Seq.Nil->Seq.Nil|Seq.Cons(`Delim_,tl)->filtertl()|Seq.Cons(`Texts,tl)->Seq.Cons(s,filtertl)infilterseq;;letsplit_delim?pos?lenres:_Seq.t=letseq=split_full?pos?lenresinletrecfilter~delimseq()=matchseq()with|Seq.Nil->ifdelimthenSeq.Cons("",fun()->Seq.Nil)elseSeq.Nil|Seq.Cons(`Delim_,tl)->ifdelimthenSeq.Cons("",fun()->filter~delim:truetl())elsefilter~delim:truetl()|Seq.Cons(`Texts,tl)->Seq.Cons(s,filter~delim:falsetl)infilter~delim:trueseq;;