講座『正規表現』

                第一回 はじめに
                第二回 メタキャラクタ 「.」(ピリオド)
                第三回 メタキャラクタ 「*」
                第四回 メタキャラクタ 「[ ]」
                第五回 メタキャラクタ 「^」と「$」
                第六回 メタキャラクタ 「\」
                第七回 メタキャラクタ 「\」(続)
                第八回 強力な置換 「 \( \) 」 \1 \2...
                第九回 繰返しの回数 「 \{n,m\} 」と簡易AND検索
                第十回 拡張メタキャラクタ「+」「?」「|」
                第十一回 拡張メタキャラクタ 「 ( ) 」
                第十二回 まとめ 


第一回 はじめに

電子的なテキストは、紙の上に印刷されたテキストと比較して、さまざまな利点をもっています。その一つは語句や文字の検索が簡単であるということでしょう。多くのエディタやワープロは簡単なものでも検索機能を備えているのが普通です。この検索機能を使えば、紙に印刷すれば何十頁、何百頁にもなる大量の文書のなかから、ある特定の語句を瞬時に探しだすことが可能になります。また置換機能があれば、特定の語句を別の語句に一括して変更することも簡単に行えます。

その上に、もしそのエディタやソフトが<正規表現>をサポートしていれば、この検索機能や置換機能はさらに大幅に拡張・強化されます。

簡単な例をあげましょう。たとえば、歴史的かなづかいと現代的かなづかいの混在するテキストがあって、そこで「思えば」という文字列を検索したいとします。そしてこのテキストでは、「思えば」と「思へば」の二つの書き方が見られるとします。こういう場合、普通の検索では「思えば」と「思へば」で別々に二回検索しなければなりません。

しかし、<正規表現>を用いて、/思[えへ]ば/で検索すれば、一回でどちらの表現も発見してくれます。<正規表現>では、複数の文字を [ ] で括ると、これは [ ] の中の文字の内の「任意の1文字」をあらわします。だから「思えば」「思へば」のどちらも一度に検索してくれるわけです。

ここで、大事な注意を一つ述べておきます。これから、特に<正規表現>であるということを示したいときには、<正規表現>の前後をスラッシュ「/」 で囲む場合があります。しかしスラッシュ自体は正規表現に含まれないことを覚えておいてください。従って上の例で言えば実際に検索する文字列として指定するのは「 思[えへ]ば 」です。

もうひとつ例をあげましょう。送り仮名のつけかたが統一されていないようなテキストでも、検索において同様の問題にぶつかります。「唱へる」「唱る」の二つの用法が見られるとき、この語を検索する際に<正規表現>が力を発揮します。「唱へ*る」で検索すれば、どちらもヒットします。「*」は直前の文字が0回以上出現するという意味で、上記のどちらにもマッチする訳です。

自分の使っているエディタやソフトの検索機能が<正規表現>をサポートしていれば、この文章をそのエディタの画面で表示して、<正規表現>の使用をONにして、「思[えへ]ば」や「唱へ*る」で検索してみれば実際にその便利さを実感できます(注1)

これらの例で、<正規表現>の便利さが、少しはわかっていただけるでしょう。<正規表現>とは、結局、文字列のもつ条件を、柔軟かつ精密に規定するための方法だといっても良いでしょう。
だから<正規表現>とは、「文字列を指定したり、照合したりするのに用いられる記法」(『プログラミング言語AWK』エイホ他著、トッパン)とか「文字の特定のシーケンスを記述するもの」(『sed & awkプログラミング』ドウーラティ著、ASCII)などといわれます。

次回から、上で見たような、「[ ]」や「*」の独特な使い方を含む<正規表現>の使用法を学んで、電子的テキストをより有効に活用できるようになりたいと思います。


(注1)<正規表現>の扱えるツールとしては、高機能なエディタ、即ちMacでは「Edit7」や「Jedit」「YooEdit」、Winでは「WZ」「秀丸」などがあります。さしあたってはこれらのような<正規表現>をサポートしたエディタを一つ用意して実際に使用しながら学んでいくのがわかりやすいと思います。
これらで<正規表現>を使用するときは検索設定の画面などで「正規表現」の使用をONにしますが、「正規表現」ではなく「grep」と表示されているものもあります(MacのEdit7など)。また<正規表現>を駆使する本格的なテキスト処理ツールとしては、sed、awk、perl、などがあります。これらはUnix由来のものですが、Mac版やDos版、Win版もあります。


第二回 メタキャラクタ ピリオド「.

正規表現では、語句や文字列の条件を精密に記述するために、いくつかの記号を特殊な意味で使います。第一回目に挙げた [ ] や 「*」 などがそうです。これらの記号を正規表現では、<メタキャラクタ>(メタ文字、超文字)と呼びます。つまり、通常の文字(列)を、ひとつ上の次元から精密に記述し操作するための文字、とでもいうんでしょうね。しかしどちらも同じ文字だから最初は少しややこしいです。

.」即ちピリオドも<メタキャラクタ>のひとつで、正規表現では、改行以外の全ての文字を表すために使います。「法」の後にピリオドをひとつ打って、「法.」で検索すれば、「法律」「法門」「法人」「法は」etc などにヒットします。正規表現を使いこなすためには、こういう<メタキャラクタ>に慣れる必要があります。<メタキャラクタ>を含んだ文字列がどういうものを意味するのかを知り、また自分でも検索のときに使えるようになれば、正規表現がだいたい理解できたことになります。

今回から数回に分けて、これらの<メタキャラクタ>について説明します。<メタキャラクタ>は10個程度あります。程度というのはツールによって若干の異同があるからです。まずどのツールでも用いられる基本的なものから順に説明していきます。(注2)

  ●メタキャラクタ ピリオド「.

ピリオド「.」は代表的なメタキャラクタです。上でも述べましたように、メタキャラクタとしてのピリオドは、「改行以外の全ての文字」にマッチします。いわゆるワイルドカード・メタキャラクタです。トランプで言えばなんにでもなるジョーカーみたいなものです。そして、「改行以外の全ての文字」にマッチするということですから、これを単独で検索に使うことはありません。ピリオドをつかうときは、その前後に肝心な検索パターンがあります。

一例をあげましょう。「法華経」と「法花経」「法句経」などを一度に検索したいときはどうしたらよいでしょうか。この三つに共通するのは前後に「法」と「経」があって真ん中だけが異なった文字になっています。簡単に検索するには、「法」と「経」の字の間にピリオドを挟んで以下のようにします。

    検索文字列  法.経 

この正規表現は、前に「法」、真ん中に任意の一文字、後ろに「経」の字が来る文字列にマッチします。もちろん、この検索のパターンでは上の三つの語句だけでなく、「法と経」「法や経」などという文字列も該当するものとして、検索に引っかかってくるでしょう。

厳密に上の三つだけにマッチさせたいときは「法[華花句]経」のように [ ] を使用しますが、この方法は後に詳しく見ることにして、とりあえずは「法.経」で、目的の三つの語句を必ず拾い出してくれます。この文全体を正規表現の使えるエディタあるいはワープロに移して、実際に上の検索を行って、確認してください。


(注2)前回紹介した『sed&awkプログラミング』の66頁に、Unix の grep や sed というツールで使われている最も基本的なメタキャラクタとして、ピリオド「.」、アスタリスク「*」、ブラッケット「[ ]」、サーカムフレックス「^」、ドル記号「$」、バックスラッシュ「\」(日本語フォントでは円の記号に見えますが、欧文フォントではスラッシュ / を逆に傾けたものです)などがあげられています。これらがメタキャラクタの基本的なセットですが、ツールによってはさらに拡張されます。拡張されたものについても後に解説します。


第3回 メタキャラクタ 「*

二つ目のメタキャラクタを紹介しましょう。

 ● メタキャラクタ 「*

アスタリスク「*」は何かの文字を表すわけではなく、直前の文字の0回以上の繰返しをあらわします。したがって、これはいつも別の文字の後で使用されます。使い方の例をあげましょう。たとえば、二乗成仏、二乗不成仏、という二つの語句を同時に検索したいときには、以下のようにします。

    検索文字列  二乗不*成仏

こうすると、「*」は直前の「不」という文字の0回以上の繰返しを指定していますから、この正規表現は「不」の字がないものにも、あるものにもマッチします。

しかし待てよ、と注意深い人は思うかも知れません。0回以上の繰返しということは、「不」が二回以上続く場合にもあてはまるんじゃないのかと。その通りです。実際、「二乗不*成仏」という正規表現は

    二乗成仏、二乗不成仏、二乗不不成仏、…

などにマッチします。もし厳密に前の二つだけにマッチさせたいというときは「*」の代わりに「?」を使いますが、これについては、もう少し先で学びましょう。

もう一つ「*」の使用例をあげましょう。もしある文章の中で引用符「」で囲まれた部分を見つけたいときはどうすればよいでしょうか?正解はピリオドの後にアスタリスクを加えて

    検索文字列  「.*」

とします。ピリオドは前回述べたように任意の文字にあてはまりますから、それに「*」をつけて全体を「」で括った正規表現 /「.*」/は、引用符に囲まれた任意の文字の、任意の個数のつらなりにマッチするというわけです。要するにここで検索したい文字列の条件は「」に囲まれているということだけで、その中は何でも良いというわけですから、このように指定します。そうするとこれは「私は学校へ行きました」という表現にも、「法華経」という表現にもマッチします。

さて、ここで大事なことを一つ注意しておきましょう。正規表現の該当する範囲についてです。検索したときに該当する可能性が複数あるときは、もっとも長い文字列の範囲にマッチします。この文章自体で、実際に/「.*」/という正規表現を用いて検索してみてください。このことがすぐわかるでしょう。念のために下の文を例にして説明しておきます。

    例文      私は「法華経」と「摩訶止観」を学んだ。

例文では、/「.*」/という正規表現に一致する可能性はいくつあるでしょうか?「法華経」、「摩訶止観」はすぐわかりますが、実はもうひとつあるんですね、全部で次の三つです。

    1)「法華経」
    2)「摩訶止観」
    3)「法華経」と「摩訶止観」

3)の場合も実は「 で始まって 」で終わるという条件を満たしています( 内側のカギカッコ自体も文字ですから)。こういうとき、この正規表現にマッチするものとしては、最も長い範囲が選ばれるということです。すなわち、3)が選ばれます。この文を、正規表現が使えるエディタ等に移して、/「.*」/ で検索して、ここで述べていることを確認してください。

しかし、「」で囲まれた部分を探したいとき、3)が選ばれるというのは少し困ります。1)と2)だけを選びたいときには「」のなかにくる文字を限定する必要があります。そういうときによくつかわれるのが、メタキャラクタ [ ] です。これについては次回に説明します。


第四回 メタキャラクタ [ ]

 ● メタキャラクタ [ ]

「法華経」「法花経」「法句経」の三つを検索したいとき、ピリオドを用いて / 法.経 /(//は含まない)とすれば、とりあえずはこの三つを検索してくれると、第2回目にお話ししました。しかし、これでは「法と経」のような真ん中にひらがななどが来る場合も検索にひっかかってきます。そこでもっと検索文字を限定したいときにこのブラッケット(角カッコ)[ ] を使用します。

  (1) [ ] を使って文字を列挙する

[ ] の中に検索したい文字を並べれば、そのうちのいずれかの文字がある箇所を検索してくれます。このような働きをもつので [ ] は「文字クラスを指定する」働きがあるなどと言われます。そこで上の三つの単語の検索は [ ] の中に華、花、句の三文字をいれて

    検索文字列   法[華花句]経

とすればいいわけです。実際にこの正規表現をつかって、この文章を検索して威力を確かめてください。

  (2) [ ] を使って範囲を指定する

[ ] の中は文字を列挙するだけでなく、文字の範囲を指定することができます。たとえばアルファベットの大文字だけを指定したいときは、ハイフン「-」を使って、

    検索文字列   [A-Z]

とします。こうすれば、A から Z までのアルファベット一文字が検索できます。さらに小文字も含めたければ

    検索文字列  [A-Za-z]

とします。また数字を全部というときは

    検索文字列   [0-9]

とします。列挙と範囲指定を組み合わせて、良く使う英数字全部を検索するには以下のようにします。

    検索文字列   [A-Za-z0-9?!.,*";:] (注3)

またひらがなやカタカナだけも検索できます。

    検索文字列   [あ-ん]
    検索文字列   [ア-ン]

とします。便利ですね。さらに漢字だけの検索も可能です。漢字の最初と終わりをつないでやれば良いんです。ひらがなの最初と終わりはだれでも知っていますが、漢字の最初と終わりなんてあるの?と思われるでしょうが、コンピュータにはあるんですね。

コンピュータの内部では、全ての文字に順番に番号を振り当てています(これを文字コードと言いコンピュータはこれを頼りに検索しています)。漢字の最初は「亜」で続いて「唖」「娃」と整然とならんでいて、最後に「龠」(「やく」と読みます)が来ます。この順番に文字コードが割り当てられているので、次のように指定してやれば、コンピュータは全ての漢字を検索してくれます。

    検索文字列   [亜-龠]

また漢字二文字がならんでいる場合はこれを重ねて

    検索文字列   [亜-龠][亜-龠]

とします。 [亜-龠] で一文字を表していることを忘れないようにしましょう。(注4)

  (3)「…以外の文字」の検索

[ ] を使えば、ある文字だけを除外した検索などもできます。そのためにはサーカムフレックス(脱字記号)すなわち「^」 を [ ] 内の一番最初に使うだけです。そして「^」の後に除外する文字を列挙するか、範囲指定してやります(注5)。たとえばひらがな以外のときは

    検索文字列   [^あ-ん]

です。漢字以外なら [^亜-龠] ですね。aとbとcを除外したければ [^abc] とします。

また前回「」で囲まれた箇所をみつけるとき、単に/「.*」/という正規表現では

    「法華経」と「摩訶止観」

も検索されてまずいと言いました。厳密に「法華経」や「摩訶止観」だけ見つけたいときは、「」の中の文字を指定するときに閉じカッコ 」 を除外してやります。つまり

    検索文字列   「[^」]*」

で検索すると良いわけです。

  (4)組み合わせてみよう。

これまで学んだ正規表現を組み合わせて使ってみましょう。たとえば漢字が二字以上連なった、漢字熟語を検索したいときはどうしましょうか?

    検索文字列   [亜-龠][亜-龠][亜-龠]*

とします。最初に漢字二字がきてその後に漢字が0個以上連なる文字列を探します。もし「[亜-龠][亜-龠]*」としますと、これは漢字が一字だけの場合もあてはまりますから、熟語になりません。少なくとも二個は漢字があることを指定するために最初に [亜-龠][亜-龠] を置き、そのあとは何もないか漢字が続く場合だけ検索するようにします。また「*」の効力は直前の [亜-龠] にしか及ばないことも忘れないようにしましょう。

  ●【練習問題】

・「…経」という漢字のお経の名前を全部検索したければどうしましょうか?

・東京の市内局番全てを表す正規表現はどうなるでしょうか?。


(注3) [ ] の中にピリオドやアスタリスクが入っていることに注意してください。[ ] の中では「.」や「*」などのメタキャラクタも、いわゆるリテラル(文字どおりの、通常の文字)とみなされます。少数の例外はこの「-」と後にみる「^」と「\」です。「-」は[ ] の中で、かつ文字と文字の間で使われるとき範囲を表します。しかし[ ] 内の最初や最後、また [ ] の外で使われたときはリテラルとして扱われます。

(注4)細かい注意が続きますが、ブラッケット「[」 や 「]」 自身を文字クラスの中に含めたいときは、開始ブラッケット 「[」 であれば、 [ ] 内の任意の場所に、終端のブラッケット 「]」 は [ ] 内の始めに置きます。 これらの位置に置いた場合は、どちらも文字クラスを表すブラッケットとはみなされず、文字クラスの内のリテラルとみなされます。たとえば、先ほどの英数字のなかに含めた場合は下のようになります。

検索文字列   []A-Za-z0-9?!.,*";[:]

一番外側の「[」と「]」が文字クラスをあらわすメタキャラクタと見なされます。内側の「]」と「 [」はリテラルとして扱われます。

(注5)^」は [ ] の中の先頭で使われたときは否定をあらわしますが、[ ] の中の他の場所で使われるとリテラル(普通の文字)として扱われます。また [ ] の外でかつ正規表現の一番はじめに使われた場合はメタキャラクタとして別の特殊な意味を持ちますが、これは次回以後で解説します。


第五回 メタキャラクタ「^」と「$

 ●メタキャラクタ「^」と「$

サーカムフレックス 「^」が、[ ] の中で使われるときの役割については前回お話しましたが、これにはもうひとつの役割があります。すなわち、正規表現の先頭で使われたときには、「^」は行頭をあらわします。またドル記号 「$」は正規表現の末尾で使われると、行末をあらわします。つまり「^」と「$」は位置を表すメタキャラクタです。

また、ここでいう<行>は、リターンキーを打って行われる改行によって区切られたテキストを指します。エディタ、ワープロなどのウィンドの右端で自動的に折り返しがおこなわれる、見せかけの改行ではありません。具体例は下のようになります。

    検索文字列  ^如是我聞

は行頭に来る「如是我聞」を探し、

    検索文字列  恐々謹言$

は行末の「恐々謹言」を検索します。しかし、下のようにこれらが単独で用いられたり

    検索文字列   ^
    検索文字列   $

また、下のように正規表現の先頭あるいは末尾以外の位置で用いられても、

    検索文字列   ab^c
    検索文字列   $500

リテラル(文字どおりの、普通の文字)として扱われ、これらの正規表現はそれぞれ、文字どおりの「^」「$」 「ab^c」 「$500」を検索します。

また 「^」と「$」を続けて書き

    検索文字列  ^$

で検索すれば、改行以外に文字のない、いわゆる「空行」を見つけることができます。

  ●【練習問題】

経の始まりは「如是我聞」です。では行頭にきているこの言葉を検索すれば経の始まりを知ることができますね。行頭をあらわすメタキャラクタは「^」ですから、これを使って

    検索文字列   ^如是我聞

で、検索すればうまく経の始まりをみつけられそうです。

しかしちょっと待ってください。もし日本語の習慣に従って、段落の初めの字下げが行なわれていて、スペース(空白)がはいっていると、行頭はスペースになり、これではヒットしません。どうすればよいでしょうか。しかも字下げが半角のスペースか全角のスペースによっても違ってきます。さらに見やすいように二字以上さげているかもしれません。字下げのないものも、半角の字下げも全角の字下げも、二字以上の字下げもすべてにマッチするような行頭の「如是我聞」を見つける正規表現はどうなるでしょうか?


【第四回の練習問題の解答】
・ 「[亜-龠][亜-龠]*経」です。経の名前は漢字が連なって最後に「経」が来ます。一字以上の漢字の後に「経」がくるようにします。

・ 市内局番と残りの番号が - で結ばれている場合だけを考えると、

    3[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]
ハイフンは [ ] のなかで文字と文字の間で使われると範囲を表しますが、それ以外のときはリテラル、文字どおりのものを指すことを思い出してください。
()で市内局番が囲まれている場合も考えると
    (*3[0-9][0-9][0-9][)-][0-9][0-9][0-9][0-9]
となります。


第六回 メタキャラクタ「\

 ● メタキャラクタ 「\

バックスラッシュ「\」(日本語のフォントで見るとこれは円の記号ですが、欧文フォントではスラッシュを逆に傾けた文字なのでこう呼ばれます)は少し変わったメタキャラクタです。「\」は他のメタキャラクタをリテラル(文字どおりの普通の文字)に変える特別のメタキャラクタです。

講座の第一回目で、「.」はメタキャラクタで、改行以外のあらゆる文字をあらわす、と述べました。あの時、じゃ、ピリオド自体を検索するときはどうするんだと疑問に思った人もいるでしょう。最近の日本語の本では、横組みでピリオドを使っているような場合があります。こういうテキストでピリオド「.」を「。」に変換したいというときなど、ピリオドを検索したくなります。

この場合、検索文字列に単にピリオドだけを指定してやると、正規表現では、ピリオドはあらゆる文字にマッチしますから、「.」から「。」の置換では全ての文字が「。」に変わってしまいとんでもないことになります。まさに、こういう時に 「\」 を使います。これを「.」の前に付けてやると、メタキャラクタとしてのピリオドがリテラルとしてのピリオドに変わってしまいます。従って正規表現で「.」から「。」への置換は

    検索文字列   \.
    置換文字列   

と指定します。「\」はメタキャラクタをリテラルに変える力があるわけです。

しかし、上のような単純な例では、正規表現での検索置換ではなく、通常の検索置換で「.」を「。」に置換するほうが簡単です。もう少し正規表現らしい例をあげましょう。あるテキストのなかに [ ] で括った部分があるとします。その場所を知りたいというときはどうしたらよいでしょう。[ ] のなかは任意の文字で良いですから、

    検索文字列   [.*] 

で検索したらどうでしょう?実はこれはうまくいきません。 [ ] は、正規表現では、文字クラスを指定するためのメタキャラクタでした。ですから、このままつかうと、これは単に検索すべき文字としてリテラルの「.」 と「*」を列挙しただけで、「.」か「*」のどちらかを検索します(ここで、あれぇ? と思った人は、 [ ] の中ではメタキャラクタもすべて文字どおり、リテラルとして解釈されることを思い出してください。もう一度第四回の(注1)を参照してください)。

こういう時には「\」 を使用して、

    検索文字列   \[.*\]

で検索します。 「\[」 は「[」のメタキャラクタとしての働きを「\」で打ち消し、リテラルとしての、「[」を指します。「\]」 も同様に、文字どおりの「]」を表します。これで 「[」が先ずあり、その次に任意の文字を表す 「.」(「\」の効力は直後の1文字にしか及ばないので、ピリオドはメタキャラクタとして扱われます)と、それの0個以上の繰返しをあらわす「*」があり、次に「]」 がくる場所をあらわすことになります。

  ●【練習問題】
・商品の値段を表す「\200」という文字列を検索する正規表現はどうなるでしょうか?
・「500$」という文字列を検索する正規表現はどうなりますか?


【第五回の練習問題の解答】
行頭に半角スペースか全角スペースが0個以上くる、「如是我聞」を指定してやります。そのためには [ ] の中に半角スペースと全角スペースをそれぞれ一個ずついれて後ろに「*」をつけ、その後ろに「如是我聞」をつけた正規表現をつくります。従って、
  検索文字列   [  ]*如是我聞
が正解です。


第七回 メタキャラクタ 「\」(続き)

 ●メタキャラクタ「\」(続)

バックスラッシュ「\」はとても重要なメタキャラクタで、前回お話した以外にもさまざまな働きがあります。まとめておきます。

  (1)「\」 の第1の役割

\」 の役割は二つあります。第一に、前回のピリオドの例のように、メタキャラクタを、リテラルに、普通の文字に変えます。

言い換えれは、「\」をメタキャラクタの前につけることは、メタキャラクタの文脈からエスケープ(抜け出)して、本来の普通の文字として解釈せよという命令です。したがって、こういう 「\」 の記号のついた正規表現の書き方をエスケープシーケンスと呼び、「\」 自体をエスケープとかエスケープ文字と呼びます。これまでに見てきたメタキャラクタを、普通の文字として使おうとするならば、以下のようにエスケープ 「\」をつけなければなりません。

      \.
      \[
      \]
      \^
      \$
      \*

たとえば、具体的に示しますと「500$」(五百ドル)を検索したいときは、

    検索文字列   500\$

としないといけないんですね。「500$」のままだと正規表現では「行末にある、500 」として解釈されます。

また 「\」 自体を 普通の文字として検索したいときは(日本語では円のマークとして使いますから結構有ります)どうするか?例えば、ものの値段の、「\200」というのを検索したいとき正規表現では 「\」 自体をエスケープするために 「\」 を重ねて

    検索文字列   \\200

と書くんですね。こうしないで、「\200」で検索すれば正規表現では「200」を検索します。すぐあとで見るように、検索文字列においては普通の文字に「\」をつけても、意味は変わりません。「\2」 も「2」も同じものとして解釈されます。

またこのエスケープの効力の及ぶのは<直後の1文字>だけだという事もわすれないでください。

    検索文字列   \\.

と書くと 最初の「\」によって2番目の「\」がエスケープされ、普通の文字としての 「\」とみなされますが、次のピリオドはメタキャラクタとして解釈されます。ですからこれは、「\」のあとに任意の文字がつづく事を意味する正規表現で、

    \1 、\あ 、\亜 、\A

などがすべてマッチします。

  (2)「\」 の第2の役割

エスケープ「\」の第2の用法は全く逆です。普通の文字のなかには 「\」 をつけると、普通の文脈をエスケープ(抜けだ)して、メタキャラクタとして特殊な意味に解釈されるようになるものがいくつかあります。

どういう場合かというと、テキストの構成要素の中で普通の文字ではあらわせないもの、例えばタブとか、改行などをあらわす場合です。そういうものは以下のように書きます。例えば、タブを検索したいときは

    検索文字列   \t

とします。同様に改行は \n であらわします(注6)

さらに \( \)のように、() をエスケープしたものは、次回に見るように、検索と置換の中で、メタキャラクタに変身し、置換において大きな力を発揮します。

  (3)まとめ

\」の働きは従って、まとめると以下の3つの場合に分けられます

    1) 本来のメタキャラクタ       ・       リテラル(普通の文字)に

      . * [ ] ^ $ \       ->  「\」付加 ->       \.  \* \[  \]  \^  \$ \\ (. * [ ] ^ $ \ と同じ) 

    2) 普通の文字(の一部)     ・        メタキャラクタ

      t n r ()       -->「\」付加 -->      \t \n \r \( \)  ...

    3) 普通の文字の大半       ・     リテラルのまま

      あ 漢 c ...                    -->「\」付加 -->      \あ \漢  \c  ...( あ 漢 c ... と同じ)

1)と2)の場合、「\」 はメタキャラクタと普通の文字の一部に対して、メタキャラクタの文脈と普通の文字の文脈を切換えます。メタキャラクタを普通の文字に変身させ、普通の文字(のいくつか)はその通常の文脈をエスケープさせて、メタキャラクタに変身させるというわけです。
しかし大半の普通の文字は 「\」 をつけることによって影響を全く受けません。検索の文字列のなかで 「\」 をつけたとしても無視されるだけです。つまり

      \あ \漢  \c ... 

などは

      あ 漢  c  ...

と全く同じものと見なされます。

  ●【練習問題】

正規表現 「\\\.\\$」 に マッチする文字列を含むのは次のうちどれでしょうか。

    1)     \.\$ 
    2)     a\c\$ 
    3)     \\a\ 
    4)     cd\.\
    5)     \.\cd


【第六回の練習問題の解答】
文中に示しましたように ・ 「\\200」・「500\$」です。


(注6) 改行を表す正規表現はコンピュータの環境によって変わる可能性があります。エディタなどのマニュアルで正規表現の規則を参照してください。

第八回 強力な置換 \( \) \1 \2...

 ●検索文字列の保護

ある長文の原稿の章立てが

    第1章
    第2章
      …
    第999章

となっているとします。これをあとから

    chapter 1
    chapter 2
      …
    chapter 999

という形式に変換したいときは、どうしたら良いでしょうか。普通にやれば、当該箇所を一つずつ手で直していく以外にありません。しかし正規表現の検索文字列の保護機能を使えば、一括して変換することができます。

上の例を使えば、まず「第」と「章」という漢字で数字が挟まれている部分を検索し、数字の部分だけを保護して、それを chapterという文字列の後に付け加え、もとの「第…章」と言う部分と入れ換えれば良いわけです。このように、検索文字列中のある部分を置換後にそのまま残しておきたいという時に、今回のタイトルの

       \(  \) 

という正規表現が使えます。この「(」と「)」 をエスケープした記号 「\(」 と 「\)」 の間に検索文字列のなかの保護したい部分をはさんで、置換文字列中で、それを「\1」(最初に保護した文字列)「\2」(次に保護した文字列)などと再現します。百聞は一見にしかずで、上の例では以下のようにします。

    検索文字列    第\([0-9][0-9]*\)章

    置換文字列    chapter \1

少し解説しましょう。第1章、第2章、…、第999章、などの章を表す文字列を正規表現で表せば

       第[0-9][0-9]*章

となります。置換後にも残しておきたい数字の部分を、「\(」 と 「\)」の間にはさんで保護すると上で示した検索文字列ができます。

保護した文字列が一つの場合は、置換後にはそれを「\1」として、再現できます。複数の文字列を保護した場合は、左のものからから順番に「\1」、「\2」などとして再現されます。上の例では一つですから、「chapter」の後に適当に半角スペースを入れて、その後に「\1」を置けば上記のような置換文字列ができます。この文章全体を正規表現の使えるエディタにコピーして、上の検索・置換を実行して威力を試してください。

さて、「\」の役割については前回詳しく話しましたが、ここでの働きはどうなっているでしょうか。もうおわかりですね。この場合の「\」の働きは普通の文字である「(」や「)」をメタキャラクタに変身させています。メタキャラクタの基本セットには、「(」や「)」は含まれていませんから、そのままでは、リテラルとしての単なるカッコにすぎません。そこで、通常の文字としての意味をエスケープし、文字列を保護するメタキャラクタに変身させるために、次のように、それぞれの前に「\」をつけているわけです。

      \ +  (    ・   \(

      \ +  )    ・   \)

では応用問題です。章だけでなく節も変換したいというときはどうしましょうか。つまり

        第1章第3節   ->     chapter 1-3
        第2章第10節   ->     chapter 2-10
        第999章第41節   ->     chapter 999-41

などと変換したいときです。置換前の文字列を正規表現であらわせば、

        第[0-9][0-9]*章第[0-9][0-9]*節

となります。数字の部分をそれぞれ保護するため 「\(」と「\)」で括ります。そして保護した二つの文字列を chapter という語のあとに「-」をはさんで再現すればよいわけです。正解は、次のようになります。

    検索文字列    第\([0-9][0-9]*\)章第\([0-9][0-9]*\)節

    置換文字列    chapter \1-\2

  ●【練習問題】

・ 引用の形式を 「…」 から 『…』に一括して変えるときにはどうすれば良いでしょうか。

・ 文中の年月日の形式を 1999年5月26日 から 1999/5/26 という形式に一括して変えたいときはどうしたらよいでしょうか。


【第七回の練習問題の解答】

\\\.\\$」を最初から順番に見ていくと簡単です。まず最初の「\\」はリテラルの「\」になります。次の「\.」もリテラルの「.」です。さらにつぎの「\\」も同様にリテラルの「\」です。最後に残る「$」は行末をあらわすメタキャラクタになります。従ってこの正規表現の意味は、行末にくるリテラルの「\.\」です。正解は 4) の 「cd\.\」です。


第九回 繰返しの回数 \{n,m\} と簡易AND検索

  ●繰返しの回数を指定する 「\{n,m\}

アスタリスク「*」は直前の文字の「0回以上」の繰返しを意味しました。繰返しの回数を指定したいときには、「\{n,m\}」という正規表現を文字の後ろにつけてやります。n、m、には0から256までの数字が使えます。これで直前の文字の n回以上m回までの繰返しを指定します。これには省略形もあり、下のようにまとめられます。

  \{n,m\}      n 回以上 m 回までの繰返し

  \{n,\}        n 回以上の繰返し

  \{n\}        きっかり n 回の繰返し

たとえば、

10\{2,4\}1

は 1001、10001、100001、にマッチしますが、101、や 1000001 にはマッチしません。また東京の電話番号は、あいだが−でつながれている形式のものは

   03-3[0-9]\{3\}-[0-9]\{4\}

となります。 長さの決まっているようなデータを探し出すのには、これはなかなか便利な正規表現です。ただし残念ながら、この正規表現は全てのツールで使えるわけではありません。たとえばテキスト処理ツールのsedで使えても、awk では使えません。エディタなどのマニュアルを確認してください。

  ●簡易 AND 検索

これまでの正規表現の方法を用いて、簡便な AND 検索 を行なうことができます。ある行に(検索は通常、改行文字で区切られた1行ずつに対して行なわれます)、二つの文字列が、同時に含まれているかどうかを調べることができます。「法華経」と「行者」の二つの言葉がともに含まれている行を検索するやり方は、以下のようになります。

    検索文字列   法華経.*行者

真ん中の 「.*」 は改行以外の任意の文字の0回以上のつながりですから、これにマッチする行は上の二つの言葉を含みます。しかし欠陥がひとつ、必ず「法華経」がさきにこなければ、マッチしません。従って、この二つの言葉をふくむ行を探すためには、もう一回

    検索文字列   行者.*法華経

で検索しなければなりません。

以上でメタキャラクタの基本セットの説明と使用法の解説は終わります。次回からは拡張セットのお話をしましょう。


【第八回の練習問題の解答】

・
    検索文字列   「\([^」]*\)」
    置換文字列   『\1』
となります。「」の中はなんでも良いと考えて検索文字列を /「\(.*\)」/とするといけません。正規表現がマッチする可能性が複数ある時、もっとも長い文字列が選ばれるということを忘れないようにしてください。 /「\(.*\)」/ の場合には

 「法華経」と「行者」『法華経」と「行者』 

のように変わってしまいます。「」のなかに来る文字としては、を除外しないといけません。(第三回の正規表現のマッチする範囲と第四回の、一定の文字を除外する正規表現 [^ ]の所を復習してください)

・
    検索文字列  \([0-9][0-9]*\)年\([0-9][0-9]*\)月\([0-9][0-9]*\)日
    置換文字列   \1/\2/\3
とします。


第十回 拡張メタキャラクタ「+」「?」「|

前回までにいくつかの<メタキャラクタ>を見てきましたが、それらは、Unixの grep や sed で使われはじめた、最も基本的なものです。ツールによってはさらに新しく<メタキャラクタ>を定義して拡張しているものがあります。それらを次に見ていきましょう。

 ●「*」の拡張としての「+」と「?

*」は直前にある文字の「0回以上」の繰返しを表しましたが、 「+」は、「1回以上」の繰返しを表します。「a+」と書けば 「a」「aa」「aaa」などにマッチします。

?」は、直前にある文字の「0回または1回」の出現を表します。

    検索文字列  二乗不?成仏

という正規表現は 「二乗成仏」と「二乗不成仏」の二つにマッチします。「*」と「+」と「?」を使い分けることによって、より柔軟な効率の良い検索が可能になります。

 ●語句の選択をあらわす 「|

[ ] は複数の文字のうちのどれか、「1文字」を表す正規表現でした。これに対して縦棒「|」は複数の語句のうちの一つを表します。つまり語句の OR 検索が可能になります。

    検索文字列  天台|妙楽|伝教

は、「天台」か「妙楽」か「伝教」の三つの語句のうちいずれかを探してくれます。これもなかなか応用範囲の広い強力な正規表現でしょう。


第十一回 拡張メタキャラクタ ( )

 ●グル−プ化のためのメタキャラクタ ( )

( ) はその中の正規表現をひとまとめのものにします。つまりグル−プ化するわけです。用法は二つあります。

  (1) 正規表現をグル−プ化して、その存在や繰返しを指定する

   検索文字列     天台(大師)?

という正規表現は 「天台」という文字列のあとに 「大師」 という文字列が0又は1回出現するところにマッチします。従って

        天台
        天台大師

の二つにマッチします。ただしこの場合 ( ) のあとの ? を忘れれば、これは

     検索文字列  天台大師

と全くおなじになります。

  (2)「|」と組み合わせて語句の選択をあらわす。

    検索文字列         (天台|伝教)大師
などと使います。これは 「天台大師」「伝教大師」の二つにマッチするようになります。 しかし、

    検索文字列         天台|伝教大師

とすれば、この正規表現は「天台」「伝教大師」のふたつの、どちらかにマッチするだけです。 また ( ) によるグル−プ化は英語の単語の語尾変化を記述したりする場合にも使えます。

     compan(y|ies)    -->   company, companies  にマッチ
     stud(y|ies|ied)   -->  study, studies, studied  にマッチ
なかなか便利です。

基本セットのメタキャラクタは文字単位の操作を可能にしますが、このように文字列のなかの部分文字列をひとまとめにして扱う方法は、前々回の \( \)の検索文字列の保護だけしかありませんでした。しかも、\( \)の中ではORの選択を許してくれませんでした。拡張セットの ( ) はこれを簡単に実現するようになったわけです。

  ( ) についての重大な注意

ただ、注意しないといけないのは、この便利さは正規表現のメタキャラクタに混乱をもたらすことにもなりかねません。基本セットでは ( ) はメタキャラクタに入っていませんでした。従ってメタキャラクタとして使おうとすれば、「 \ 」 によってエスケープしなければなりませんでした。しかし、拡張セットでは ( )はそのままで、メタキャラクタとして使われます。

この混乱をさけるため、例えば、awk というツールでは sed で使われていた 検索文字列の保護の\( \)を使わないで、もっぱらグル−プ化するためにだけ( )を使うということになっています。そしてsed では前回のものも含めて、拡張メタキャラクタは一切使わない仕様になっています。

従って、この( )を正規表現のなかで使うときは、その役割をツールごとに確認しておくことが不可欠です。たとえばMacの YooEditなどでは、基本セットに忠実に ( ) を通常の文字として扱い、メタキャラクタとして使うときには、いつも「 \ 」でエスケープすることを要求します。そして、その上「| 」もエスケープして 上のような語句の選択にも使えるようにしています。

従って、YooEditでは上記の 「(天台|伝教)大師」 という検索文字列の指定は

  検索文字列   \(天台\|伝教\)大師
となります。皆さんが使っているエディタやソフトではどうなっているでしょうか。

  ●【練習問題】

正規表現、「(天台|伝教)(門下|大師)?」 にマッチする文字列を全て列挙してください。


第十二回 まとめ

今まで学んできたメタキャラクタをまとめておきましょう。

 ● 基本セット
. ・ピリオド、改行以外の任意の文字を表す。 * ・直前にある文字の0回以上の並びを表す。 例 a* と書けば 「」「a」「aa」「aaa」などにマッチ [ ][ ] 内の任意の文字を表す。文字クラスを定義。 例 [あいうえお] あ〜お までの任意の文字 ・ハイフンを[ ] 内で使えば、ある文字からある文字までの範囲。 例 [あ-ん] と書けばすべてのひらがな [亜-龠] ですべての漢字 (注) [ ] 内で用いられなければハイフンは通常の文字と して解釈される ^ ・正規表現の最初におかれると、行頭をあらわす 例 ^第 で行頭にある「第」の文字 (注) 正規表現の最初に用いられなければ通常の文字 として解釈される ・[ ] 内の冒頭で使えば否定を表し、〜以外の文字になる 例 [^0-9] で数字と改行以外の任意の文字を表す $ ・正規表現の最後に用いて、行末をあらわす 例 。$ と書けば行末の「。」を表す。 (注) 正規表現の最後に用いられなければ通常の文字 として解釈される \ ・メタキャラクタを通常の文字に戻す。またいくつかの通常の 文字にメタキャラクタの性格を与える。 例 \. と書けば文字どおりのピリオドを表す。 例 \t と書けばタブ(TAB)を表す。 \{n,m\} ・直前の文字の n 回から m 回までの繰り返しを表す。 \{n,\} と指定すれば n 回以上の繰返しを表す。 \{n\} と指定すれば n 回の繰返しを表す。 例 [0-9]\{2,5\} 数字の2回から5回までの繰返し。
 ● 拡張メタキャラクタ
+ ・直前にある文字の1回以上の並び 例 a+ と書けば 「a」「aa」「aaa」などにマッチ ? ・直前にある文字の0回または1回の並び 例 a? と書けば 「」「a」にマッチ || の前後の語句のいずれかをあらわし OR 検索に使用。 例 天台|伝教 と書けば 「天台」「伝教」のどちらかにマッチ () ・ 正規表現のグル−プ化 例 天台(大師)? で「天台」と「天台大師」のどちらかにマッチ

いかがでしょうか?数としてはわずかですが、これらを活用すれば、驚くほどテキスト処理の能率をあげることができます。 また正規表現は、sed、awk、perl などの本格的なテキスト処理ツールの基礎でもあり、マスターすれば、これらの有益なツールの使用にも楽々と進んでいけることでしょう。がんばってください。(完)

 【第十一回の練習問題の解答】
       「天台」「伝教」「天台門下」「伝教門下」「天台大師」「伝教大師」

文責 河合一夫

ご質問は、管理人まで