この記事は、不動産情報サイト LIFULL HOME'S などを運営する株式会社LIFULL の LIFULL Advent Calendar 2022 の記事です。
まだまだ入社1年目、株式会社LIFULLの暴れ回る新卒、 @pal4de です。
正規表現が大好きです。
これは、その中でもとくにお気に入りな正規表現「単語境界 \b
」の検索における威力を説き、褒め称える記事です。
「正規表現、まァ基本は一通り勉強したな...」 というあなたにオススメしたい、ステップアップにピッタリなヤツです。
これは何?
改めて、 正規表現パターン \b
は「単語境界」を表す記法です1。
Word BoundaryのBですね。
ここでは、「単語」は単語構成文字 \w
= [A-Za-z0-9_]
の連続と定義します2。
挙動の例
実際の挙動を見てみるとこんな感じ3。
正規表現 | 検索対象文字列 | マッチする位置 |
---|---|---|
\b |
let count; | |let| |count|; |
\b |
snake_case | |snake_case| |
\b |
kebab-case | |kebab|-|case| |
\b |
1: IMAGE001 | |1|: |IMAGE001| |
\bimage\b |
var image, imageSize, yourImage; | var image, imageSize, yourImage; |
アンダースコア_
の扱いがやや意外ですが4、おおよそ直感的ではないでしょうか。ご覧の通り「単語の両端にマッチする」雰囲気が感じ取れます。
文頭^
や文末$
などと同様、\b
は文字そのものではなく文字の隣にマッチする表現です5。
特に嬉しさを表現しているのが一番最後のimage
の例。
パターン \bimage\b
はimage
の両サイドに単語境界\b
が引かれている表現となっています。
つまり、日本語に意訳するなら「ちょうどピッタリimage
にマッチする」ぐらいの意味になります。
何がうれしい?
先ほど挙げた例で、grepやVSCodeのファイル横断検索を使用したことがあるなら嬉しさがわかってくるのではないでしょうか。
そう、Language Serverなどによるリッチな言語サポートがなくとも、\b
の 2文字×2=4文字 で変数名や関数名などのトークンの厳密な一致による検索が行えるようになるわけです。
この単語境界\b
は、新しい6GitHub Code Searchでも使用可能というのですから喜びはひとしおです。
もう少し具体的な例として /\buser\b/i
をした例を示します。
下記のようにプレフィックスやサフィックスに惑わされない検索が行えるようになり、検索結果ノイズもグッと減ります。
マッチする | マッチしない |
---|---|
$|user| = | $user_type = |
class |User|() | class UserOrganization() |
"./|user|.php" | "./special_user.php" |
そして次回予告へ
さらに、「変数はいらないなあ...」とか「CSSのクラス名だから-
の場合は区切りとみなしたくないなあ...」みたいな場合には検索クエリに肯定先読み、否定先読み、肯定後読み、否定後読みを組み合わせて検索結果をさらに絞り込んでいくことになります。
みんなが苦手なヤツです。羅列の仕方もイヤな感じを演出しています。
「(肯定|否定)[先後]読み
編」もぜひご覧ください👇
まとめ
-
\b
は文字ではなく、単語境界を表します。 - 単語とは
[A-Za-z0-9_]+
で表されるものです。 - 正規表現を使った検索時、
\b
で両端を挟んでやることにより、プレフィックス等が紛れ込まなくなり、regex searchが捗ります。
弊社アドベントカレンダーの他の記事もお楽しみください👇
オマケ
等価な表現
\b
は(?<=\W|^)(?=\w)|(?<=\w)(?=\W|$)
と等価です。恐らく。
日本語に書き下すなら次のような感じです。
断片 | 日本語訳 |
---|---|
(?<=\W|^) |
マッチ開始位置より左隣が「非単語構成文字または文字列先頭」 |
(?=\w) |
この位置より右隣が単語構成文字 |
| |
または |
(?<=\w) |
この位置より左隣が単語構成文字 |
(?=\W|$) |
この位置より右隣が「非単語構成文字または文字列終端」 |
逆の表現 \B
ちなみに、\B
で逆の意味、つまり「単語の境界以外」になります。
使ったことはありません。
大文字で逆の意味になるのは正規表現あるあるですね。大変大変覚えやすい。
ここまで読んでくれてありがとう 😘