概要
正規表現(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 の前後に別の文字があっても構いません。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
|
キャリッジ リターン(復帰)文字。 |
\u nnnn
|
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