DTPab

印刷やデザイン、アドビ製アプリやスクリプトなど、雑多な技術ブログ

本文中に2回目に登場する語句を正規表現で探す

概要

なんのこっちゃという感じですよね。
たとえばこんな文章があったとします。

f:id:uske_S:20200130200101p:plain

分かりやすいように六波羅探題という語句をマゼンタにしました。仮に「初出のものにルビを振りたい」といわれたとき、どのように探すと効率的でしょうか。
単純に頭から「六波羅探題」を検索していってもいいのですが、正規表現で探す方法があるのでご紹介します。

正規表現

いきなり答えを書いてしまいますが、こんな正規表現で検索できます。

(?s)(六波羅探題).+?\1 f:id:uske_S:20200130200337p:plain

検索結果はご覧の通り。 f:id:uske_S:20200130200353p:plain

選択範囲の頭が初出、末尾が2回目になっています。

この正規表現のポイントは2つです。それぞれ説明しましょう。

シングルラインモード

(?s)
何をする正規表現でしょう。実はこれ自体は何も検索していません。先頭につけることで検索モードを変えています
シングルラインモード*1といって、検索対象のテキストを1行(シングルライン)と見なして検索を行います。

有り体にいえば、任意の文字を示す.改行文字を含むようになります*2。つまり、先の正規表現の.+?部分が、改行文字を含む任意の文字という意味になり、段落をまたいでストーリー全体を参照することになります。

グループ参照

\1
検索条件に指定すると、検索条件の中でグルーピングしたグループを順に参照します。置換でいうところの$1みたいな使い方です。置換におけるグループ参照と同じく9つまで参照できます。

abcabeabababcdefg

というテキストに対して、正規表現([abc]{3}).+?\1で検索した結果はどうなるでしょうか。

abcabeaba

だと思いました? 不正解です。
正解は

abcabeabababc

ですね。

グループ参照は、グルーピングしてヒットした文字列そのものを参照します。したがって、このケースの正規表現では文字列の先頭から参照して、([abc]{3})が「abc」にヒットします。\1はそれを参照するので、このケースでは([abc]{3}).+?\1abc.+?abcという検索になるわけです。
([abc]{3}).+?[abc]{3}となるわけではないことに注意してください。

さいごに

同僚に正規表現を見せたらグループ参照を知らなかったので、今回のネタにしました。
こんな話をいくつか逆引きTipsとして書いたのが下記で頒布されている同人誌「Adobe CC アンソロジー vol.3」です。

466548.booth.pm

ご興味ある方、ぜひご購入ください〜

*1:single line modeの頭文字を取って「s」。マルチラインモードの場合は「m」。InDesignは明示的に指定しない限りマルチラインモードによる検索です

*2:当然ながら、正規表現スタイルは段落ごとに設定されるものなので、段落スタイルの正規表現スタイルに登録しても無意味です