正規表現(regular expression)は、文字列のパターン マッチングに使う簡易言語です。 .NET の場合、Regex クラス(System.Text.RegularExpressions 名前空間)を使うことで、正規表現によるパターン マッチングができます。
Regex クラスが受け付ける正規表現の書き方は、Perl での書き方に準じます。 ネットで「正規表現」で検索すると、Perl や Java のものが多く見つかりますが、同じ書き方ができます。
参考:
概要の通り、Regex クラスを使って文字列パターン マッチングを行います。
例えば、以下のように書くことで、ハイフンで区切られた単語を抜き出すことができます。 Match メソッド(最初の1件を得る)や、Matches メソッド(マッチした個所すべてを得る)を使います。
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 メソッドで、単語の切り出しを行います。
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の前後に別の文字があっても構いません。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(@"(\d{4})/(\d{2})/(\d{2})"); var m = r.Match("2011/12/15"); foreach (var x in m.Groups) { Console.WriteLine(x); }