何が正規なのか問いたい。問い詰めたい。小1時間問い詰めたい。
はい、今日のテーマは正規表現です。
サンプル コード: 正規表現.cs
正規表現とは
まずは昨日のおさらいから行きましょう。
- 正規表現(regular expression)は、文字列のパターン マッチのための簡易言語です。
- C#や.NETに特有のものではなく、PerlやJavaのものとおおむね共通です。
- C#から正規表現を使うには、Regexクラスを利用します
-
詳細はMSDNの以下のページで確認できます。
しかし、codezineの記事でも言いましたけど、呼び名としていまいちなんですよねぇ、正規表現って。
元々はコンピューター言語学方面の学術用語です。今となっては、パターン マッチのためにいろいろと追加されていて、本来の意味での正規表現にはなっていないそうですけども。
とりあえず、正規表現 = パターン マッチ と覚えてください。
正規表現の書き方
いくつかの特別な意味を持った記号(. {} \ * + など)以外は、一致させたい文字をそのまま書きます。例えば、abという正規表現は、abを含む文字列に一致します。
ab |
||
abを含む文字列に一致します。abの前後に別の文字があっても構いません。aとbの間に別の文字が入る場合には一致しません。 |
||
一致例 |
abc |
stab |
不一致例 |
a |
acb |
この例をC#で書くと、以下のようになります。
var r = new Regex(“ab”);
Console.WriteLine(r.Match(“abc”).Success); // true
Console.WriteLine(r.Match(“enable”).Success); // true
Console.WriteLine(r.Match(“a”).Success); // false
Console.WriteLine(r.Match(“acb”).Success); // false
以降では、特殊記号について説明していきましょう。
数量指定
同じ文字の繰り返しを検出したい場合に使える、数量指定用の特殊記号として、 *(アスタリスク)、+(プラス)、? (はてな)、{} (波括弧)などがあります。
ab*a |
||
* (アスタリスク)で、0個以上の同じ文字を表します |
||
一致例 |
aa |
abbba |
不一致例 |
a |
ab |
ab+a |
||
+ (プラス)で、1個以上の同じ文字を表します |
||
一致例 |
aba |
abbba |
不一致例 |
aa |
aca |
ab?a |
||
? (はてな)で、0個もしくは1個の文字を表します |
||
一致例 |
aa |
aba |
不一致例 |
abba |
aca |
ab{2}a |
||
{} で、連続する同じ文字を表します。数字を1つだけ入れると、その個数ぴったりを表します。 |
||
一致例 |
abba |
|
不一致例 |
aba |
abbba |
ab{2,4}a |
||
{} に、コンマで区切って2つの数字を入れると、最小と最大の数指定できます。 |
||
一致例 |
abba |
abbbba |
不一致例 |
aba |
abbbbba |
通常、これらの数量指定は「最大一致」になります。一方、これらの記号の後ろに ? (はてな)をつけることで、「最小一致」パターンも作れます。
var r1 = new Regex(@”.*,”); // 任意の文字の後ろにコンマ
var r2 = new Regex(@”.*?,”); // 同上。ただし、最小一致
var str = “aaa,aaa,aaa,”;
Console.WriteLine(r1.Match(str)); // aaa,aaa,aaa, まで拾われる
Console.WriteLine(r2.Match(str)); // aaa, だけ拾われる
エスケープ
特殊な意味を持つ記号(. や *)自体を検索するためには、特殊記号の前に\ 記号(半角円、フォントによっては逆スラッシュ)をつけます。
\\\.\* |
||
\ の直後に特殊記号を書くことで、特殊記号自身を検索できます。 |
||
一致例 |
\.* |
|
不一致例 |
\a* |
\. |
また、普通は見えない文字(改行やタブ文字)も、\ 記号に続けて n や t などの文字を書くことで表現します。主要なものを書くと、以下の通りです。
\t |
タブ文字。 |
\n |
改行文字。 |
\r |
キャリッジ リターン(復帰)文字。 |
\unnnn |
Unicodeを直接指定します。nnnnのところに、Unicodeを16進数で記述します。 |
このような、特殊記号/不可視文字を入力するための記法をエスケープ(escape: 逃げ道、避難)と呼びます。
文字クラス
特定の文字ではなく、ある範囲の文字(たとえば、算用数字全部など)と一致するようなパターンを作ることができます。
エスケープ同様、\ 記号に続けて d や s などの文字を書くことで、文字クラスを表現します。また、[] (角括弧)中に複数の文字を入れることで、そのいずれかの文字に一致します。
\d+ |
||
\ 記号は特別な意味を持ちます。\d や \s など、直後の文字によって意味が変わります。\d は任意の算用数字を表します。 |
||
一致例 |
1234 |
65536 |
不一致例 |
abc |
—- |
\sx+\s |
||
\s は任意の空白文字を表します。 |
||
一致例 |
y x y |
y xxx y |
不一致例 |
yxy |
yxxxxy |
\w+\s+\w+ |
||
\w は単語に使われる文字を表します。 |
||
一致例 |
abc xyz |
あいう |
不一致例 |
abcdef |
あいうえお |
\p{Ps}\w+\p{Pe} |
||
\p{} で特定の Unicode カテゴリーに一致します。Ps は開き括弧、Pe は閉じ括弧です。 |
||
一致例 |
(abc} |
【abc] |
不一致例 |
|abc| |
.abc. |
a.*\. |
||
. (ピリオド)は任意の1文字を表します。ピリオド自信を表すためには、\. と書きます。 |
||
一致例 |
abcd. |
a(!#$%&'(). |
不一致例 |
abcd |
a |
[,\d]+ |
||
[] (各括弧)中に含まれる任意の文字に一致します。 |
||
一致例 |
19,800 |
12,34,56 |
不一致例 |
abcd |
あいうえ |
^[,\d]+$ |
||
^ は文字列の先頭、$ は末尾を意味します。 |
||
一致例 |
19,800 |
12,34,56 |
不一致例 |
-19,800 |
12,34.56 |
グループ化
パターンの一部分だけ取り出したり、置換したりするために、正規表現内にグループを作ることができます。() (丸括弧)でくくった部分がグループになります。
例えば以下のようなコードを見てみましょう。
var r = new Regex(@”(\d{4})/(\d{2})/(\d{2})”);
var m = r.Match(“2011/12/15”);
foreach (var x in m.Groups)
{
Console.WriteLine(x);
}
() が3か所あります。マッチ結果(m)のGroupsには、マッチした全体と、() でくくった3か所の結果が格納されています。したがって、実行結果は以下の通りです。
2011/12/15
2011
12
15
グループには、名前を付けておくこともできます。(?<id>パターン) というように、?<> をつけます。
var r = new Regex(@”(?<year>\d{4})/(?<month>\d{2})/(?<day>\d{2})”);
var m = r.Match(“2011/12/15”);
Console.WriteLine(m.Groups[“year”]);
Console.WriteLine(m.Groups[“month”]);
Console.WriteLine(m.Groups[“day”]);