💦

正規表現の最短マッチ(.*?)を知らなくて今更躓いた話

2021/07/04に公開

今まで個人や業務でも正規表現を扱うことはありましたが、
最短マッチの存在に気づくまで地味に時間がかかってしまいました。

今まで雰囲気で正規表現を扱ってきたバチが当たったんだと反省しております。

事件は数日前・・・

色々な諸事情により、下記のようなMarkdownを正規表現でHTMLに書き換える必要が出てきたのです。
さて、こいつをJavaScriptで置換しようか・・・となりました。

input.md
![](/hogehoge/img/sunny.png)のち![](/hogehoge/img/cloudy.png)
output.html
<img src="/hogehoge/img/sunny.png">のち<img src="/hogehoge/img/cloudy.png">

image01.png

サクッと正規表現を作成

初め、「サクッと出来そう」と思いつつ、下記のような正規表現を作成しました。

正規表現
/\!\[(.*)\]\((.+)\)/g
RegExp.js
"![sunny](/hogehoge/img/sunny.png)のち![cloudy](/hogehoge/img/cloudy.png)".replace(/\!\[(.*)\]\((.+)\)/g, '<img src="$2">')

正規表現の可視化

エスケープが多く大変見づらかった為、正規表現の可視化を行いました。
凄い見やすいです。
そして、ぱっと見て特に問題なさそうだと思い、実行してみました。

https://regexper.com/#%2F\!\[(.*)\]\((.%2B)\)%2Fg

image02.png

実行してみたところ・・・

console
"![sunny](/hogehoge/img/sunny.png)のち![cloudy](/hogehoge/img/cloudy.png)".replace(/\!\[(.*)\]\((.+)\)/g, '<img src="$2">')"<img src="/hogehoge/img/cloudy.png">"

ぬっ。
晴れ画像がどっか行った?
何故ゆえ。

色々調査

ここの調査の時間、何も記憶に残ってないのですが、
ふと気が付くと何故か、サクラエディタの利用可能な正規表現を眺めていました。
そこで目に入ったのが、 最小一致(無欲)最大一致(欲張り) の記述でした。

なるほど、完全に理解した(分かってない)

標準の+*を使用する場合、文字列の末尾の)がマッチした後、
!までの条件を満たす場所まで戻る、という挙動をするらしい・・・。

これが 欲張り量指定子(最長マッチ) で、
反対が 非欲張り量指定子(最短マッチ) だと。

なるほど、そう言う事ならと、下記のように正規表現を直してみました。
?を付けただけですが。

正規表現(改)
/\!\[(.*?)\]\((.+?)\)/g

その他

詳説正規表現 のオライリー本でも読めれば良いんだが、
オライリー本の値段と厚さに圧倒されているので中々でを出せないんですよね。
図書館に有ったりしないかな。

あと、?の有無で可視化してみましたが、完全に間違い探しレベルでした。

image02.png

image03.png

Discussion