上のコード例では単語を表すために「1文字以上の連続」を意味する「+」記号を使用している。このように「直前に記述した正規表現が何回繰り返すか」を指定するメタ文字のことを「量指定子」と呼ぶ。C#は次のような量指定子を使える。
量指定子 | 説明 |
---|---|
* | 直前に記述した要素の0回以上の繰り返し |
+ | 直前に記述した要素の1回以上の繰り返し |
? | 直前に記述した要素が0回または1回 |
{n} | 直前に記述した要素のn回の繰り返し |
{n, m} | 直前に記述した要素のn回からm回の繰り返し |
{n,} | 直前に記述した要素のn回以上の繰り返し |
C#で使用できる量指定子(一部) |
例えば、日本の郵便番号は「\d{3}-\d{4}」のように表現できる。これは「数字(\d)が3文字({3})続いた後にハイフン(-)があり、その後に数字(\d)が4文字({4})続く」ことを意味している。
「*」と「+」の違いは直前に記述した正規表現が「0回以上出現するか」「1回以上出現するか」だ。例えば、小数の値の表現を考えてみよう。単純には「0.1」などが考えられるが、「.1」といった表記もある。小数点の前の数字を省略できるというのは、「数字の0回以上の繰り返し」に相当するので、こういう場合には「*」が利用できる。よって、これを表す正規表現は「\d*.\d+」と書ける(ここでは小数点と、小数点以下の数値が必須であるものとする)。
以下に例を示す。
string[] input = { ".1", "1.2", "3." };
string pattern = @"\d*.\d+";
foreach (var item in input)
{
Console.WriteLine(Regex.Match(item, pattern));
}
ここでは変数inputは文字列配列として、その要素をRegex.Matchメソッドに渡しているが、最初の2つはマッチするが最後の要素は「3.」となっているのでマッチしない。興味のある方はパターンを「\d+.\d+」にして試してみよう。
「{}」を使った場合には、繰り返しの回数を明示的に指定できる。以下に例を示す。
string input = "12,345,678";
string pattern = @"\d{1,3}";
string result = "";
foreach (Match m in Regex.Matches(input, pattern))
{
result += m;
}
Console.WriteLine(result);
ここでは「\d{1,3}」として繰り返しの回数が1回から3回となるように指定して、カンマ区切りの数字列から数字だけを抜き出している(もちろん、これはカンマを削除するように置換するのがよい)。
また、量指定子には「?」記号を付加することで、最小マッチ(最短マッチ、控えめマッチなどともいう)を行うように指定することも可能だ。通常は、最長マッチ(欲張りマッチ)が行われるが、「?」を付けることで正規表現の処理を変更できる。例えば、「some text(in parenthesis), and some text(in another parenthesis)」という文字列からかっこに囲まれたテキストを取り出したいとしよう。このときにすぐに思い付くのは「\(.*\)」というパターンだ(正規表現では「()」はグループ化に使用するので、ここでは「\(」のようにエスケープしている)。これを使って、マッチをしてみると次のようになる。
string input = "some text(in parenthesis), and some text(in another parenthesis)";
string pattern = @"\(.*\)";
foreach (Match m in Regex.Matches(input, pattern)) {
Console.WriteLine(m);
}
これを実行すると、次のようになる。
予想とは異なり、その結果は「(in parenthesis), and some text(in another parenthesis)」となる。
これは「.*」としている部分に最初のかっこに対応する閉じかっこも含まれて、2つ目の閉じかっこまでが一気にマッチしてしまうからだ。このようになるべく長い範囲をマッチするような動作のことを「最長マッチ」とか「欲張りマッチ」という。「?」を付加すると、マッチを最小の範囲とするように動作が変更される(最小マッチ、最短マッチ、控えめマッチなどという)。
string input = "some text(in parenthesis), and some text(in another parenthesis)";
string pattern = @"\(.*?\)";
foreach (Match m in Regex.Matches(input, pattern)) {
Console.WriteLine(m);
}
といっても変わったのはパターンを「\(.*\)」から「\(.*?\)」にしただけだ。これで、プログラムを実行すると次のようになる。
なお、上のコードではかっこまでマッチしてしまっている。かっこの中のテキストだけをちゃんと抜き出すのであれば、グループ化を行って、そのキャプチャー結果を得るのがよい。これを行っているコードは例えば次のようになる。
string input = "some text(in parenthesis), and some text(in another parenthesis)";
string pattern = @"\((.*?\))";
foreach (Match m in Regex.Matches(input, pattern)) {
foreach (Group g in m.Groups)
{
Console.WriteLine(g);
}
}
次に行頭、行末などを意味するメタ文字であるアンカーを見てみよう。
Copyright© Digital Advantage Corp. All Rights Reserved.