String#gsub で選択子 | を使う時に注意したいこと
#sub
#gsub
する際に正規表現の選択子 (|
) を使うことができるが、このチェックは正規表現ベースではなく、文字列ベースで 1 文字ずつイテレートしながら行われる*1。
ので、意識せず |
を使っていると思わぬところでハマりそう。
# "abc" を /a/ /ab/ /bc/ のパターンを使ってマッチさせたい場合 # /ab/ がなければ話は簡単 "abc".gsub(/bc|a/, "") => "" # パターンとしては /bc/ が先にあるが、 # 文字列をベースにチェックしていくので"a" と/ab/ が先にマッチする "abc".gsub(/bc|ab|a/, "") # => "c" # 先にマッチさせたいパターンを単独で先にマッチさせると期待通りの挙動となる "abc".gsub(/bc/, "").gsub(/ab|a/, "") # => ""
- Ruby の正規表現エンジンに限った話ではなく、 正規表現チェッカー(JavaScript版) でチェックした時も同じ挙動だったのでおそらく一般的な挙動
正規表現制御型(regexp-directed)エンジン
の挙動らしい- はじめての正規表現とベストプラクティス#5(特別編)
|
と部分マッチのワナ|TechRacho テキスト制御型(text-directed)エンジン
だとこの辺りの挙動が変わるらしい
- はじめての正規表現とベストプラクティス#5(特別編)
- Ruby の正規表現ライブラリは Onigumo
先読み & 後読みでなんとか書けそうな気はするけど、その辺はまだよくわからない…
*1:動作的にそうだったけどコードベースで確認したわけではないです