Regexp#match(str, index)
文字列の後に最初の一致が得index
られます。これは、各一致を左から右に反復するのに最適です。しかし、特定のインデックスの前の最後の一致を見つけるにはどうすればよいでしょうか? 最後の一致のインデックスを提供しますが、完全な一致データが必要な場合はどうすればよいですか?String#rindex
例:
/.oo/.rmatch("foo boo zoo")
...譲るべき...
#<MatchData "zoo">
Regexp#match(str, index)
文字列の後に最初の一致が得index
られます。これは、各一致を左から右に反復するのに最適です。しかし、特定のインデックスの前の最後の一致を見つけるにはどうすればよいでしょうか? 最後の一致のインデックスを提供しますが、完全な一致データが必要な場合はどうすればよいですか?String#rindex
例:
/.oo/.rmatch("foo boo zoo")
...譲るべき...
#<MatchData "zoo">
文字列をサブストリング化することで、正規表現が文字列のどこまで一致するかを制限できます。
irb> /.oo/.match("foo boo zoo"[0..-3])
=> #<MatchData "foo">
irb> /.oo/.match("foo boo zoo"[0..-3],3)
=> #<MatchData "boo">
irb> /.oo/.match("foo boo zoo"[3..-3]) # can also express the start with slice
=> #<MatchData "boo">
irb> /.oo/.match("foo boo zoo"[0..-3],5)
=> nil
String#scan
すべての一致の配列を返す正規表現を繰り返し適用し、そこから最後のものを選択します。
module RegexpHelper
def rmatch str, rlimit = -1
str[0..rlimit].scan(self).last
end
end
Regexp.send :include, RegexpHelper
/.oo/.rmatch 'foo boo moo' # => "moo"
/.oo/.rmatch 'foo boo moo', -3 # => "boo"
/.oo/.rmatch 'foo boo moo', 4 # => "foo"
これがmonkeypatchソリューションです:
class Regexp
def rmatch str, offset = str.length
last_match = match str
while last_match && last_match.offset(0).last < offset
break unless m = match(str, last_match.offset(0).last)
last_match = m
end
last_match
end
end
p /.oo/.rmatch("foo boo zoo")
#<MatchData "zoo">
文字列を逆にし、正規表現を逆にしlength(str) - index
て、開始点に使用できます。
1.9.3p194 :010 > /oo./.match("foo boo zoo".reverse)[0].reverse
=> "zoo"
正規表現が表す言語が本当に規則的であれば、正規表現を逆にするのは簡単です。貪欲またはその欠如は、考え抜かなければならないエッジケースにつながる可能性があります。
正規表現に Kleene スターが付いている場合、大きなプロジェクトである独自の逆正規表現マッチャーを構築しない限り、これが仕事を成し遂げる唯一の方法だと思います。