8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

正規表現 `$^` は何にマッチするか(アンカーの正しい理解に向けた確認)

Posted at

エディターなどにおいて空行にマッチさせるとき、正規表現で ^$ というのを使う。この正規表現の意味は雑に言えば「行頭があり1文字も無く行末がくる」というものである。 ^$ は正規表現のアンカーという機能で、文字列中でとある特徴を持つ位置にマッチする。

では、このアンカーを逆順に書いた正規表現 $^ は何にマッチするか?

答え

一般的な正規表現エンジンなら、これも空行にマッチする。つまり ^$ と全く同じである。

grep(拡張正規表現)
echo '' | grep -E '^$' && echo "matched."
echo '' | grep -E '$^' && echo "matched."

「一般的な」と書いたのは、そうでないものも存在するから。例えばアンカーの効力を失って普通の文字にマッチすることがある。このような動作は本記事の対象外とする。

grep(基本正規表現)
echo '' | grep '^$' && echo "matched."
echo '!$^"%(#&)' | grep -o '$^' #=> $^

ありがちな間違い

「何にもマッチしない」と思わなかっただろうか。

その場合は恐らく次のように考えたと思う。「行末の後に行頭がくる行、なんて条件が破綻している。」

もし行頭でなく適当な文字( $a など)だったら、その考え方はだいたい正しい。行末の後ろにあるのは改行文字(か文字列終端)なので、普通の文字がくることはあり得ない。

この考え方の何が問題かというと、アンカーに対して「○○の後に」とヘタに順序を意識してしまったことである。アンカーは文字列の位置にマッチするのであり1文字も読み進めない1ため、同じ位置から何事もなかったかのように次の正規表現パターンを検査する。一方で a のように文字列を読み進める正規表現に対しては順序を意識する必要がある。

あるいは、そもそも文字列の位置という考え方に慣れていないのかもしれない。エディターでカーソルが縦棒だとわかりやすいが、文字と文字の間が位置である。部分文字列(エディターでいう範囲選択)として見る場合、その長さは0。

それを踏まえて $^ を正しく解釈すれば次のようになる。「行末であり行頭である位置が存在する行、それは空行だけである。」

まとめ

アンカーは文字列の位置にマッチする。その言葉の裏には「マッチしても文字列を読み進めない」という意味があり、同じ文字列位置から次の正規表現パターンを検査することになる。そのため連続するアンカー同士の順序を入れ替えても意味は変わらない。アンカーだけでなく、先読みや後読みと呼ばれる機能も同じである2

なお、同じ意味になるからといって $^ と書くのは混乱の元なのですべきでない。可読性を考えて書くべきである。

  1. そのためアンカーなどを「ゼロ幅アサーション」と呼ぶことがある

  2. さすがに先読みの中でキャプチャー・後方参照を利用していたりしたら、順序は重要だと思う

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?