System.Text.RegularExpressionsのクラスを使用した正規表現操作に関するTips・サンプルなど。 正規表現(System.Text.RegularExpressions)の更新版。

.NET Frameworkで使用できる正規表現

.NET Frameworkで使用できる正規表現とその使用例。

文字クラス

正規表現要素 マッチする箇所 マッチ例 備考
. \n以外の任意の一文字 .o.
(連続する任意の3文字のうち2文字目がoの箇所にマッチ
The quick brown fox jumps_over the lazy dog
(_は空白)
RegexOptions.Singlelineの場合は\nも含む
[chars] 文字クラス内の任意の一文字 [aeiou]
(a, e, i, o, uいずれかの文字にマッチ)
The quick brown fox jumps over the lazy dog
[^chars] 文字クラス内の任意の一文字以外 [^aeiou]
(a, e, i, o, u以外の文字にマッチ)
The quick brown fox jumps over the lazy dog
[first-last] 文字クラスの範囲内の一文字 [a-f]
(aからfまでの文字にマッチ)
The quick brown fox jumps over the lazy dog
[^first-last] 文字クラスの範囲外の一文字 [^a-f]
(aからf以外の文字にマッチ)
The_quick_brown_fox_jumps_over_the_lazy_dog
(_は空白)
[first1-last1first2-last2...] 文字クラスの範囲内の一文字(複数の範囲) [0-9a-fA-F]
(0から9、aからf、AからFの文字にマッチ)
0x1234cdcd
&h00FF8040
[^first1-last1first2-last2...] 文字クラスの範囲外の一文字(複数の範囲) [^0-9a-fA-F]
(0から9、aからf、AからF以外文字にマッチ)
0x1234cdcd
&h00FF8040
[base-[exclude]] 文字クラスbaseから文字クラスexludeを減算したクラス内の一文字 [a-z-[d-w]] abcdefghijklmnopqrstuvwxyz [a-z-[d-w]]
= [a-z]-[d-w]
= [a-cx-z]
[base-[exclude1-[exclude2]]] (文字クラスの減算を入れ子にしたもの) [a-z-[d-w-[m-o]]] abcdefghijklmnopqrstuvwxyz [a-z-[d-w-[m-o]]]
= [a-z]-[d-w-[m-o]]
= [a-z]-[d-w]+[m-o]
= [a-cx-z]+[m-o]
= [a-cx-zm-o]
\w 単語に使用されるUnicode文字 \w abc+-*/あいう漢字+−×÷ RegexOptions.ECMAScriptの場合は[a-zA-Z0-9_]と等価
\W \w以外の文字 \W abc+-*/あいう漢字+−×÷ RegexOptions.ECMAScriptの場合は[^a-zA-Z0-9_]と等価
\d 10進数字に使用されるUnicode文字 \d abc123あいう123一二三 RegexOptions.ECMAScriptの場合は[0-9]と等価
\D \d以外の文字 \D abc123あいう123一二三 RegexOptions.ECMAScriptの場合は[^0-9]と等価
\s 空白を表すUnicode文字 \s "a_b\tc\n" (_は空白) RegexOptions.ECMAScriptの場合は[ \f\n\r\t\v]と等価
\S \s以外の文字 \S "a b\tc\n" RegexOptions.ECMAScriptの場合は[^ \f\n\r\t\v]と等価
\p{name} nameで指定されたカテゴリまたは名前付きブロック内のUnicode文字 \p{IsCJKUnifiedIdeographs}
(名前付きブロックIsCJKUnifiedIdeographs(CJK統合漢字、U+4E00-9FFF)に一致する文字にマッチ)
あいうアイウ漢字〆々 サポートされるカテゴリ・ブロック名の一覧はMSDNの文字クラス参照
\P{name} \p{name}以外の文字 \P{IsKatakana}
(名前付きブロックIsKatakana(片仮名、U+30A0-30FF)以外の文字にマッチ)
あいうアイウ漢字〆々 サポートされるカテゴリ・ブロック名の一覧はMSDNの文字クラス参照

文字のエスケープ

エスケープ文字 備考
\uxxxx 4桁の16進数xxxxで表されるUnicode文字 " " = "\u0020" = "\x20" = "\040"
\xxx 2桁の16進数xxで表されるASCII文字 " " = "\u0020" = "\x20" = "\040"
\0ooo 3桁までの8進数oooで表されるASCII文字 " " = "\u0020" = "\x20" = "\040"
※\numberの表現は前方参照でも用いられる点に注意
\cC Ctrl+Cで表されるASCII制御文字 "\cJ" = "\n" = "\u000a"
\char charのエスケープ表現 正規表現要素に使われる文字(*や[など)を通常の文字としてエスケープする場合に用いる
\a BEL, ベル = "\u0007"
\b BS, バックスペース = "\u0008"
文字クラスとして使用された場合のみバックスペースとして解釈される
それ以外の場合は単語の境界を表すアトミックゼロ幅アサーションとして解釈される
\t HT, 水平タブ = "\u0009"
\n LF, ラインフィード = "\u000a"
\v VT, 垂直タブ = "\u000b"
\f FF, フォームフィード = "\u000c"
\r CR, キャリッジリターン = "\u000d"
\e ESC, エスケープ = "\u001b"

量指定子

量指定子は文字クラスまたはグループの連続する数を指定する。

正規表現要素 マッチする箇所 マッチ例
* 0個以上連続する箇所 a*x
(連続する0個以上のaの後にxがある箇所にマッチ)
 xaxaaxaaaxaaaaxaaaaax
+ 1個以上連続する箇所 a+x
(連続する1個以上のaの後にxがある箇所にマッチ)
 xaxaaxaaaxaaaaxaaaaax
? 0個または1個連続する箇所 a?x
(aの後にxある箇所、またはxのある箇所にマッチ)
 xaxaaxaaaxaaaaxaaaaax
{n} n個連続する箇所 a{3}x
(連続する3個のaの後にxがある箇所にマッチ)
 xaxaaxaaaxaaaaxaaaaax
{n,} n個以上連続する箇所 a{3,}x
(連続する3個以上のaの後にxがある箇所にマッチ)
 xaxaaxaaaxaaaaxaaaaax
{n,m} n個以上m個以下連続する箇所 a{1,3}x
(連続する1から3個のaの後にxがある箇所にマッチ)
 xaxaaxaaaxaaaaxaaaaax

※一部処理系でサポートされる{,n}の形式は.NET Frameworkの正規表現では使用できない。

最短一致の量指定子

量指定子の後に?を付けると最短一致の量指定子となる(付けない場合は最長一致となる)。

正規表現要素 マッチする数 最初にマッチする箇所
*? 0個以上連続する箇所の中で最短の箇所 a*
a*?
aaaaabbbbb (1文字目からの5文字にマッチ)
aaaaabbbbb (1文字目からの0文字にマッチ)
+? 1個以上連続する箇所の中で最短の箇所 a+
a+?
aaaaabbbbb
aaaaabbbbb
?? 0個または1個連続する箇所の中で最短の箇所 ab?
ab??
abcdefghij
abcdefghij
{n}? n個連続する箇所
({n}と同義)
{n,}? n個以上連続する箇所の中で最短の箇所 a{3,}
a{3,}?
aaaaabbbbb
aaaaabbbbb
{n,m}? n個以上m個以下連続する箇所の中で最短の箇所 a{2,4}
a{2,4}?
aaaaabbbbb
aaaaabbbbb

アトミックゼロ幅アサーション

アトミックゼロ幅アサーションは文字列の先頭・末尾や境界などの条件(=アサーション)を表す。 他の正規表現要素が長さを持つのに対して、アトミックゼロ幅アサーションは境界などを表すため長さを持たない(=ゼロ幅)。

正規表現要素 マッチする箇所 マッチ例 備考
^ 文字列の先頭 ^http
(httpで始まる箇所にマッチ)
http://
https://
ftp:// (マッチしない)
RegexOptions.Multilineの場合は文字列の先頭に加え行頭も表す
$ 文字列の末尾 \.html$
(.htmlで終わる箇所にマッチ)
index.html
index.xhtml (マッチしない)
index.html.org (マッチしない)
RegexOptions.Multilineの場合は文字列の末尾に加え行末も表す
\A 文字列の先頭 (別表参照) ^とは異なりRegexOptions.Multilineでも意味は変わらない
\z 文字列の末尾 (別表参照) $とは異なりRegexOptions.Multilineでも意味は変わらない
\Z 文字列の末尾または文字列の末尾の\nの前 (別表参照) $とは異なりRegexOptions.Multilineでも意味は変わらない
\G 前回の一致が終了した位置
(未整理 アトミック ゼロ幅アサーション)
\b 単語の境界(\wと\Wの境界)
(未整理 アトミック ゼロ幅アサーション)
文字クラス[\b]はバックスペースを表す
置換バターン\bは常にバックスペースを表す
\B \b以外
(未整理 アトミック ゼロ幅アサーション)

^と\Aの比較。

正規表現 RegexOptions マッチする箇所
^line None "line1\nline2\nline3"
^line Multiline "line1\nline2\nline3"
\Aline None "line1\nline2\nline3"
\Aline Multiline "line1\nline2\nline3"

$と\z, \Zの比較。

正規表現 RegexOptions マッチする箇所
line$ None "1st line\n2nd line\n3rd line\n"
line$ Multiline "1st line\n2nd line\n3rd line\n"
line\z None "1st line\n2nd line\n3rd line\n" (マッチ箇所なし)
line\z Multiline "1st line\n2nd line\n3rd line\n" (マッチ箇所なし)
line\Z None "1st line\n2nd line\n3rd line\n"
line\Z Multiline "1st line\n2nd line\n3rd line\n"

先読み・後読み(戻り読み)

先読み/後読み(もしくは戻り読み)は正規表現に対する一種の付加的な条件を表す。

正規表現要素 動作 マッチ例
(?=subexpression)
(肯定先読み)
subexpression後続することを要求する
先行する正規表現がマッチした箇所から先読みしてsubexpression後続する場合のみマッチ
Windows(?=\s\d+)
('Windows'にマッチ、ただし空白に続けて1文字以上の数字が後続する)
Windows 2000
Windows XP (マッチしない)
Windows Vista (マッチしない)
Windows 7
(?!subexpression)
(否定先読み)
subexpression後続しないことを要求する
先行する正規表現がマッチした箇所から先読みしてsubexpression後続しない場合のみマッチ
Windows(?!\s\d+)
('Windows'にマッチ、ただし空白に続けて1文字以上の数字が後続しない)
Windows 2000 (マッチしない)
Windows XP
Windows Vista
Windows 7 (マッチしない)
(?<=subexpression)
(肯定後読み)
subexpression先行することを要求する
後続する正規表現がマッチした箇所から戻り読みしてsubexpression先行する場合のみマッチ
(?<=IE)\d+
(1文字以上の数字にマッチ、ただし'IE'が先行する)
IE7
IE8
FF2 (マッチしない)
FF3 (マッチしない)
(?<!subexpression)
(否定後読み)
subexpression先行することを要求する
後続する正規表現がマッチした箇所から戻り読みしてsubexpression先行しない場合のみマッチ
(?<!IE)\d+
(1文字以上の数字にマッチ、ただし'IE'が先行しない)
IE7 (マッチしない)
IE8 (マッチしない)
FF2
FF3

先読み/後読みでは先行/後続する正規表現にマッチした箇所からsubexpressionが評価される点に注意。 例えば"Windows"が先行しない文字列にマッチする正規表現を意図して"(?<!Windows).+"とした場合、"Windows Vista"という文字列に対しては文字列全体がマッチしてしまう。 これは".+"の部分で"Windows Vista"全体がマッチする一方、そこから戻り読みしても期待する"Windows"が出現しないため否定後読みの条件にマッチしないからである。

未整理 非バックトラッキング先読みおよび後読み

グループ

正規表現要素 グループ化される箇所 マッチ例(下付き文字はグループ番号またはグループ名) 備考
(subexpression) subexpressionにマッチする箇所 \b(\w{3})\s(\w+)\b
(3文字の単語とそれに続く単語をキャプチャ)
The 1 quick 2 brown fox1jumps2 over the1lazy2 dog RegexOptions.ExplicitCaptureの場合は(?:subexpression)と同様に扱われる(キャプチャされない)
(?:subexpression) subexpressionにマッチしてもキャプチャされない \b(?:\w{3})\s(\w+)\b
(3文字の単語に続く単語をキャプチャ)
The quick1 brown fox jumps1 over the lazy1 dog
(?<name>subexpression) subexpressionにマッチする箇所をグループ名nameとしてキャプチャする \b(?<def_art>(?:T|t)he)\s(?<word>\w+)\b
(定冠詞theをグループ名def_art、theに続く単語をグループ名wordとしてキャプチャ)
The def_art(1) quick word(2) brown fox jumps over thedef_art(1)lazyword(2) dog
(?<name1-name2>subexpression) グループ定義の均等化
(未整理 グループ化構成体)
(?>subexpression) 非バックトラッキング部分式
(未整理 グループ化構成体)

グループ番号はグループの位置順に1から始まるインデックスが与えられる。 グループ番号0のグループは正規表現にマッチした箇所全体を意味する。 またグループ名を明示したグループにもグループ番号が与えられる。 グループ名に与えられるグループ番号は、グループ名を明示しない場合と同じとなる。

入れ子になったグループの場合は、もっとも外側のグループから順にインデックスが与えられる。 例えば"(a(b(c)(d)(e(f))))"という正規表現の場合、各グループに割り当てられるインデックスは次のようになる。

<----------------0---------------->
( a ( b ( c ) ( d ) ( e ( f ) ) ) )
                        <-6->
        <-3-> <-4-> <----5---->
    <-------------2------------->
<----------------1---------------->

マッチしたグループは、前方参照では\numberまたは\k<name>、置換文字列では$numberまたは${name}で参照できる。 コード上からはMatchクラスのGroupsプロパティで参照できる。 Groupsプロパティのインデクサにはグループ番号またはグループ名を指定できる。 例えば次のコード

Regex r = new Regex(@"Windows\s(\w+)(?:\s([\w\s]+))?");

foreach (var input in new[] {
  "Windows Vista Ultimate Edition",
  "Windows XP Professional",
  "Windows 95",
  "Windows 98 Second Edition",
}) {
  Match m = r.Match(input);

  Console.WriteLine("{0} => Release: {1}, Edition: {2}", input, m.Groups[1].Value, m.Groups[2].Value);
}
 Release: {1}, Edition: {2}", input, m.Groups[1].Value, m.Groups[2].Value);
}]]>

を実行すると、

Windows Vista Ultimate Edition => Release: Vista, Edition: Ultimate Edition
Windows XP Professional => Release: XP, Edition: Professional
Windows 95 => Release: 95, Edition: 
Windows 98 Second Edition => Release: 98, Edition: Second Edition

のようになる。 上記のコードをグループ名を使用したものに書き換えると次のようになる。

Regex r = new Regex(@"Windows\s(?<release>\w+)(?:\s(?<edition>[\w\s]+))?");

foreach (var input in new[] {
  "Windows Vista Ultimate Edition",
  "Windows XP Professional",
  "Windows 95",
  "Windows 98 Second Edition",
}) {
  Match m = r.Match(input);

  Console.WriteLine("{0} => Release: {1}, Edition: {2}", input, m.Groups["release"].Value, m.Groups["edition"].Value);
}
\w+)(?:\s(?[\w\s]+))?");

foreach (var input in new[] {
  "Windows Vista Ultimate Edition",
  "Windows XP Professional",
  "Windows 95",
  "Windows 98 Second Edition",
}) {
  Match m = r.Match(input);

  Console.WriteLine("{0} => Release: {1}, Edition: {2}", input, m.Groups["release"].Value, m.Groups["edition"].Value);
}]]>

Regex.Replaceメソッドを用いた置換でグループ番号、グループ名を参照する場合は$numberもしくは${name}とする。 例えば次のコード

Regex r = new Regex(@"Windows\s(\w+)(?:\s([\w\s]+))?");

foreach (var input in new[] {
  "Windows Vista Ultimate Edition",
  "Windows XP Professional",
  "Windows 95",
  "Windows 98 Second Edition",
}) {
  Console.WriteLine("{0} => {1}", input, r.Replace(input, "Release: $1, Edition: $2"));
}
 {1}", input, r.Replace(input, "Release: $1, Edition: $2"));
}]]>

を実行すると、

Windows Vista Ultimate Edition => Release: Vista, Edition: Ultimate Edition
Windows XP Professional => Release: XP, Edition: Professional
Windows 95 => Release: 95, Edition: 
Windows 98 Second Edition => Release: 98, Edition: Second Edition

のようになる。 上記のコードをグループ名を使用したものに書き換えると次のようになる。

Regex r = new Regex(@"Windows\s(?<release>\w+)(?:\s(?<edition>[\w\s]+))?");

foreach (var input in new[] {
  "Windows Vista Ultimate Edition",
  "Windows XP Professional",
  "Windows 95",
  "Windows 98 Second Edition",
}) {
  Console.WriteLine("{0} => {1}", input, r.Replace(input, "Release: ${release}, Edition: ${edition}"));
}
\w+)(?:\s(?[\w\s]+))?");

foreach (var input in new[] {
  "Windows Vista Ultimate Edition",
  "Windows XP Professional",
  "Windows 95",
  "Windows 98 Second Edition",
}) {
  Console.WriteLine("{0} => {1}", input, r.Replace(input, "Release: ${release}, Edition: ${edition}"));
}]]>

また、グループ名を使用した場合でもグループ番号は割り当てられるので、グループ番号で参照することができる。

Regex r = new Regex(@"Windows\s(?<release>\w+)(?:\s(?<edition>[\w\s]+))?");

foreach (var input in new[] {
  "Windows Vista Ultimate Edition",
  "Windows XP Professional",
  "Windows 95",
  "Windows 98 Second Edition",
}) {
  Console.WriteLine("{0} => {1}", input, r.Replace(input, "Release: $1, Edition: $2"));
}
\w+)(?:\s(?[\w\s]+))?");

foreach (var input in new[] {
  "Windows Vista Ultimate Edition",
  "Windows XP Professional",
  "Windows 95",
  "Windows 98 Second Edition",
}) {
  Console.WriteLine("{0} => {1}", input, r.Replace(input, "Release: $1, Edition: $2"));
}]]>

選択・条件分岐

正規表現要素 マッチする箇所 マッチ例
expression1|expression2|... |で区切られた正規表現のいずれかに一致する箇所 (fox|dog|(T|t)he)
(fox, dog, The, theのいずれかにマッチ)
The quick brown fox jumps over the lazy dog
(?(expression)yes) expressionに一致する場合はyesに一致する箇所、そうでない場合はマッチしない (?(^Win)Win(dows\s)?\w+)
(Winで始まる場合は'Win'または'Windows 'に続けて1文字以上続く文字列)
Windows 7
Windows Vista
Win32
Mac OS X (マッチしない)
Debian GNU/Linux (マッチしない)
Ubuntu (マッチしない)
(?(expression)yes|no) expressionに一致する場合はyesに一致する箇所、そうでない場合はnoに一致する箇所 (?(^Win)Win(dows\s)?\w+|.*Linux.*)
(Winで始まる場合は'Win'または'Windows 'に続けて1文字以上続く文字列、そうでない場合は'Linux'を含む文字列にマッチ)
Windows 7
Windows Vista
Win32
Mac OS X (マッチしない)
Debian GNU/Linux
Ubuntu (マッチしない)
(?(name)yes|no) 名前付きキャプチャ文字列nameに一致する場合はyesに一致する箇所、そうでない場合はnoに一致する箇所
(未整理 代替構成体)

前方参照

前方参照は前方参照が現れる以前にマッチしたグループの値を表す。

正規表現要素 マッチ例
\number グループ番号numberの値 (\"|')[^\1]+\1
(同一の引用符"または'で括られた範囲にマッチ)
"'quoted' string"
'quoted "string"'
"'quoted' 'string'"
"quoted' "string'
'quoted" 'string"
\k<name> グループ名nameの値 (?<char>\w)\k<char>+
(同一の文字が連続する箇所にマッチ)
abbccaaccbabbcbabaaabbbccbccbacbbcaabbaab

未整理 前方参照

インラインオプション

インラインオプションを使用することで、Regex.Optionsプロパティを参照せず正規表現内で一時的にオプションを変更出来る。 指定出来るオプションは次の5つ(詳細はRegexOptions列挙体の説明を参照)。

i
大文字小文字の違いを無視する。 RegexOptions.IgnoreCaseと同じ。
m
複数行モード。 RegexOptions.Multilineと同じ。
n
名前または番号を明示したグループのみキャプチャする。 RegexOptions.ExplicitCaptureと同じ。
s
単一行モード。 RegexOptions.Singlelineと同じ。
x
エスケープされない空白をパターンから除外し、#以降を行末までのコメントとして扱う。 RegexOptions.IgnorePatternWhitespaceと同じ。

RegexOptions列挙体と同様に上記5つを組み合わせて指定できる。

正規表現要素 動作 マッチ例
(?imnsx:subexpression) オプションを一時的に有効にしてsubexpressionを評価する (?i:the)
(大文字小文字を区別せずtheに一致する箇所にマッチ)
The quick brown fox jumps over the lazy dog
(?-imnsx:subexpression) オプションを一時的に無効にしてsubexpressionを評価する (?i:windows)\s(?-i:Windows)
(大文字小文字を区別せずwindowsに一致する箇所に続き、大文字小文字も含めて正確にWindowsと一致する箇所にマッチ)
windows WINDOWS Windows
(?imnsx-imnsx:subexpression) 有効・無効にするオプションを一時的に指定してsubexpressionを評価する (?n-i:(T|t)he)
(nオプションを有効、iオプションを無効にして(T|t)heに一致する箇所にマッチ = (?i:(?:the))と同義)
The quick brown fox jumps over the lazy dog

コメント

正規表現要素 意味 マッチ例 備考
(?#comment) インラインコメント "(?i:the(?#大文字小文字を区別せずtheと一致する箇所))" The quick brown fox jumps over the lazy dog /*comment*/のような表現
#comment 行末までのコメント "(?i:the) #大文字小文字を区別せずtheと一致する箇所" The quick brown fox jumps over the lazy dog //commentのような表現
RegexOptions.IgnorePatternWhitespaceの場合のみコメントとして扱われる
行末までをコメントとして扱うため(?x:)で一時的に有効にすることはできない

置換

置換の正規表現要素は、Regex.Replaceメソッドでの置換を行う場合に用いる。

正規表現要素 例(正規表現) 例(置換文字列) 例(入力文字列) 例(置換後の結果)
$number グループ番号numberに一致した文字列 (\w+)
(1文字以上の単語)
<$1>
(マッチした箇所を括弧で括る)
The quick brown fox jumps over the lazy dog <The> <quick> <brown> <fox> <jumps> <over> <the> <lazy> <dog>
${name} グループ名nameに一致した文字列 (?<word>\w{5})
(5文字の単語)
<${word}>
(マッチした箇所を括弧で括る)
The quick brown fox jumps over the lazy dog The <quick> <brown> fox <jumps> over the lazy dog
$$ 単一の"$"リテラル (?<num>[\d\.]+)
(小数点を含む数字)
$$${num}
(マッチした数字の先頭に$を付ける)
100 1.25 30.5 $100 $1.25 $30.5
$& 一致した文字列全体 (\w+)\s(\w+)
(空白で区切られた2つの単語)
<$&>
(マッチした箇所を括弧で括る)
The quick brown fox jumps over the lazy dog <The quick> <brown fox> <jumps over> <the lazy> dog
$` 一致した箇所より前にある文字列全体 (third) <$`>
(thirdにマッチした箇所をそれより前にある文字列に置換)
first second third first second <first second >
$' 一致した箇所より後ろにある文字列全体 (first) <$'>
(firstにマッチした箇所をそれより後ろにある文字列に置換)
first second third < second third> second third
$+ キャプチャした最後のグループに一致した文字列
(未整理 置換)
$_ テスト対象の文字列全体 (second) <$_>
(secondにマッチした箇所を入力文字列に置換)
first second third first <first second third> third

.NET Frameworkで使用できる機能

.NET Frameworkで使用できる正規表現の機能。

正規表現のコンパイルと再利用 (未整理)

(以下は未検証のコードです。 正しく動作しないか、誤りがある可能性があります。)

正規表現のコンパイル
var name = new AssemblyName("MyRegexAssembly");
var ns = "MyRegexNamespace";
var regexes = new[] {
  new RegexCompilationInfo(@"\.html$", RegexOptions.IgnoreCase, "HtmlFileRegex", ns, true),
  new RegexCompilationInfo(@"\.xhtml$", RegexOptions.IgnoreCase, "XhtmlFileRegex", ns, true),
  new RegexCompilationInfo(@"\.txt$", RegexOptions.IgnoreCase, "PlainTextFileRegex", ns, true),
};

name.CodeBase = name.Name + ".dll";

Regex.CompileToAssembly(regexes, name);
コンパイル済み正規表現の再利用
var htmlFileRegexHandle = Activator.CreateInstanceFrom("MyRegexAssembly.dll", "MyRegexNamespace.HtmlFileRegex");
var htmlFileRegex = (Regex)htmlFileRegexHandle.Unwrap();

htmlFileRegex.IsMatch("index.html");

正規表現とスレッド (未整理)

Regexクラス

Regexクラスは正規表現のインスタンスを表し、入力文字列に対するマッチ箇所の検索・置換・分割を行うメソッドを持つ。 クラスメソッドを用いる場合はインスタンスを作成することなく検索・置換・分割を行うことが出来る。

主なコンストラクタ

Regex(string)
文字列で表された正規表現のインスタンスを作成する。
Regex(string, RegexOptions)
正規表現エンジンの動作を指定するRegexOptionsを指定し、文字列で表された正規表現のインスタンスを作成する。

主なメソッド

bool IsMatch(string)
入力文字列が正規表現にマッチするかどうかを表す値を返す。 正規表現にマッチする箇所があるかどうかだけ調べたい場合に用いる。
Match Match(string)
入力文字列のうち、正規表現にマッチする最初の箇所を表すMatchを返す。 正規表現にマッチする最初の箇所だけを取得したい場合などに用いる。
MatchCollection Matches(string)
入力文字列のうち、正規表現にマッチする箇所のコレクションを表すMatchCollectionを返す。 正規表現にマッチするすべての箇所を取得したい場合に用いる。
string Replace(string, string)
入力文字列のうち、正規表現にマッチする箇所を置換文字列で置換した値を返す。 正規表現にマッチする箇所を置換したい場合に用いる。
string Replace(string, MatchEvaluator)
入力文字列のうち、正規表現にマッチする箇所をMatchEvaluatorデリゲートの戻り値で置換した値を返す。 正規表現にマッチする箇所を置換文字列では表現しきれない形式に置換したい場合に用いる。
string[] Split(string)
入力文字列を、正規表現にマッチする箇所で分割した配列を返す。 正規表現で表される区切り文字列で文字列を分割したい場合に用いる。

以下はクラスメソッド。

static bool IsMatch(string, string, RegexOptions)
入力文字列、正規表現文字列とオプションを引数に取る。 動作はインスタンスメソッドのIsMatchと同じ。
static Match Match(string, string, RegexOptions)
入力文字列、正規表現文字列とオプションを引数に取る。 動作はインスタンスメソッドのMatchと同じ。
static MatchCollection Matches(string, string, RegexOptions)
入力文字列、正規表現文字列とオプションを引数に取る。 動作はインスタンスメソッドのMatchesと同じ。
static string Replace(string, string, string, RegexOptions)
入力文字列、正規表現文字列、置換文字列とオプションを引数に取る。 動作はインスタンスメソッドのReplaceと同じ。
static string Replace(string, string, MatchEvaluator, RegexOptions)
入力文字列、正規表現文字列、MatchEvaluatorデリゲートとオプションを引数に取る。 動作はインスタンスメソッドのReplaceと同じ。
static string[] Split(string, string, RegexOptions)
入力文字列、正規表現文字列とオプションを引数に取る。 動作はインスタンスメソッドのSplitと同じ。

Matchクラス、Groupクラス、Captureクラス

Matchクラス、Groupクラス、Captureクラスは正規表現にマッチした部分文字列を表す。 それぞれのクラスが表す部分文字列は次の通り。

Matchクラス
Regexクラスで表される正規表現にマッチした箇所全体を表す。
Groupクラス
Regexクラスで表される正規表現のグループにマッチした箇所を表す。
Captureクラス
Regexクラスで表される正規表現の部分式にマッチした箇所を表す。

MatchクラスはGroupクラスを包含し、GroupクラスはCaptureクラスを包含する。 包含するコレクションを表すプロパティは次の通り。

Match.Groupsプロパティ
Matchが表す部分文字列中に含まれるGroupのコレクション(GroupCollection)を表す。
Group.Capturesプロパティ
Groupが表す部分文字列中に含まれるCaptureのコレクション(CaptureCollection)を表す。

また同時にMatchクラスはGroupクラス、GroupクラスはCaptureクラスを継承する。 継承関係をツリー形式で表すと次の通り。

  • Captureクラス
    • Groupクラス
      • Matchクラス

それぞれのクラスに対応するコレクションクラスは次の通り。

  • Matchクラス - MatchCollectionクラス
  • Groupクラス - GroupCollectionクラス
  • Captureクラス - CaptureCollectionクラス

Matchクラス、Groupクラス、Captureクラスの表す部分文字列

例えば、"([A-Z])([a-z]+)"という正規表現では各クラスが表す部分文字列は次のようになる。

Matchクラス
"([A-Z])([a-z]+)"にマッチした箇所を表す部分文字列。
Groupクラス
"([A-Z])"または"([a-z]+)"にマッチした箇所を表す部分文字列。
Captureクラス
"[A-Z]"または"[a-z]+"にマッチした箇所を表す部分文字列。

上記の正規表現と入力文字列"Windows Vista"を例にとると、Matchクラスが表す箇所とインデックスは次のようになる。

W i n d o w s   V i s t a
~~~~~~~~~~~~~0
                ~~~~~~~~~1

同様にGroupクラスが表す箇所とMatchクラス内でのインデックスは次のようになる。 インデックス0のグループはマッチした箇所全体を表す点に注意。

W i n d o w s   V i s t a
~~~~~~~~~~~~~0  ~~~~~~~~~0
~1              ~1
  ~~~~~~~~~~~2    ~~~~~~~2

同様にCaptureクラスが表す箇所とGroupクラス内でのインデックスは次のようになる。

W i n d o w s   V i s t a
~0              ~0
  ~~~~~~~~~~~0    ~~~~~~~0

Matchクラスの主なメソッド

Match NextMatch()
次にマッチする箇所を表すMatchを返す。
string Result(string)
Matchクラスの値を指定した置換文字列で置換した結果を返す。

Matchクラスの主なプロパティ

GroupCollection Groups {get;}
正規表現にマッチしたグループのコレクションを表すGroupCollectionを取得する。
int Index {get;}
マッチした部分文字列の、入力文字列中のインデックスを取得する。 (Captureクラスから継承)
int Length {get;}
マッチした部分文字列の長さを取得する。 (Captureクラスから継承)
string Value {get;}
マッチした部分文字列を取得する。 (Captureクラスから継承)
bool Success {get;}
マッチした箇所があるかどうかを取得する。 (Groupクラスから継承)

RegexOptions列挙体

RegexOptions列挙体はRegexクラスの動作を指定する。 一部のオプションは正規表現文字列内で一時的に変更することが出来る。

RegexOptions列挙体のメンバ

None
なし。 オプションを指定しない。
IgnoreCase
インラインオプションi。 大文字小文字の違いを無視する。
Multiline
インラインオプションm。 複数行モードにする(^と$がそれぞれ行頭と行末にもマッチする)。
ExplicitCapture
インラインオプションn。 (subexpression)をキャプチャしない(明示的に名前または番号を指定したグループのみをキャプチャする)。
Singleline
インラインオプションs。 単一行モードにする(.が\nにもマッチする)。
IgnorePatternWhitespace
インラインオプションx。 エスケープされない空白をパターンから除外し、#以降を行末までのコメントとして扱うように変更する。
CultureInvariant
カルチャの違いを無視する。
ECMAScript
ECMAScript互換の動作にする。
RightToLeft
検索の方向を右から左にする。
Compiled
正規表現をコンパイルし、MSILコードを生成する。

Regexクラスを用いたサンプル

Regexクラスの各メソッドを用いたサンプル。

IsMatchメソッド

IsMatchメソッドを使ってファイルの拡張子が.htmlか判断する例。

var inputs = new[] {
  "readme.txt",
  "index.html",
  "index.html.org",
  "INDEX.HTML",
  "index.xhtml",
};
var html = @"\.(?i:html)$";

foreach (var input in inputs) {
  if (Regex.IsMatch(input, html))
    Console.WriteLine("    HTML file : {0}", input);
  else
    Console.WriteLine("not HTML file : {0}", input);
}
実行結果
not HTML file : readme.txt
    HTML file : index.html
not HTML file : index.html.org
    HTML file : INDEX.HTML
not HTML file : index.xhtml

Matchメソッド

Matchメソッドを使って文字列中から3文字の単語を強調表示する例。

var input = "The quick brown fox jumps over the lazy dog";
var word = @"\b\w{3}\b";

for (var m = Regex.Match(input, word); m.Success; m = m.NextMatch()) {
  Console.WriteLine("{0}<{1}>{2}", input.Substring(0, m.Index), m.Value, input.Substring(m.Index + m.Length));
}
{2}", input.Substring(0, m.Index), m.Value, input.Substring(m.Index + m.Length));
}]]>
実行結果
<The> quick brown fox jumps over the lazy dog
The quick brown <fox> jumps over the lazy dog
The quick brown fox jumps over <the> lazy dog
The quick brown fox jumps over the lazy <dog>

上記の例をMatch.Resultメソッドを用いてより簡略に書き換えた例。

var input = "The quick brown fox jumps over the lazy dog";
var word = @"\b\w{3}\b";

for (var m = Regex.Match(input, word); m.Success; m = m.NextMatch()) {
  Console.WriteLine(m.Result("$`<$0>$'"));
}
$'"));
}]]>

Regex.MatchメソッドおよびMatch.NextMatchメソッドの代わりに、Regex.Matchesメソッドを用いて書き換えると次のようになる。

var input = "The quick brown fox jumps over the lazy dog";
var word = @"\b\w{3}\b";

foreach (Match m in Regex.Matches(input, word)) {
  Console.WriteLine(m.Result("$`<$0>$'"));
}
$'"));
}]]>

Matchesメソッド

Matchesメソッドを使ってCSVの各レコードからフィールドの値を抽出する例。

var inputs = new[] {
  "column1,,column3",
  "column1,column2,column3,,",
  "\"column1\",\"column\"\"2\"\"\",column3",
};

var quoted = "\"(?<value>(\"\"|\\w)*?)\"";
var plain = "(?<value>\\w*)";
var field = string.Format("({0}|{1})", quoted, plain);
var record = string.Format("^{0}(,{0})*$", field);

foreach (var input in inputs) {
  Console.WriteLine(input);
  foreach (Match m in Regex.Matches(input, record)) {
    foreach (Capture c in m.Groups["value"].Captures) {
      Console.WriteLine("  {0}", c.Value);
    }
  }
}
(\"\"|\\w)*?)\"";
var plain = "(?\\w*)";
var field = string.Format("({0}|{1})", quoted, plain);
var record = string.Format("^{0}(,{0})*$", field);

foreach (var input in inputs) {
  Console.WriteLine(input);
  foreach (Match m in Regex.Matches(input, record)) {
    foreach (Capture c in m.Groups["value"].Captures) {
      Console.WriteLine("  {0}", c.Value);
    }
  }
}]]>
実行結果
column1,,column3
  column1
  
  column3
column1,column2,column3,,
  column1
  column2
  column3
  
  
"column1","column""2""",column3
  column1
  column""2""
  column3

Replaceメソッド

Replaceメソッドを使って単語の1文字目を大文字にする例。

var input = "The quick brown fox jumps over the lazy dog";
var word = @"(?<initial>\w)(?<trail>\w*)";

Console.WriteLine(input);
Console.WriteLine(Regex.Replace(input, word, delegate(Match m) {
  return m.Groups["initial"].Value.ToUpper() + m.Groups["trail"].Value;
}));
\w)(?\w*)";

Console.WriteLine(input);
Console.WriteLine(Regex.Replace(input, word, delegate(Match m) {
  return m.Groups["initial"].Value.ToUpper() + m.Groups["trail"].Value;
}));]]>
実行結果
The quick brown fox jumps over the lazy dog
The Quick Brown Fox Jumps Over The Lazy Dog

上記の例を、\bを使ってより簡略に書き換えた例。

var input = "The quick brown fox jumps over the lazy dog";
var initial = @"\b(?<initial>\w)";

Console.WriteLine(input);
Console.WriteLine(Regex.Replace(input, initial, delegate(Match m) {
  return m.Groups["initial"].Value.ToUpper();
}));
\w)";

Console.WriteLine(input);
Console.WriteLine(Regex.Replace(input, initial, delegate(Match m) {
  return m.Groups["initial"].Value.ToUpper();
}));]]>

\bはゼロ幅であり部分文字列中には現れないため、さらに簡略化して次のようにも書ける。

var input = "The quick brown fox jumps over the lazy dog";
var initial = @"\b\w";

Console.WriteLine(input);
Console.WriteLine(Regex.Replace(input, initial, delegate(Match m) {
  return m.Value.ToUpper();
}));

Splitメソッド

Splitメソッドを用いて、改行文字に\rと\nが混在するテキストを行毎に分割する例。 この例では\r, \n, \r\nのいずれかを改行と見なす。

var input = "line1\r\nline2\nline3\rline4\n\rline6";
var newline = @"\r\n|\r|\n";

foreach (var line in Regex.Split(input, newline)) {
  Console.WriteLine("[{0}]", line);
}
実行結果
[line1]
[line2]
[line3]
[line4]
[]
[line6]

Splitメソッドに指定される正規表現にキャプチャされるグループを含む場合は、グループの部分文字列も戻り値に含まれる。 そのため、次の例

var input = "line1\r\nline2\nline3\rline4\n\rline6";
var newline = @"(\r\n|\r|\n)";

foreach (var line in Regex.Split(input, newline)) {
  Console.WriteLine("[{0}]", line.Replace("\n", "\\n").Replace("\r", "\\r"));
}

を実行すると。

[line1]
[\r\n]
[line2]
[\n]
[line3]
[\r]
[line4]
[\n]
[]
[\r]
[line6]

となる。 グループを含む正規表現で区切り文字をキャプチャさせたくない場合は、xオプション(RegexOptions.ExplicitCapture)を指定するか、(subexpression)の代わりに(?:subexpression)を用いる。