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

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

今までふわっとした知識で正規表現を扱ってきたバチが当たったんだと反省しております:sweat_drops:

事件は数日前・・・

色々な諸事情により、下記のような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%5C!%5C%5B%28.*%29%5C%5D%5C%28%28.%2B%29%5C%29%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">"

私「ぬっ:thinking:
何故か、後ろの曇り画像のみがマッチして、置換されたようです。
な〜ぜ〜。

=== 2018/03/21追記 ===
@swordone様よりご指摘ありました。
後ろの曇り画像のみがマッチして、置換されたの部分は私の認識違いでした。
詳細は下記コメント欄の@swordone様のコメント内容を参照のこと。

色々調査

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

なるほど、理解した(怪しい

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

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

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

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

その他

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

あと、?の有無で可視化してみましたが、分かるようで分からなかったです。

image02.png

image03.png

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.