There's an echo in my head

日々のメモ。

Rubyの正規表現で対応する括弧を考慮していい具合にマッチさせる

1.9以降に搭載された正規表現エンジン(oniguruma, onigumo)では

  • (?<name>式)によってマッチした部分に名前(ここではname)を付けることができ、
  • それにマッチした内容を後方参照\k<name>で参照でき、
  • また\g<name>でその式を再帰的に呼び出すことができる

これを使えば、括弧のペアを対応させた上でマッチさせることができる。

たとえば次の例ではLispのシングルクォーテーション記法をquote関数の呼び出しに変換する。

regexp  = /'(?<paren>\((?:[^()]|\g<paren>)*\))/
replace = '(quote \k<paren>)'

# 1段
"'(+ 1 2)".match(regexp)               #=> #<MatchData "'(+ 1 2)" paren:"(+ 1 2)">
"'(+ 1 2)".gsub(regexp, replace)       #=> "(quote (+ 1 2))"

# 2段
"'(+ 1 (+ 2 3))".match(regexp)         #=> #<MatchData "'(+ 1 (+ 2 3))" paren:"(+ 1 (+ 2 3))">
"'(+ 1 (+ 2 3))".gsub(regexp, replace) #=> "(quote (+ 1 (+ 2 3)))"

# 並んでてもOK
"'(+ (+ 0 1) (+ 2 3))".match(regexp)   #=> #<MatchData "'(+ (+ 0 1) (+ 2 3))" paren:"(+ (+ 0 1) (+ 2 3))">

# 括弧の対応がとれていない場合にはマッチしない
"'(+ 1 2))".match(regexp)              #=> nil

参考

このブログに出てくるコードスニペッツは、引用あるいは断りがない限りMITライセンスです。