正規表現では文字の繰り返しを指定することができます。文字の繰り返しと言っても普通の文字というより、前回説明した任意の文字を表す「.」やある範囲の文字の集合を表す文字クラスなどの繰り返しなどがよく使われます。
たとえば住所録で文頭に「住所:」がありその後に任意の文字が繰り返される部分はたぶん住所を表す文字列でしょうし、「Tel:」の後に続く数字とハイフンや丸括弧の繰り返し部分は電話番号でしょう。
正規表現で繰り返しを表すルールは4つです。*5
直前の文字が1回登場するか、もしくは登場しないことを表します。
正規表現 「情報化?社会」
は直前の文字「化」があったりなかったりするわけですから
情報化社会
情報社会
の両方にヒットします。
直前の文字が1回以上繰り返して登場することを表します。例としては前回の解説でとりあげた
正規表現 「国連.+会議」
をみてください。この場合の直前の文字は「.]、つまりどんな文字でもOKですね。
1回以上の繰り返しですから「国連会議」にはマッチしないことに注意してください。
「0回以上」という聞き慣れない表現が登場します。「0回登場する」とは「登場しない」ことです。言い換えれば「直前の文字が登場しないか、もしくは1回以上登場する」という意味になります。
たとえば名簿などで姓と名の間に空白を入れてあったりなかったりする場合、検索はたいへん困難です。ちょっと考えただけで下のようなバリエーションがあります。(□は全角の空白、_は半角の空白を表します)
1. 小泉□純一郎
2. 小泉純一郎
3. 小泉_純一郎
4. 小泉__純一郎
まず半角空白が使われているか全角空白が使われているかは分かりませんから、前回説明した文字クラスを使って
[_□]
とどちらの空白にもヒットするようにします。
空白があるかないかと考えて「?」を使って
小泉[_□]?純一郎
とすると、1.〜3.にはヒットしますが、半角の空白がふたつ入っている4.のケースにはヒットしません。といって2.のように空白がないこともありますから「+」も使えません。そこで「*」の登場です。
小泉[_□]*純一郎
このケースの繰り返される文字「[_□]」はよく使われる文字クラスです。
繰り返しを表す正規表現はなかなか奥が深いものです。少し例をあげましょう。
次のような表現は同じ意味になります。正規表現では同じ意味を違う形で表現できます。こういったケースではなるべく簡潔な表現になるようにしましょう。
aa* = a+ a?a* = a*
英語では空白は単なるセパレート記号ですから数は1個でも2個でも同じ意味になりますから注意が必要です。記号の前後には空白が入ることもあるでしょう。こんなことを考えると簡単な英文でも厳密には以下のような指定になります(実務的には半角空白がふたつ連続した部分を検索して修正してしまったほうが遥かに楽です)。HTMLやXMLのタグの中の空白の扱いも同様です。
this_+is_+a_+pen *.
<a_+href_*=_*".+"_*>.+<_*/_*a_*>
コロン、セミコロンやカンマなどもあとに空白を伴うことが多いはずです。コロンの後に登場する語句を検索したい場合などは必ず空白の存在を予測しておきましょう。日本語の文書の場合は全角のコロンと半角のコロンが混じっていることも多いので注意が必要です。コロンの後に続く「abc」を検索するなら
[::][_□]*abc
と念入りに指定をします。
「?*+]を組み合わせると出現回数を指定できます*6。
aが3回以上登場する aaa+ Xの間にaが2〜5回登場する Xaaa?a?a?X Xの間にaが4個以内登場する Xa?a?a?a?X
トレーニングのために最初に出した年月日の例を厳密に指定してみましょう。前回は簡単に以下のような正規表現を書きました。
[0-9]+年[0-9]+月[0-9]+日
この表現だと「10000000年100月1000日」などというあり得ない年月日にもマッチしますね。これを少しましな指定にしようというわけです。
まず月と日の数字を考えます。月も日も1桁の場合もあれば2桁の場合もあります。0桁はありえず、3桁以上になることもありませんね。これを考えて月日の表現は
年[0-9]?[0-9]月[0-9]?[0-9]日
とします。これで数字を1から2桁に限定することができました。
さて月は1〜12、日は1〜31ですから、2桁目と1桁目に登場する数字は異なります。そこで
年1?[0-9]月[1-3]?[0-9]日
とすれば月は0〜19、日は0〜39の間に限定されます。
ついでに年の後ろと月の後ろには空白が入ることが予想されますのでそれに対処しましょう。
年[_1]?[0-9]月[_1-3]?[0-9]日
年についてはコンテンツにもよりますが、1900年から2003年までを前提にすると
[1-2][90][0-9][0-9]年
で、1000〜2999年までの範囲に限定できます*7。
実際にはここまで厳密に指定する必要はないと思いますがちょっとした頭の体操です。
最後のルール「最長一致の原則」は繰り返しルールの落とし穴です。正規表現では繰り返しはできる限り長く一致するように動作します。これが「最長一致の原則」の原則です。
次のような文章からかっこ内の文字列を検索する場合を考えてみましょう。
正規表現(せいきひょうげん)を使いこなせると文章(ぶんしょう)の加工(かこう)が楽(らく)だ。
かっこ内の任意の文字だからと簡単に次のような正規表現を使うと
(.+)
ヒットする部分は下の赤い部分になります。
正規表現(せいきひょうげん)を使いこなせると文章(ぶんしょう)の加工(かこう)が楽(らく)だ。
一瞬間違っているように感じますが、なるほど「(」と「)」の間に任意の文字が繰り返されています。任意の文字「.」は「)」も含みますから「.+」の部分が最長になるようマッチすると上のようになってしまうわけです。
この検索を利用して置換などをしたらとんでもないことになりますね。かっこ内を削除するつもりで空文字と置換すれば結果は何と
正規表現だ。
となってしまいます。恐ろしいことですね。機械処理にはこんな怖い面もあるので注意が必要です。これを避けるには次のような表現を使うとよいでしょう。
このケースなら括弧内がかなだけの場合に限定することでよい結果が得られます。
([ぁ-んァ-ヴー]+)
より一般的には次のような類型表現が使われます。
([^)]+)
これは開きかっこの後に閉じかっこではない文字([^)])が1文字以上繰り返し、閉じかっこが来るという意味ですね。これでかっこ一組に検索結果を絞れるわけです*8。この類型はよく使われますのでよく理解しておくとよいでしょう。
aが3回以上登場する a{3,} Xの間にaが2〜5回登場する Xa{2,5}X Xの間にaが4個以内登場する Xa{0,4}X
(.+?)