English

原文は http://publish.ez.no/article/articleprint/11/ にあります

正規表現の説明



この記事は「正規表現」の紹介をいたします。まず、「正規表現」について説明し、その構文を紹介、幾つかの複雑度の違う例を出し、最後に「正規表現」を使うツールをリストアップします。

概念

「正規表現」 は英数字とメタキャラクタで知られる特別な文字を組合せたテキストパターンです。ファイル管理でよく用いられている「ワイルドカード表現」はこれとよく似てます。このパターンはテキストストリングとのマッチに使われてます。マッチの結果は成功か失敗として得られますが、成功した時はすべてのパターンがマッチする必要は無く、これは記事の後半で説明されてます。

「正規表現」は三つの用途があります:一般のテキストマッチ、検索/置換、及び分割です。後者は基本的には反マッチと同じで、すなわち「正規表現」とマッチしないすべてのテキストストリングのリストアップを意味します。

「正規表現」 はよく簡単に「regexps」か「RE」と呼ばれますが、マッチ性を考えて、その全名を指します。

「正規表現」が多能の為、テキストの処理及び構文解析に広く使われています。UNIXユーザは「grep」「sed」「awk」 及び「ed」などのプログラムの使用を通して、良く理解していると思います。テキストエディタの「(X)Emacs」及び「vi」も度々用います。多分「正規表現」を使う一番良く知られているのはプログラミング言語の「Perl」で、今日まで「Perl」が一番先進した「正規表現」を実装しているのがお分かりでしょう。

使い道

なんで「正規表現」を学ばなくてはならないか、きっと今考えているでしょう。パソコンの一般ユーザなら、その使用から得られる利益は少ないけれど、開発者かシステム管理者であれば、「正規表現」を学習する事によって、仕事がどんなにか楽になるでしょう。

開発者はそれを使ってテキストを切り刻み、コードを直したり、その他の不思議な事ができるでしょう。システム管理者はそれを使ってログを捜索し、くだらないタスクを自動化したり、不法活動があるかどうかネットワークトラフィックを嗅ぎ出す事ができます。

システム管理者が「正規表現」の知識を持っていなかったら、それは罪を犯しているとまで言いたいです。

量記号

構文を説明する前に、最後のページへ行って、どのプログラムがこの記事のサンプルをテストできるか見て下さい。

表現内容は、前にも説明しましたが、英数字とメタキャラクタの組合せです。英数字は

abc
のアルファベット文字か

123
の数字です。事実、「正規表現」の世界で、メタキャラクタ以外のキャラクタはそれ自身(リテラル(文字通りの)キャラクタと呼ぶ)とマッチ(一致)しますが、殆んどの場合はあなたが思った通り英数字です。バックスラッシュ「\」は非常に特殊なキャラクタで、メタキャラクタをリテラルキャラクタに変え、英数字をメタキャラクタの様なキャラクタかシーケンス(後に説明)に変えます。メタキャラクタは:

\ | ( ) [  {  ^ $ * + ? . < >
とにかく一般のキャラクタはそんなにおもしろくないので、我々の初めてのメタキャラクタに飛び込もう。

句読点或はドット、「.」はよく混乱をもたらすので、一番最初に説明する必要があります。このキャラクタはみんなが考えるような文字行の句読点とマッチしません。その代わり、これはどんなキャラクタともマッチする特別なメタキャラクタです。これを使って文字行の終端や小数点を探そうとしたら、変な結果をもたらします。前にも説明しましたが、「リテラル」の(文字どおりの)意味を得たければ、「.」にバックスラッシュを付ける必要があります。例えばこの表現を見て下さい:

1.23
これはテキスト中の「1.23」と言う数字とマッチすると推測できますが、下記の数行ともマッチします

1x23
1 23
1-23
この表現法を小数点の付いた数字にだけマッチするには、下記の様に変えます

1\.23
これは非常に大事な事なので、覚えておいて下さい。さあ先へ進みましょう。

度々起こるメタキャラクタは下記の2つあります

* and +
それらは「量記号」と言って、あるキャラクタが度々出現するかどうかを検索し、検索したいキャラクタを「量記号」の前に置きます。「*」メタキャラクタは一行の文字の内、ゼロかそれ以上のキャラクタのマッチの検索をし、「+」のメタキャラクタは似通ってますが、1かそれ以上のマッチを検索します。

一行の単語の中に「c」と言う文字の付く単語を探し出すには、下記の様に書きたいでしょう:

c*
驚いた事に、「c」が含まれてない単語までも多量なマッチが出てきてしまいます。どうしてかと疑問を持たれますが、答えは簡単です。「*」は文字のマッチがゼロかそれ以上と言うことを思い出して下されば、全くその通りで、ゼロ文字を捜索したからです。
正規表現では「空のストリング」と言われるマッチが可能で、それはただ単にゼロサイズのストリングです。この空のストリングはテキストの至る所にあり、例えば次の単語を見て下さい:

go
「go」は三つの空のストリングを持っています。これらの空のストリングの位置は「g」の前、「g」「o」の間、及び 「o」の後です。一つの空のストリングは厳密にはたったの一つの空のストリングしか含まれていません。始めは全くばかげた事見たいの様ですが、もっと複雑な表現法がどの様に使われているかを後ほど学びます。

以上の知識でもって、次の表現に変えて行きたいでしょう:

c+
この結果、「c」が含まれている単語だけが出てきます。

次の勉強するメタキャラクタは下記のものです:

?
これはただ単に、サーチエンジンに指定した文字の有無のマッチ(1か0)です。例えば下記の表現法では:

cows?
以下のいずれかの行とマッチします:

cow
cows

これらの3つのメタキャラクタはただ単にもっと一般的な下記の「量記号」の特別なシナリオです

{n,m}
「n」「m」はそれぞれ「量記号」の最小と最大サイズ値です。例えば

{1,5}
は1から5個の文字のマッチを意味します。無限のマッチをしたければ、「m」をスキップすることが出来ます:

{1,}
では一個以上の文字のマッチです。これは「+」キャラクタと全く同じです。これで関連がお分かりでしょう。すなわち、「*」「{0,}」と同じで、 「+」「{1,}」 と、それから 「?」「{0,1}」と同じです。
「量記号」に最後に出来ることは「カンマ」をスキップ出来ます

{5}
そしてそれは5個の文字までのマッチを意味し、それ以上でも以下でもありません。

アサーション(前提条件)

次に説明するメタキャラクタタイプは「アサーション」で、与えられたアサーションが正しい場合はマッチします。最初に紹介するアサーションペアは下記の2つで、

^ と $
それらは行の先頭と最後とをマッチします。幾つかの「正規表現」の実行はその行動を変え、すなわちテキストの先頭と最後とをマッチする事に気をつけて下さい。これらのアサーションはいつも「ゼロ長さストリング」とマッチし、即ち位置とマッチします。例えば下記の表現を書いたならば:

^The
「The」で始まるどんな行ともマッチします。

次のアサーションキャラクタは単語の先頭と最後とをマッチし、それらは下記のもので:

< と >
正確にある単語とのマッチに便利で、例えば:

cow
は下記の単語とマッチします

cow
coward
cowage
cowboy
cowl
表現をちょっと変化すると:

<cow>
そうすれば、テキストの「cow」と言う単語だけとマッチします。

最後に一言。リテラルキャラクタは事実全部自分自身のアサーションで、上記のアサーションとの違いはリテラルキャラクタは「長さ」を持ってます。明確にする為、「ゼロ幅」のものだけに「アサーション」と言う単語を使います。

グループと交替

「量記号」は説明した時にお気づきだと思いますが、その左側のキャラクタにだけ作用します。これは我々の表現法を制限するので、「量記号」の他の使用方法を述べます。「量記号」はメタキャラクタにも使われ、「アサーション」に使われるのはばかげていて、なぜなら「アサーション」は「ゼロ幅」なので、1個、2個、3個、或はそれ以上のマッチングは余り有用ではありません。しかし、グルーピング及びシーケンスメタキャラクタの量記号化は理想的です。まず、グルーピングを始めましょう。

左括弧と右括弧を使ってグループ、すなわち「次表現」と良く言われるものを形成することが出来ます:

「(」 と 「)」
左括弧「(」は「次表現」の始まりで、右括弧「)」はその終わりです。一つの「次表現」の中に一個以上の「次表現」を含む事が出来ます。コンテンツがマッチすれば、「次表現」がマッチします。それでこれを「量記号」と「アサーション」と混用すると:

( ?ho)+
下記のすべての行とマッチします

ho
ho ho
ho ho ho
hohoho
「次表現」の他の使い方はマッチの一部を抽出する。これは後述の「シーケンス」と接続して良く使われてます。

「次表現」の結果をバックリファレンスに用いる事も出来ます。バックリファレンスはゼロ以外のバックスラッシュされた数字が与えられ、合計9個です。
バックリファレンスはそれと実際マッチされた「次表現」とマッチします(例外は{article_contents_1}は「null」キャラクタにマッチします)。「次表現」の数は左括弧を左から数えれば分かります。

バックリファレンスは幾らか制限されますが、特に9個しかなく、希な場合、これを必要とします。幾つかの「正規表現」の実施ではゼロから始まらない複数の数字を使う事が出来ます。

次は「交替」を説明します。これは多数の単語のマッチを許します。「交替」のキャラクタは次の通りです

|
例としては:

Bill|Linus|Steve|Larry
「Bill」、「Linus」、「Steve」か「Larry」、のいづれかにマッチ出来、「次表現」と「量記号」と混用すれば、次の事が出来ます:

cow(ard|age|boy|l)?
それは下記のだけの単語とマッチします

cow
coward
cowage
cowboy
cowl
この記事で前にも申し上げましたが、マッチを成功させるには全部の表現がマッチする必要はありません。「次表現」を「代替」と一緒に使ったときに起こります。例えば下記の例です:

((Donald|Dolly) Duck)|(Scrooge McDuck)
お分かりの通り、左か右のトップ「次表現」のどちらかとマッチしますが、両方ではありません。複雑なパターンを一つの「次表現」に実行する時、それが失敗し、もう一つの「次表現」に実行するのに便利です。

シーケンス(手順)

最後に、マッチできる文字シーケンスを定義するシーケンスについて。時々、そのままマッチさせたくはないけれど、しかし何かそれにとても似ている単語でマッチさせたい場合、シーケンス文字は

「[」 と 「]」
シーケンス角括弧に入れられるどんな文字でも(メタキャラクタさえ)、リテラル文字として扱われます。唯一の特殊文字は文字範囲を示す「-」とシーケンスを無効にするのに用いられる「^」です。シーケンスはalternation(交代)といくぶん類似しています。類似性はリストされるアイテムのうちのただ1つがマッチする事です。

[a-z]
は英語のアルファベット「a‐z」であるどんな小文字にでもマッチします。 その他の普通のシーケンスは

[a-zA-Z0-9]
は英語のアルファベットで数字と同様に、どんな小文字や大文字にでもマッチします。例えば

<[a-zA-Z]+>
はすべての全部の語にマッチします。これは

cow
Linus
regular
expression
にマッチします。しかし

200
x-files
C++
にはマッチしません。もし語以外のものを見付けたい時の表現は

[^a-zA-Z0-9]+
とすれば、英語のアルファベットやどんな数字も含まない文字シーケンスを見つけられます。

いくつかの正規表現の実装は、一般的に使われるシーケンスの省略版を使う事を許します。これらがそうです:

\d, a digit [0-9]
\D, a non-digit [^0-9]
\w, a word (alphanumeric) [a-zA-Z0-9]
\W, a non-word [^a-zA-Z0-9]
\s, a whitespace [ \t\n\r\f]
\S, a non-whitespace [^ \t\n\r\f]

ワイルドカード

ワイルドカードで若干の知識がある人のために、ワイルドカードを正規表現に変換する方法について、簡単な説明をします。本稿を読んだ後に、おそらくワイルドカードとの類似点がわかるでしょう。例えば

*.jpg
は「.jpg」で終わるどんなテキストにでもマッチします。 文字で角括弧を指定する事もできます。例えば

*.[ch]pp
は「.cpp」または「.hpp」で終わるどんなテキストにでもマッチします。まったく正規表現と非常に類似しています。

演算子「*」の変換

私達は、これを句読点と量記号「*」による正規表現でする事を勉強したので、「*」はワイルドカードで何かの0以上がマッチする事を意味します。このようになります

.*
また、ワイルドカードからどんな句読点に変換する時にもバックスラッシュが付けられる事を忘れないで下さい。

演算子「?」の変換

「?」はどんな文字にもマッチする事を意味しますが、何かをマッチします。 これはまさに句読点がするものです。

演算子 [] の変換

角括弧はワイルドカードから正規表現へ同じ意味で行かせる時に、角括弧をそのままに扱うことができます。

次のようになります:
どんな「*」文字でも「.*」に置換します
どんな「?」文字でも「.」 文字で置換します
角括弧はそのままにしておいて下さい。
どんなメタキャラクタの文字でもバックスラッシュ変数(variant)に置換します。


*.jpg
は、次のように変換されます

.*\.jpg


ez*.[ch]pp
は次のように変換されます

ez.*\.[ch]pp
あるいは、

ez.*\.(cpp|hpp)

正規表現を本当に理解するために、私はこのページにいくつかの普通に使われる正規表現を書いておきます。それを勉強して、実験して、正規表現が何をしているか正確に理解するようにして下さい。

Eメールの妥当性、妥当なEメールアドレスでマッチするものだけ、例えば
user@host.com

[a-z0-9_-]+(\.[a-z0-9_-]+)*@[a-z0-9_-]+(\.[a-z0-9_-]+)+

Eメールの妥当性 #2、Eメールアドレスの前にある名前でマッチ、例えば "Joe Doe <user@host.com>"

("?[a-zA-Z]+"?[ \t]*)+\<[a-z0-9_-]+(\.[a-z0-9_-]+)*@[a-z0-9_-]+(\.[a-z0-9_-]+)+\>

プロトコルの妥当性、htpp://、 ftp:// あるいは https:// など、ウェブベースのプロトコルでマッチ

[a-z]+://

C/C++ include、C/C++ ファイルの妥当なinclude文でマッチ。

^#include[ \t]+[<"][^>"]+[">]

C++ 行コメントの終り

//.+$

C/C++ スパン行コメント、それは1つの不備があります、発見できますか?

/\*[^*]*\*/

浮動小数点数、1.2や0.5と言った簡単な浮遊小数点数でマッチ

-?[0-9]+\.[0-9]+

16進数、C/C++ スタイルの16進数(0xcafebabe)でマッチ

0x[0-9a-fA-F]+

ユーティリティ

正規表現を使用するいくつかのユーティリティがあります。短い説明でそのリストを残しておきます:

grep

grepは、名前の付いた入力ファイルを与えられたパターンのマッチを含む行で検索します。それは、特定のパターンを含むファイルを見つけるのに用いる事もできます。例えば:

grep -E "cow|vache" * >/dev/null && echo "Found a cow"

これはLinuxディストリビューションの中でむしろ一般的なユーティリティです。しかし、あなたがそれを持っていないならば、GNUページでバージョンを手に入れられます。

もしこの項目で説明されているメタキャラクタが機能しないならば、-E オプションを付けると小さな情報が、拡張正規表現を可能にします。

sed

sedは、ストリームエディタです。ストリームエディタは、入力ストリーム上で基本的なテキスト変換を実行するのに用いられます。

これはLinuxディストリビューションの中でむしろ一般的なユーティリティです。しかし、あなたがそれを持っていないならば、GNUページでバージョンを手に入れられます。

gawk

Gawkは、AWKプログラミング言語のGNUプロジェクトによる実装です。 それは、POSIX 1003.2 コマンド言語の言語定義とユーティリティ基準に準拠します。

これはLinuxディストリビューションの中でむしろ一般的なユーティリティです。しかし、あなたがそれを持っていないならば、GNUページでバージョンを手に入れられます。

[ここで編集されたドキュメント]
正規表現 関連リンク:

Regular Expressions and NP-Completeness
Equivalence of Regular Expressions and Finite Automata
perlretut - Perl の正規表現のチュートリアル