目次

キーワード

概要

正規表現(regular expression)は、文字列のパターン マッチングに使う簡易言語です。 .NET の場合、Regex クラス(System.Text.RegularExpressions 名前空間)を使うことで、正規表現によるパターン マッチングができます。

Regex クラスが受け付ける正規表現の書き方は、Perl での書き方に準じます。 ネットで「正規表現」で検索すると、Perl や Java のものが多く見つかりますが、同じ書き方ができます。

参考:

Regex クラス

概要の通り、Regex クラスを使って文字列パターン マッチングを行います。

例えば、以下のように書くことで、ハイフンで区切られた単語を抜き出すことができます。 Match メソッド(最初の1件を得る)や、Matches メソッド(マッチした個所すべてを得る)を使います。

  • C#
  • VB
  • F#
var text = @"
C# (pronounced C sharp) is a programming language that
is designed for building a variety of applications that
run on the .NET Framework. C# is simple, powerful,
type-safe, and object-oriented. The many innovations
in C# enable rapid application development while
retaining the expressiveness and elegance of C-style
languages. ";

var withHyphen = new Regex(@"\w+-\w+", RegexOptions.Multiline);

var hyphenedWord =
    from Match m in withHyphen.Matches(text)
    select m.Value;

foreach (var item in hyphonedWords)
{
    Console.WriteLine(item);
}
Dim text = "C# (pronounced C sharp) is a programming language that" & vbCrLf &
    "is designed for building a variety of applications that" & vbCrLf &
    "run on the .NET Framework. C# is simple, powerful," & vbCrLf &
    "type-safe, and object-oriented. The many innovations" & vbCrLf &
    "in C# enable rapid application development while" & vbCrLf &
    "retaining the expressiveness and elegance of C-style" & vbCrLf &
    "languages. "

Dim withHyphen = New Regex("\w+-\w+", RegexOptions.Multiline)

Dim hyphenedWord = From m As Match In withHyphen.Matches(text).OfType(Of Match)()
                   Select m.Value

For Each item In hyphenedWord
    Console.WriteLine(item)
Next
open System
open System.Text.RegularExpressions

let text = "
C# (pronounced C sharp) is a programming language that
is designed for building a variety of applications that
run on the .NET Framework. C# is simple, powerful,
type-safe, and object-oriented. The many innovations
in C# enable rapid application development while
retaining the expressiveness and elegance of C-style
languages. "

let withHyphen = new Regex(@"\w+-\w+", RegexOptions.Multiline)

let hyphenedWord = seq {
    for m in withHyphen.Matches(text) do
        yield m.Value
        }

let e = seq {
    for x in 0..10 do
        for y in 0..10 do
            System.Threading.Thread.Sleep(100)
            yield x * y
            }

for x in hyphenedWord do Console.WriteLine x
type-safe
object-oriented
C-style

もう1つ、単語の出現頻度を数える例を示しましょう。 単語の区切りを表すのに正規表現を使います。 Split メソッドで、単語の切り出しを行います。

  • C#
  • VB
var text = @"
C# (pronounced C sharp) is a programming language that
is designed for building a variety of applications that
run on the .NET Framework. C# is simple, powerful,
type-safe, and object-oriented. The many innovations
in C# enable rapid application development while
retaining the expressiveness and elegance of C-style
languages. ";

var splitter = new Regex(@"[\s\(\)\.,\n\r]+", RegexOptions.Multiline);

var wordCount =
    from word in splitter.Split(text)
    where !string.IsNullOrEmpty(word)
    group word by word into g
    orderby g.Count()
    select new { Count = g.Count(), Word = g.Key };

foreach (var item in wordCount)
{
    Console.WriteLine(item);
}
Dim text = "C# (pronounced C sharp) is a programming language that" & vbCrLf &
    "is designed for building a variety of applications that" & vbCrLf &
    "run on the .NET Framework. C# is simple, powerful," & vbCrLf &
    "type-safe, and object-oriented. The many innovations" & vbCrLf &
    "in C# enable rapid application development while" & vbCrLf &
    "retaining the expressiveness and elegance of C-style" & vbCrLf &
    "languages. "

Dim splitter = New Regex("[\s\(\)\.,\n\r]+", RegexOptions.Multiline)

Dim wordCount = From word In splitter.Split(text)
                Where Not String.IsNullOrEmpty(word)
                Group By Word = word Into Group
                Order By Group.Count()
                Select New With {Group.Count(), Word}

For Each item In wordCount
    Console.WriteLine(item)
Next
前略
{ Count = 2, Word = of }
{ Count = 2, Word = the }
{ Count = 2, Word = and }
{ Count = 3, Word = C# }
{ Count = 3, Word = is }    

これらの例では、Regex クラスのインスタンスを作っています。 作ったインスタンスを取っておけば、文字列で与えた正規表現を、内部的な表現にコンパイルする作業を1度限りにできて、実行効率が良くなります。 一方、実行効率を気にしない、もしくは、一度きりのパターン マッチングなら、静的メソッド版も使えます。

var text = "abcde";
Console.WriteLine(Regex.Match(text, "a+"));
Console.WriteLine(Regex.Match(text, "a.*e"));
a
abcde

以下では、正規表現の中身(Regex クラスに与える文字列)の説明をしていきましょう。

正規表現の基本: 文字をそのまま書く

いくつかの特別な意味を持った記号(. {} \ * + など)以外は、一致させたい文字をそのまま書きます。例えば、abという正規表現は、abを含む文字列に一致します。

正規表現 ab
説明 abを含む文字列に一致します。abの前後に別の文字があっても構いません。abの間に別の文字が入る場合には一致しません。
一致例 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(@"(?<y>\d{4})/(?<m>\d{2})/(?<d>\d{2})");
var m = r.Match("2011/12/15");

Console.WriteLine(m.Groups["y"]); // 2011
Console.WriteLine(m.Groups["m"]); // 12
Console.WriteLine(m.Groups["d"]); // 15

更新履歴

ブログ