+ [ >string ] dip match-start dup [ to>> ] when ;
+
+<PRIVATE
+
+! XXX: Terrible inefficient regexp match group support
+
+: #match-groups ( regexp -- n/f )
+ raw>> [ CHAR: ( = ] count [ f ] when-zero ;
+
+: nth-index ( n obj seq -- i )
+ [ = dup [ drop 1 - dup 0 < ] when ] with find drop nip ;
+
+: match-group-regexp ( regexp n -- skip-regexp match-regexp )
+ [ [ options>> options>string ] [ raw>> ] bi ] dip
+ CHAR: ( pick nth-index cut CHAR: ) over index 1 + head
+ rot '[ H{ } [ _ <optioned-regexp> ] cache ] bi@ ;
+
+: skip-first-match ( match regexp -- tailseq )
+ first-match [ seq>> ] [ to>> ] bi tail ;
+
+: nth-match ( match regexp n -- slice/f )
+ match-group-regexp [ skip-first-match ] [ first-match ] bi* ;
+
+: update-match-group ( str match regexp n -- str' )
+ [ nth-match ] [ CHAR: 1 + "$%c" sprintf ] bi swap replace ;
+
+: update-match-groups ( str match regexp -- str' )
+ [ >string ] dip
+ dup #match-groups [ update-match-group ] 2with each-integer ;
+
+GENERIC: fixup-end ( match regexp end -- end' )
+
+M: string-matcher fixup-end
+ [ string>> -rot update-match-groups ]
+ [ ignore-case?>> ] bi <string-matcher> ;
+
+MEMO: <fixup-regexp> ( raw matched options -- regexp )
+ <optioned-regexp> {
+ [ parse-tree>> ] [ options>> ] [ dfa>> ] [ next-match>> ]
+ } cleave regexp boa ;