.NET Frameworkで使える正規表現

 『正規表現の使い方』では主にRegexクラスの使い方について説明しました。ここでは実際に使える正規表現について、説明したいと思います。とはいうものの、言葉で説明するより試してみるのが一番と思いますので、正規表現のお試しスクリプトを以下に準備しました。

# coding: shift-jis

from System.Text.RegularExpressions import *

while True:
  input = raw_input(" > ") ←入力する文字列
  if input == "quit": ←"quit"を入力するとプログラムは終了します。
    break

  pattern = raw_input(">> ") ←正規表現
  print Regex.Replace(input, pattern, "<$0>")

raw_input("bye-bye")


以下は、役に立つと思われる正規表現を抜粋しました。
文字クラス
 一文字を指定する正規表現です。
正規表現要素 マッチする箇所 マッチ例
. \n以外の任意の一文字 .at
(連続する任意の3文字のうち2,3文字目がatの箇所
<bat>man fought with <cat> woman.
[chars] 文字クラス内の任意の一文字 [aiueo]
(a, i, u, e, oのいずれかの文字)
b<a>tm<a>n f<o><u>ght w<i>th c<a>t w<o>m<a>n.
[^chars] 文字クラス内の任意の一文字以外 [^aiueo]
(a, i, u, e, o以外の文字にマッチ)
<b>a<t><m>a<n>< ><f>ou<g><h><t>< >
<w>i<t><h>< ><c>a<t>< ><w>o<m>a<n><.>
[first-last] 文字クラスの範囲内の一文字 [a-h]
(aからhまでの文字にマッチ)
<b><a>tm<a>n <f>ou<g><h>t wit<h> <c><a>t wom<a>n.
[^first-last] 文字クラスの範囲外の一文字 [^a-h]
(aからh以外の文字にマッチ)
ba<t><m>a<n>< >f<o><u>gh<t>< >
<w><i><t>h< >ca<t>< ><w><o><m>a<n><.>
[first1-last1first2-last2...] 文字クラスの範囲内の一文字(複数の範囲) [7-9a-e]
(7から9、aからeの文字にマッチ)
0123456<7><8><9><a><b><c><d><e>fghijklmn
[^first1-last1first2-last2...] 文字クラスの範囲外の一文字(複数の範囲) [^4-9a-k]
(7から9、aからf、AからF以外文字にマッチ)
<0><1><2><3>456789abcdefghijk<l><m><n>
[base-[exclude]] 文字クラスbaseから文字クラスexludeを減算したクラス内の一文字 [a-z-[e-w]] <a><b><c><d>efghijklmnopqrstuvw<x><y><z>
[base-[exclude1-[exclude2]]] (文字クラスの減算を入れ子にしたもの) [a-z-[e-w-[i-k]]] <a><b><c><d>efgh<i><j><k>lmnopqrstuvw<x><y><z>
\w 単語に使用される文字 \w <1><2><3><a><b><c>+-*/
\W \w以外の文字 \W 123abc<+><-><*></>
\d 10進数字に使用される文字 \d <1><2><3>abc+-*/
\D \d以外の文字 \D 123<a><b><c><+><-><*></>
\s 空白を表す文字 \s 123< >abc<\t>+-
\S \s以外の文字 \S <1><2><3> <a><b><c>\t<+><->

量指定子
 量指定子は文字クラスの連続する数を指定することができます。
正規表現要素 マッチする箇所 マッチ例
* 0個以上連続する箇所 a*b
(連続する0個以上のaの後にbがある箇所にマッチ)
<b><ab><aab><aaab><aaaab><aaaaab>
+ 1個以上連続する箇所 a+b
(連続する1個以上のaの後にbがある箇所にマッチ)
b<ab><aab><aaab><aaaab><aaaaab>
? 0個または1個連続する箇所 a?b
(aの後にbある箇所、またはbのある箇所にマッチ)
<b><ab>a<ab>aa<ab>aaa<ab>aaaa<ab>
{n} n個連続する箇所 a{3}b
(連続する3個のaの後にbがある箇所にマッチ)
babaab<aaab>a<aaab>aa<aaab>
{n,} n個以上連続する箇所 a{3,}b
(連続する3個以上のaの後にbがある箇所にマッチ)
babaab<aaab><aaaab><aaaaab>
{n,m} n個以上m個以下連続する箇所 a{2,3}b
(連続する2から3個のaの後にbがある箇所にマッチ)
bab<aab><aaab>a<aaab>aa<aaab>

アトミックゼロ幅アサーション
 ゼロ幅アサーションは境界を指定するのであって、一文字も指定しないという意味ですが
もう少し砕けていう文字列の位置を指定できます。
正規表現要素 マッチする箇所 マッチ例
^ 文字列の先頭 ^cat
(catで始まる箇所にマッチ)
<cat>catcatcatcat
$ 文字列の末尾 cat$
(catで終わる箇所にマッチ)
catcatcatcat<cat>
\b 単語の境界
(\wと\Wの境界)
\b\w{2}
(単語の境界からの2文字にマッチ)
<ca>t <ca>t <ca>t
\B \b以外 \B\w+
(単語の境界でない箇所から文字にマッチ)
c<at> d<og> c<hiken>

条件分岐
 正規表現の中でもif文やandやorみたいに条件分岐することが可能ですが、かえってスクリプトを分かりにくくすることが多くなってしまいます。使うとしても大体、下のorぐらいだと思います。
正規表現要素 マッチする箇所 マッチ例
expression1|expression2|... |で区切られた正規表現のいずれかに一致する箇所 (^cat|cat$)
(^catまたはcat$にマッチ)
<cat>catcatcat<cat>

グループ化
 下の例のように正規表現中で()で括られた箇所はグループと見なされます。グループ番号はグループの位置順に1から始まるインデックスが与えられます。 グループ番号0は特別に正規表現にマッチした箇所全体を示しています。
正規表現要素 グループ化される箇所 マッチ例(下付き文字はグループ番号またはグループ名)
(subexpression) subexpressionにマッチする箇所 \b(\w{3})\s(\w+)\b
(3文字の単語とそれに続く単語を記憶)
batman fought with <cat1 woman2>.

前方参照
 グループ番号を指定することで、前方の文字列を参照する正規表現が書けます。
正規表現要素 マッチ例
\number グループ番号numberの値 (\S)[^\1]*\1
(空白以外の文字で挟まれた範囲にマッチ)
<I think I>'<ll be l><ate aga>in.

最短一致の量指定子
 上の例で最後にマッチした箇所が"<ate aga>"であって、なぜ"<ate a>"でないのか疑問ではありませんか。
それは普通の正規表現では最長一致の原則というのがあり、できるだけ長いエリアをマッチされるように
決まっているからです。
 しかし時にはその原則を破りたいときが出てきます。そうした時に以下のようなものを使います。
正規表現要素 マッチする数 マッチ例
*? 0個以上連続する箇所の中で最短の箇所 a*
a*?
<aaaaa><>b<>b<>
<>a<>a<>a<>a<>a<>b<>b<>
+? 1個以上連続する箇所の中で最短の箇所 a+
a+?
<aaaaa>bb
<a><a><a><a><a>bb
{n,}? n個以上連続する箇所の中で最短の箇所 a{3,}
a{3,}?
<aaaaa>bb
<aaa>aabb
{n,m}? n個以上m個以下連続する箇所の中で最短の箇所 a{2,4}
a{2,4}?
<aaaa>abb
<aa><aa>abb

置換
 Regex.ReplaceメゾットやMatch.Resultメゾット内で使える置換文字列の正規表現です。
お試しスクリプトの次の行で、"<$0>"の部分を"例(置換文字列)"に変えてテストしてみましょう。

  print Regex.Replace(input, pattern, "<$0>")

正規表現要素 例(正規表現) 例(置換文字列) 例(入力文字列) 例(置換後の結果)
$number グループ番号numberに一致した文字列 (\w+)\s(\w+)
(空白で区切られた2つの単語)
<$0>
(マッチした箇所を括弧で括る)
it must be a duck. <it must> <be a> duck
$` 一致した箇所より前にある文字列全体 (ghi) <$`>
(ghiにマッチした箇所をそれより前にある文字列に置換)
abcdefghi abcdef<abcdef>
$' 一致した箇所より後ろにある文字列全体 (abc) <$'>
(abcにマッチした箇所をそれより後ろにある文字列に置換)
abcdefghi <defghi>defghi
$_ テスト対象の文字列全体 (def) <$_>
(defにマッチした箇所を入力文字列に置換)
abcdefghi abc<abcdefghi>ghi