UNIX/基礎知識/正規表現
Table of Contents |
正規表現の基礎 
正規表現とは、文字列のパターンマッチングを表現する方法のひとつです。 ワイルドカードみたいなものですが、 基本的にパターンマッチング (grep や sed など) で使用されます。 ワイルドカードは文字列全体を表現するために使用されるのに対し、正規表現は部分文字列を表現して、対象文字列に含まれているかを判断するのに使用します。
ツールによって使える正規表現が違ったりするので、 基本的なものだけを紹介します。
. | 任意のキャラクタ一文字とマッチします。 |
* | 演算子の直前に置かれている部分正規表現の可能な限り大きい0回以上の繰り返しにマッチします。 |
+ | 演算子の直前に置かれている部分正規表現の可能な限り大きい1回以上の繰り返しにマッチします。 |
^ | 文字列の先頭にマッチします。 |
$ | 文字列の末尾にマッチします。 |
[] | []の中に置かれた文字のいずれかにマッチします。[^ のように [ の直後に ^ がきていた場合は逆に、[] 内に置かれた文字以外の文字にマッチします。例えば[abc] は a か b か c を意味します。[^abc] は a か b か c 以外を意味します。また、[a-z] のように a から z までの任意の1文字という意味の範囲指定も可能です。 |
() | 正規表現のグループ化を意味します。例えば (hoge)+ は hoge, hogehoge, hogehogehoge 等を意味します。hoge+ とすると、hoge, hogee, hogeee などです。(hoge+)+ のような指定も可能です。また (hoge|foo)+ ならば hoge または foo の繰り返し、たとえば hogefoohoge などです。 |
\N または $N | 後方参照。N は数字(1,2,3,...)の意。\N の場合 (emacs, sed) や $N の場合 (perl, php) があります。先行して現れた N 番目の ()で囲まれた部分正規表現にマッチした文字列を参照することができます。例えば (Ora+nge)\1 の \1 は Orange や Oraaaange など正規表現にマッチした文字列になります。置換目的として、置換対象文字列内で使用することもできます。 |
具体例 
'' (空文字)
↑全ての文字列にマッチします(全ての文字列は空文字部分文字列をもちろん持つ)。
.*
↑全ての文字列にマッチします。
^Apple$
↑Apple だけの文字列にマッチします。 (xxxApplexxx などはダメ)
(^Apple$|^Orange$)
↑Apple だけ、もしくは Orange だけの文字列にマッチします。
^Apple
↑Apple で始まる文字列にマッチします。
Apple$
↑Apple で終わる文字列にマッチします。
拡張正規表現 
egrep や perl, php, python, ruby などモダンな言語では、拡張正規表現を使うことができます。拡張記法は
(?...)
のように始まります。以下、便利な例
^(?!^Apple)
↑Apple で始まる文字列以外にマッチします。
^(?!^.*Apple$)
↑Apple で終わる文字列以外にマッチします。
ちょっとむずかしい具体例 
HTMLタグの取り出し 
HTMLタグの形式はすべて
<...>
という形になっています。なので一見すると
<.*>
でよさそうな気がしますが、この場合は
<p> This is a text. </p>
というテキストがあったとすると、
<p>
ではなく
<p> This is a text. </p>
とマッチしてしまいます。
<......................>
のように見てしまうわけです。 そこで以下のようにします。
<[^>]*>
このようにすると [^>]* は "> 以外の文字の繰り返し" を意味するので > が出てきたところで止まります。つまり
<p>
のところでとまってくれます。
C言語コメントの取り出し 
[^...] で文字の否定はできますが、文字列の否定はできません。しかし工夫をすればできないことはないです。 C言語のコメント /* */ を例に考えてみます。上の HTML タグのときと同じ考え方で
/\*("*/"以外の文字列)\*/
とできればいいわけですが、("*/"以外の文字列) が指定できないわけです。
まず結論からいうと、
/\*/?([^/]|[^*]/)*\*/
でマッチできます。
"/*" と "*/" の間にある文字列のパターンは、 「"/" 以外の文字」と「直前が "*" 以外の "/"」を組み合わせた文字列 という考え方をします。その部分が
([^/]|[^*]/)*
です。
/?
の部分は
/*/ ... */
のようなものにもきちんとマッチするようにするためです。/? がない場合はマッチせずに素通りしてしまいます。まず /* とマッチした後
/ ... */
のような形になりますが、問題の最初の / は [^/] とマッチしないので、[^*]/ とのマッチを試みようとしますが、 / の前に文字がないのでマッチングができません。結果 ([^/]|[^*]/)* とのマッチングが失敗して終了してしまいます。 というわけで、先頭の / に対しては特別な処理でマッチさせてやることになります。それが /? の部分です。
参照 
- 正規表現メモ
- 細かいところは言語毎に違います。リストアップしてくれているので比較しやすいです。
- Python 正規表現
- Perl 拡張正規表現