■ 正規表現の基本 ■
此処では、.NET Framework の正規表現に付いて基本を極く簡単に(主に正規表現パターンに付いて) 説明する。猶、.NET Framework の正規表現は Perl5 の正規表現に対応する様にデザインされて居ると 謂う事なので、Perl の正規表現を理解して居れば問題無い。 猶、「正規表現テストツール」(RegexTest.exe)を使って正規表現のテストを行う事が出来るので、役 に立てゝ欲しい。 ■ 正規表現で何が出来るか 正規表現は、文字列を検索する為に使用する。正規表現を使うと、可成り複雑な検索が可能で有る。正 規表現を利用する主なケースには以下の様な物が挙げられる。 ・文字列内に指定されたパターンと一致する部分が有るか調べる。例えば、入力された文字列が電子メ ールアドレスと仕て適当か調べる等。 ・文字列から指定されたパターンと一致する部分を検索、抽出する。例えば、文字列内に有るURL の 部分を総て抜き出す等。 ・文字列から指定されたパターンと一致する部分を探して別の文字列に置換する。例えば、文字列内に 有るURL にリンク(<a>タグ)を付けたり、HTML のタグを削除する等。 補足:此等以外にも、文字列を分割して配列にする場合にも使用出来る。此の場合は、Regex.Split メ ソッドを使用する。 ■ パターンは何の様に書けば良いか 「斯んな文字列が出て来る部分を探して」と謂う事を指定するには、其れを表現したパターンを書く必 要が有る。適切なパターンを書ける様に成る事が、正規表現を勉強する最大の目標と成るで有ろう。 パターンは、ファイルの検索等で使用される「*」や「?」等のワイルドカードを理解して居るならば、 此れと同じ様な物だと思って結構で有る。 例えば、文字列から或る郵便番号と一致する部分を探し度いとする。其の郵便番号が決まって居り、 「123-4567」で有るならば、パターンは「123-4567」の儘で良い。但し、此の様に探し度い文字列が 決まって居るならば、正規表現を使う意味が無い。 決まった郵便番号ではなく、郵便番号形式の文字列を探し度い、詰まり、「何等かの数字が 3 個続き、 ダッシュ( - )が挟まり、亦、数字が 4 個続く文字列」を探し度いと謂う事で有れば、正規表現が役に 立つ。此の様な場合、書く可きパターンは、「¥d¥d¥d-¥d¥d¥d¥d」と成る(別の書き方も出来る)。詰 まり、「¥d」は「何等かの数字 1 文字」を意味する。 此の様に正規表現のパターンでは、「¥」等の特定の文字列が特別な意味を持って居る。此の様な特別な 意味を持つ文字を「メタ文字」(メタキャラクタ)と呼ぶ。
正
正
規
規
表
表
現
現
■ 簡単な例
.NET で正規表現を扱うには、Regex クラスを使用する。以下に Regex クラスを使って文字列の検査、
抽出、置換を行う簡単な例を示す。更に詳しい例に付いては、「正規表現を使って文字列が或る形式と 一致するか調べる」、「正規表現を使って文字列を検索し抽出する」、「正規表現を使って文字列を置換す る」を参照され度い。 Visual Basic ' TextBox1 に郵便番号形式の文字列が含まれて居るか調べる If System.Text.RegularExpressions.Regex.IsMatch( _ TextBox1.Text, "¥d¥d¥d-¥d¥d¥d¥d") Then Console.WriteLine("郵便番号が含まれて居る") End If ' TextBox1 内の郵便番号形式の文字列を総て抽出する Dim mc As System.Text.RegularExpressions.MatchCollection = _ System.Text.RegularExpressions.Regex.Matches( TextBox1.Text, "¥d¥d¥d-¥d¥d¥d¥d") For Each m As System.Text.RegularExpressions.Match In mc
Console.WriteLine(m.Value) Next ' TextBox1 内の郵便番号形式の文字列の"-"を削除して、【】で囲む TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( _ TextBox1.Text, "(¥d¥d¥d)-(¥d¥d¥d¥d)", "【$1$2】") C# // TextBox1 に郵便番号形式の文字列が含まれて居るか調べる if (System.Text.RegularExpressions.Regex.IsMatch(TextBox1.Text, @"¥d¥d¥d-¥d¥d¥d¥d")) { Console.WriteLine("郵便番号が含まれて居る"); } // TextBox1 内の郵便番号形式の文字列を総て抽出する System.Text.RegularExpressions.MatchCollection mc = System.Text.RegularExpressions.Regex.Matches(TextBox1.Text, @"¥d¥d¥d-¥d¥d¥d¥d"); foreach (System.Text.RegularExpressions.Match m in mc) { Console.WriteLine(m.Value); } // TextBox1 内の郵便番号形式の文字列の"-"を削除して、【】で囲む TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( TextBox1.Text, @"(¥d¥d¥d)-(¥d¥d¥d¥d)", "【$1$2】"); ■ メタ文字一覧 以下に良く使われるメタ文字と其の意味を紹介する。詳しくは MSDN の「正規表現言語要素」を参照 され度い。
■ 或る 1 文字を表す文字(アトム) 文字 説明 使用例 .(ピリオド) 改行文字(¥n)以外の任意の一文字(但し [ ] 内では ピリオド文字) 「.」 「」内に任意の1 文字が有る箇 所にマッチ ¥s 空白文字。改行文字、タブ文字、半角/全角スペース 文字等。[¥f¥n¥r¥t¥v¥x85¥p{Z}]と同じ (因みに ¥S は ¥s 以外の文字を表す) Visual¥sBasic Visual と Basic の間に空白文 字が1 文字有る箇所にマッチ ¥d 0 から 9 までの数字。全角を含む。¥p{Nd}と同じ (因みに ¥D は ¥d 以外の文字を表す) VB¥d VB の後に数字が 1 文字有る箇 所にマッチ ¥w 単語に使用される文字。アルファベット、数字、ア ン ダ ー バ ー(_) 、 ひ ら が な 、 カ タ カ ナ 、 漢 字 等 [¥p{Ll}¥p{Lu}¥p{Lt}¥p{Lo}¥p{Nd}¥p{Pc}¥p{Lm}] と同じ(因みに ¥W は ¥w 以外の文字を表す。) 「¥w」 「」内に単語に使用される文字 が1 文字が有る箇所にマッチ ¥r キャリッジリターン(¥u000D と同じ) ¥r¥n Windows の改行文字(CRLF) にマッチ ¥n ラインフィールド(改行文字、¥u000A と同じ) ¥r¥n Windows の改行文字(CRLF) にマッチ ¥t タブ(¥u0009 と同じ) ¥n¥t 改行文字(¥n)の後にタブが続 く箇所にマッチ ¥¥ 文字の前に ¥ を付けると、其の文字。メタ文字の 機能を無効にする時に使う。(或る文字列内のメタ 文 字 を 総 て ¥ で エ ス ケ ー プ す る に は 、 Regex.Escape メソッドを使うと良い) DOBON¥.NET DOBON.NET にマッチ [ ] [ ]内のどれか 1 文字([abc]ならば、a か b か c) VB[2456] VB の後に 2 か 4 か 5 か 6 が続 く箇所にマッチ [^ ] [^]内の文字以外の 1 文字([^abc]ならば、a か b か c 以外の文字) 「[^「」]」 「」内に「」以外の1 文字が有 る箇所にマッチ [ - ] 連続した文字範囲の[a-zA-Z]ならばアルファベット 1 文字)1 文字([0-9]ならば数字 1 文字、 VB[24-6] VB の後に 2 か 4 か 5 か 6 が 続く箇所にマッチ
¥u0000 4 桁の 16 進数で表される Unicode 文字 [¥uFF61-¥uFF9F]
半角カナ文字の1 文字にマッチ ¥x00 2 桁の 16 進数で表される ASCII 文字 [¥x20-¥x7F] 半 角 英 数 記 号 文 字 (0x20 ~ 0x7F)の 1 文字にマッチ ■ 文字列内の位置を表す文字(アトミックゼロ幅アサーション、アンカー、位置指定子) 此処で紹介するメタ文字は、文字列内の位置を表現した物で有る。文字とマッチする訳では無い。
文字 説明 使用例 ^ 文字列の先頭 ^¥d 先頭に有る数字1 文字にマッチ $ 文字列の末尾(但し、文字列の末尾が ¥n の時は、 其の前と一致。末尾が ¥n でも末尾で一致させるに は、¥z を使う) ¥d$ 末尾に有る数字1 文字にマッチ ¥b 単語の境界(¥w と ¥W の間)と一致(但し [ ] 内 ではバックスペース文字。因みに ¥B は ¥b 以外 の境界を表す) ¥bVB¥b VB が単語と仕て現れる箇所に マッチ ■ 文字の繰り返しを表す文字(量指定子) 此処で紹介する量指定子は、文字(又は、グループ)の繰り返しを表現する物で有る。最長マッチと最 短マッチの違いは非常に重要だが、此れに付いては後述する。 文字 説明 使用例 * 直前の文字が0 回以上繰り返す <[^>]*> <>で囲まれた箇所にマッチ + 直前の文字が1 回以上繰り返す <[^>]+> <>内に 1 文字以上有る箇所にマ ッチ ? 直前の文字が0 回、又は、1 回繰り返す -?¥d+ マイナスが付いた数字、或るい は付かない数字にマッチ {n,m} 直前の文字がn 回以上 m 回以下繰り返す ¥d{2,6} 数字が2 文字以上 6 文字以下続 いて居る箇所にマッチ {n} 直前の文字がn 回繰り返す ¥d{6} 数字が6 文字続いて居る箇所に マッチ {n,} 直前の文字がn 回以上繰り返す ¥d{8,} 数字が8 文字以上続いて居る箇 所にマッチ *? 最短マッチで、0 回以上の繰り返し(? は *、+、?、 { } の後に付けて最短マッチを表す事が出来る。最 短マッチと最長マッチに付いては、後述) <.*?> <>で囲まれた箇所にマッチ ■ 選択、グループ化等を表す文字 此処で紹介するグループ化を使用する主なケースと仕ては、論理和に依る選択を行う場合や、前方参照 (後述)やMatch.Groups プロパティでの抽出を行い度い場合等が挙げられる。 .NET Framework にはグループに名前(或るいは番号)を付ける事が出来ると謂う特徴が有る。グルー プに名前を付けても付けなくても、グループには1 から連番で番号が付けられる(番号 0 はパターン全 体で有る)。 此処では先読み、後読みアサーションも紹介して居るが、此等は少し高度で有る。従って、初心者は、 此等を無視しても良いが、知って置くと可成り役に立つ。
因みに、後読みアサーションのパターンとマッチする文字列は固定長でなければ成らないとするエンジ ンが多いが、.NET Framework では此の様な制限が無い。 文字 説明 使用例 | | で区切られた文字列の孰れか(論理和) リンゴ|りんご|林檎 リンゴ 又は りんご 又は 林檎 にマッチ ( ) グループ化する箇所 山田(太郎|花子) 山田太郎 又は 山田花子 にマ ッチ (?<name> ) グループに名前(或るいは番号)を付ける(因みに、< > の代わりに ' で括る事も出来る) VB(?<ver>¥d) VB の後に数字が有る箇所にマ ッチし、数字を"ver"と謂うグル ープ名でキャプチャ (?: ) キャプチャしないグループ 山田(?:太郎|花子) 山田太郎 又は 山田花子 にマ ッチするが、太郎 又は 花子 を キャプチャしない (?= ) 直後に此のパターンが現れる事を確認する(ゼロ幅の肯定的先読みアサーション) ¥d+(?=%) 後ろに % が続く数字の連続に マッチ。但し、% はマッチした 箇所に含まれないし、グループ と仕てキャプチャもされない。 (?! ) 直後に此のパターンが現れない事を確認する(ゼロ 幅の否定的先読みアサーション) ¥d+(?!%) 後ろに % が来ない数字の連続 にマッチ。 (?<= ) 直前に此のパターンが現れる事を確認する(ゼロ幅 の肯定的後読みアサーション) (?<=¥¥)¥d+ ¥ に続く数字の連続にマッチ。 但し、¥ はマッチした箇所に含 まれないし、グループと仕てキ ャプチャもされない。 (?<! ) 直前に此のパターンが現れない事を確認する(ゼロ 幅の否定的後読みアサーション)。 (?<!¥¥)¥d+ 前に ¥ がない数字の連続にマ ッチ。 ■ 前方参照(後方参照)を表す文字 グループ化してキャプチャした文字列を後から参照する事が出来る。此れが前方参照(後方参照)で有 る。此れに依り、キャプチャした文字列をパターンに埋め込む様な事が出来る。 文字 説明 使用例 ¥number 番号がnumber のグループと一致した文字列 <(H¥d)>.*?</¥1> <H>タグで囲まれた箇所にマッ チ ¥k<name> 名前が< > の代わりに ' で括る事も出来る) name のグループと一致した文字列(因みに、 <(?<tag>H¥d)>.*?</¥k<tag>> <H>タグで囲まれた箇所にマッ チ
■ 置換パターンで使用出来る特殊文字 前方参照(後方参照)と同じ様に置換パターン内で以下の様な特殊文字を使用する事が出来る。 前方参照と似て居る為、使用例は省略する。使用例は、「正規表現を使って文字列を置換する」を参照 され度い。 文字 説明 $number 番号が number のグループと一致した文字列 ${name} 名前が name のグループと一致した文字列 $& パターン全体と一致した文字列 ■ 良く使われるオプション オプションを指定する事も出来る。オプションを指定するとメタ文字の意味が多少変わる物も有 る。.NET ではオプションを指定するのに RegexOptions 列挙体を使用する(インラインで使用する方 法も有るが、此処では紹介しない)。以下に良く使われる重要なオプションを示す。 RegexOptions 列挙体のメンバ 説明 IgnoreCase 大文字と小文字を区別しない。 Singleline .(ピリオド)の意味を変更し、¥n を含めた総ての文字と一致する様にする。 Multiline ^ と $ の意味を変更し、文字列全体の先頭と末尾丈でなく、行の先頭と末尾にも 一致する様にする。具体的には、^ は ¥n の後、$ は ¥n の前(改行文字が ¥r¥n で有ったと仕ても)にも一致する様に成る。^ と $ の代わりに ¥A と ¥Z を使 用すると、Multiline の影響を受けずに文字列全体の先頭と末尾に一致させる事が 出来る。 ECMAScript ECMAScript 準拠の動作とする。此の事で、一部のメタ文字の意味が変更される。 例えば、 ¥w は [a-zA-Z_0-9] と同じに、 ¥s は [^ ¥f¥n¥r¥t¥v] と同じに、 ¥d は [0-9] と同じに成る。 CultureInvariant 言語の違いを無視する。 Compiled 正規表現をコンパイルして実行速度を上げる(但し、起動時間は長く成る)。 ■ 最長マッチと最短マッチ 最長マッチと最短マッチの違いは非常に重要なので、此処で説明して置く。 例えば、鈎括弧(「」)で囲まれた文字列を抽出する為に次の様なパターン(コード)を書いたとする。 Visual Basic Dim mc As System.Text.RegularExpressions.MatchCollection = _ System.Text.RegularExpressions.Regex.Matches( TextBox1.Text, "「.*」") C# System.Text.RegularExpressions.MatchCollection mc = System.Text.RegularExpressions.Regex.Matches(TextBox1.Text, @"「.*」");
此の様なパターンでは、鈎括弧が複数有った場合、問題が起こる。例えば、TextBox1 に"・・・「あ」、 「い」、「う」・・・" と入力されて居るならば、マッチする文字列は、"「あ」、「い」、「う」"の 1 つ丈で 有る。"「あ」"、"「い」"、"「う」" の 3 か所にマッチする様にするには、パターンを "「.*?」" と書 き換える。詰まり、"*" の後ろに "?" を付けて、最短マッチにする。"?" を付けないと最長マッチに成 るので、一致する箇所が最も長く成る様な方法で検索が行われる。 因みに上記の様な例で有れば、最短マッチにしなくても、"「[^」]*」" と書けば、粗同じ事が出来る。 ■ 参考 .NET Framework の正規表現 正規表現言語要素
■ 正規表現を使って文字列が或る形式と一致するか調べる ■
指定された正規表現のパターンと一致する対象が入力文字列内で見付かるか何うかを調べるには、 Regex クラスの IsMatch メソッドを使用する。此処では IsMatch メソッドを使った例を幾つか紹介す る。猶、正規表現のパターンと一致する個所を探し、見付かれば、其の箇所を抽出する方法は、「正規 表現を使って文字列を検索し、抽出する」で紹介して居る。 ■ 郵便番号か調べる 次の例では、TextBox1 に入力された文字列が郵便番号形式か(「"数字 3 文字"-"数字 4 文字"」形式に成 って居るか)調べて居る。RegexOptions.ECMAScript を指定して居るのは、¥d が半角の数字丈にマ ッチする様にする為で有る。 Visual Basic ' 郵便番号形式か調べる ' パターンは "¥d{3}-¥d{4}" とも書ける If System.Text.RegularExpressions.Regex.IsMatch( _ TextBox1.Text, "^¥d¥d¥d-¥d¥d¥d¥d$", _ System.Text.RegularExpressions.RegexOptions.ECMAScript) Then Console.WriteLine("郵便番号です") End If C# // 郵便番号形式か調べる // パターンは "¥d{3}-¥d{4}" とも書ける if (System.Text.RegularExpressions.Regex.IsMatch( TextBox1.Text, @"^¥d¥d¥d-¥d¥d¥d¥d$", System.Text.RegularExpressions.RegexOptions.ECMAScript)) { Console.WriteLine("郵便番号です"); } ■ 半角カナ文字が含まれて居るか調べる
次の例ではTextBox1 に入力された文字列内に半角カナ文字(Halfwidth CJK punctuation と Halfwidth Katakana variants)が有るか調べて居る。上記の例では静的メソッドの IsMatch を使用したが、此処 ではインスタンスメソッドを使用して居る。
Visual Basic
' 正規表現パターンを指定して Regex オブジェクトを作成
Dim r As New System.Text.RegularExpressions.Regex("[¥uFF61-¥uFF9F]")
' 半角カナ文字が含まれて居るか調べる If r.IsMatch(TextBox1.Text) Then
Console.WriteLine("半角カナ文字が含まれて居る") End If
C#
// 正規表現パターンを指定して Regex オブジェクトを作成 System.Text.RegularExpressions.Regex r =
new System.Text.RegularExpressions.Regex( @"[¥uFF61-¥uFF9F]");
// 半角カナ文字が含まれて居るか調べる if (r.IsMatch(TextBox1.Text)) { Console.WriteLine("半角カナ文字が含まれて居る"); } ■ メールアドレスか調べる 次の例ではTextBox1 に入力された文字列がメールアドレス形式か調べて居る。猶、MSDN の「方法: 文字列が有効な電子メール形式で有るか何うかを検証する」では別のパターンが紹介されて居る。 Visual Basic ' メールアドレス形式か調べる If System.Text.RegularExpressions.Regex.IsMatch( _ TextBox1.Text, "^[A-Z0-9._%+-]+@[A-Z0-9.-]+¥.[A-Z]{2,4}$", _ System.Text.RegularExpressions.RegexOptions.IgnoreCase) Then Console.WriteLine("メールアドレスの様です") End If C# // メールアドレス形式か調べる if (System.Text.RegularExpressions.Regex.IsMatch( TextBox1.Text, @"^[A-Z0-9._%+-]+@[A-Z0-9.-]+¥.[A-Z]{2,4}$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)) { Console.WriteLine("メールアドレスの様です"); } ■ URL か調べる 次の例ではTextBox1 に入力された文字列が URL(HTTP)形式か調べて居る。猶、此の正規表現パタ ーンは、「Perl メモ」で紹介されて居る物で有る。 Visual Basic ' URL 形式か調べる If System.Text.RegularExpressions.Regex.IsMatch( _
TextBox1.Text, "^s?https?://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+$") Then Console.WriteLine("URL の様です") End If C# // URL 形式か調べる if (System.Text.RegularExpressions.Regex.IsMatch( TextBox1.Text, @"^s?https?://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+$")) { Console.WriteLine("URL の様です"); }
■ 電話番号か調べる 次の例ではTextBox1 に入力された文字列が(日本国内の)電話番号形式かを大雑把に調べて居る。 Visual Basic ' 電話番号形式か調べる If System.Text.RegularExpressions.Regex.IsMatch( _ TextBox1.Text, "^0¥d{1,4}-¥d{1,4}-¥d{4}$") Then Console.WriteLine("電話番号の様です") End If C# // 電話番号形式か調べる if (System.Text.RegularExpressions.Regex.IsMatch( TextBox1.Text, @"^0¥d{1,4}-¥d{1,4}-¥d{4}$")) { Console.WriteLine("電話番号の様です"); }
■ 正規表現を使って文字列を検索し抽出する ■ 正規表現を使用して文字列の検索し、検索された文字列を取得するには、Regex クラスと Match メソ ッド(又はMatchs メソッド)を使用する。一致した要素は Match オブジェクトと仕て返される。 ■ メールアドレスを抽出する 次の例ではTextBox1 に入力された文字列からメールアドレス形式の文字列を総て検索し、表示する。 Visual Basic ' Regex オブジェクトを作成
Dim r As New System.Text.RegularExpressions.Regex( _ "¥b[A-Z0-9._%+-]+@[A-Z0-9.-]+¥.[A-Z]{2,4}¥b", _
System.Text.RegularExpressions.RegexOptions.IgnoreCase)
' TextBox1.Text 内で正規表現と一致する対象を 1 つ検索
Dim m As System.Text.RegularExpressions.Match = r.Match(TextBox1.Text)
' 次の様に一致する対象を総て検索する事も出来る
' Dim mc As System.Text.RegularExpressions.MatchCollection = r.Matches(TextBox1.Text)
While m.Success ' 一致した対象が見付かった時キャプチャした部分文字列を表示 Console.WriteLine(m.Value) ' 次に一致する対象を検索 m = m.NextMatch() End While C# // Regex オブジェクトを作成 System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex( @"¥b[A-Z0-9._%+-]+@[A-Z0-9.-]+¥.[A-Z]{2,4}¥b", System.Text.RegularExpressions.RegexOptions.IgnoreCase); // TextBox1.Text 内で正規表現と一致する対象を 1 つ検索 System.Text.RegularExpressions.Match m = r.Match(TextBox1.Text); // 次の様に一致する対象を総て検索する事も出来る // System.Text.RegularExpressions.MatchCollection mc = r.Matches(TextBox1.Text); while (m.Success) { // 一致した対象が見付かった時キャプチャした部分文字列を表示 Console.WriteLine(m.Value); // 次に一致する対象を検索 m = m.NextMatch(); }
■ HTML 内の<H>タグを抽出する 次にグループ化の例を示す。正規表現でグループ化を指定するには、「(?<(数字又は名前)>)」の様に する。正規表現に一致したグループは Match クラスの Groups プロパティで取得出来る。猶、MSDN には、「HREFS のスキャン」と謂う例や、「URL 情報の抽出」と謂う例が紹介されて居る。 以下にTextBox1 に入力された文字列を検索して、HTML の H タグ(H1、H2、H3、...)と其の部分 のテキストを抽出する例を示す。先程の例ではMatch メソッドを使用したが、今回は Matches メソッ ドを使用して観る。勿論、先程と同じ様にMatch メソッドを使用しても構わない。 Visual Basic ' 正規表現パターンとオプションを指定して Regex オブジェクトを作成 Dim r As New System.Text.RegularExpressions.Regex( _
"<(h[1-6])¥b[^>]*>(.*?)</¥1>", _
System.Text.RegularExpressions.RegexOptions.IgnoreCase Or _ System.Text.RegularExpressions.RegexOptions.Singleline)
' TextBox1.Text 内で正規表現と一致する対象を総て検索
Dim mc As System.Text.RegularExpressions.MatchCollection = r.Matches(TextBox1.Text)
For Each m As System.Text.RegularExpressions.Match In mc ' 正規表現に一致したグループの文字列を表示 Console.WriteLine("タグ:" + m.Groups(1).Value + vbCrLf + _ "タグ内の文字列:" + m.Groups(2).Value) Next C# // 正規表現パターンとオプションを指定して Regex オブジェクトを作成 System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex( @"<(h[1-6])¥b[^>]*>(.*?)</¥1>", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline); // TextBox1.Text 内で正規表現と一致する対象を総て検索 System.Text.RegularExpressions.MatchCollection mc = r.Matches(TextBox1.Text); foreach (System.Text.RegularExpressions.Match m in mc) { // 正規表現に一致したグループと位置を表示 Console.WriteLine("タグ:" + m.Groups[1].Value + "¥n タグ内の文字列:" + m.Groups[2].Value + "¥n タグの位置:" + m.Groups[1].Index); } ■ HTML 内のリンクを抽出する
のURL とリンクされて居る文字列を総て調べ、結果を出力する物で有る。今迄の例ではインスタンス メソッドのMatches(或るいは Match)を使用して居たが、今回は静的メソッドを使用して観る。 Visual Basic ' TextBox1.Text 内で正規表現と一致する対象を総て検索 Dim mc As System.Text.RegularExpressions.MatchCollection = _ System.Text.RegularExpressions.Regex.Matches( _ TextBox1.Text, _ "<a¥s+[^>]*href¥s*=¥s*(?:(?<quot>[""'])(?<url>.*?)¥k<quot>|" + _ "(?<url>[^¥s>]+))[^>]*>(?<text>.*?)</a>", _ System.Text.RegularExpressions.RegexOptions.IgnoreCase Or _ System.Text.RegularExpressions.RegexOptions.Singleline)
For Each m As System.Text.RegularExpressions.Match In mc ' 正規表現に一致したグループを表示 Console.WriteLine("URL:{0}", m.Groups("url").Value) Console.WriteLine("テキスト:{0}", m.Groups("text").Value) Next C# // TextBox1.Text 内で正規表現と一致する対象を総て検索 System.Text.RegularExpressions.MatchCollection mc = System.Text.RegularExpressions.Regex.Matches( TextBox1.Text, @"<a¥s+[^>]*href¥s*=¥s*(?:(?<quot>[""'])(?<url>.*?)¥k<quot>|" + @"(?<url>[^¥s>]+))[^>]*>(?<text>.*?)</a>", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline); foreach (System.Text.RegularExpressions.Match m in mc) { // 正規表現に一致したグループを表示 Console.WriteLine("URL:{0}", m.Groups["url"].Value); Console.WriteLine("テキスト:{0}", m.Groups["text"].Value); } ■ 同じ番号(名前)のグループが複数有る時 同じ番号のグループに複数の箇所が一致する場合が有る。例えば、「(¥d)+」と謂うパターンで「123」 を検索すると、グループ1 に「1」、「2」、「3」の 3 つの文字が一致する。亦、.NET Framework ではグ ループに名前や番号を付ける事が出来るので、同じ名前や番号のグループを複数作る事も出来る。此の 様に同じ名前や番号のグループが複数有った場合、何う成るかに付いて簡単に説明する。 此の様な場合、グループの値と仕ては最後に一致したグループの値が入る。併し、キャプチャされた総 ての値は、グループのCaptures コレクションに格納されて居る。 具体的に何う成るか、例を示す。以下の例では、パターンを「(¥d)+」とし、「123」と謂う文字列を検 索して居る。
Visual Basic
Dim r As New System.Text.RegularExpressions.Regex("(¥d)+")
Dim mc As System.Text.RegularExpressions.MatchCollection = r.Matches("123")
For Each m As System.Text.RegularExpressions.Match In mc For i As Integer = 0 To m.Groups.Count - 1
Console.WriteLine("グループ{0}:{1}", i, m.Groups(i)) For l As Integer = 0 To m.Groups(i).Captures.Count - 1
Console.WriteLine(" キャプチャ{0}:{1}", l, m.Groups(i).Captures(l).Value) Next Next Next C# System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(@"(¥d)+"); System.Text.RegularExpressions.MatchCollection mc = r.Matches("123"); foreach (System.Text.RegularExpressions.Match m in mc) {
for (int i = 0; i < m.Groups.Count; i++) {
Console.WriteLine("グループ{0}:{1}", i, m.Groups[i]); for (int l = 0; l < m.Groups[i].Captures.Count; l++) { Console.WriteLine(" キャプチャ{0}:{1}", l, m.Groups[i].Captures[l].Value); } } } 此のプログラムを実行すると、以下の様に表示される。 グループ0:123 キャプチャ 0:123 グループ1:3 キャプチャ 0:1 キャプチャ 1:2 キャプチャ 2:3 此の結果の様に、グループ1 には最後にキャプチャされた「3」が入るが、グループ 1 の Captures に はキャプチャされた総ての結果が入って居る。
■ 正規表現を使って文字列を置換する ■
正規表現を使って文字列の置換を行うには、Regex クラスの Replace メソッドを使用する。此処では幾 つかの具体例を紹介する。MSDN にも「日付形式の変更」と謂う例が載って居るので、其方も参考に され度い。
■ URL にリンクを付ける
次の例ではTextBox1 に入力された文字列内の URL に自動的にリンク(<a>タグ)を付けて、TextBox1 に結果を表示して居る。猶、此の正規表現パターンは、「Perl メモ」で紹介されて居る物で有る。 Visual Basic ' URL にリンクを付ける TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( _ TextBox1.Text, _ "s?https?://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+", _ "<a href=""$&"">$&</a>") C# // URL にリンクを付ける TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( TextBox1.Text, @"s?https?://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+", "<a href=¥"$&¥">$&</a>"); ■ 行末の空白文字を削除する 次の例ではTextBox1 に入力された文字列から総ての行末の空白文字(半角スペース、全角スペース、 タブ)を削除して居る。先程の例では静的メソッドのReplace を使用したが、此処ではインスタンスメ ソッドを使用して観る。 Visual Basic ' パターンを指定して Regex オブジェクトを作成
Dim r As New System.Text.RegularExpressions.Regex("[ ¥t]+(?=¥r?¥n|$)")
' 行末の空白文字を削除 TextBox1.Text = r.Replace(TextBox1.Text, "") C# // パターンを指定して Regex オブジェクトを作成 System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(@"[ ¥t]+(?=¥r?¥n|$)"); // 行末の空白文字を削除 TextBox1.Text = r.Replace(TextBox1.Text, ""); 因みに、パターンを "[ ¥t]+$" と仕て、RegexOptions.Multiline オプションを付けたと仕ても、改 行文字が "¥r¥n" ならば、行末の空白文字を削除する事は出来ない。何故ならば、$ は ¥n の前、 ¥r の後ろとマッチする為で有る。
■ 行頭に引用記号を挿入する 次の例ではTextBox1 に入力された文字列の行頭に「< 」を挿入して居る。パターンの「^」は 0 幅だ が、置換に利用出来る。 Visual Basic ' 行頭に引用記号"> "を挿入する TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( _ TextBox1.Text, "^", "> ", System.Text.RegularExpressions.RegexOptions.Multiline) C# // 行頭に引用記号"> "を挿入する TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( TextBox1.Text, "^", "> ", System.Text.RegularExpressions.RegexOptions.Multiline); ■ 連続する同じ行を削除する 次の例ではTextBox1 に入力された文字列から連続する同じ行を削除して居る。詰まり、同じ内容の行 が連続して居る場合、其れを1 行丈にする。 Visual Basic ' 連続する同じ行を削除 TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( _ TextBox1.Text, "^(.*)(¥r?¥n¥1)+$", "$1", _ System.Text.RegularExpressions.RegexOptions.Multiline) C# // 連続する同じ行を削除 TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( TextBox1.Text, @"^(.*)(¥r?¥n¥1)+$", "$1", System.Text.RegularExpressions.RegexOptions.Multiline); ■ 日付のフォーマットを変更する 「2000/10/22」の様に「/」で区切られて居る形式の日付を「2000 年 10 月 22 日」と変更する例を示す。 Visual Basic ' "2000/10/22" の様な形式を "2000 年 10 月 22 日" の様に変換する TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( _ TextBox1.Text, _ "(?<year>(?:¥d¥d)?¥d¥d)/(?<month>¥d¥d?)/(?<day>¥d¥d?)", _ "${year}年${month}月${day}日") C# //"2000/10/22"の様な形式を"2000 年 10 月 22 日"の様に変換する TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( TextBox1.Text, @"(?<year>(?:¥d¥d)?¥d¥d)/(?<month>¥d¥d?)/(?<day>¥d¥d?)", "${year}年${month}月${day}日");
■ MatchEvaluator デリゲートを使用する
MatchEvaluator デリゲートを使用すれば、更に複雑な置換が可能で有る。次の例では、日付の部分を 1 日増やした日付と置換して居る。
Visual Basic
' Button1 の Click イベントハンドラ
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles Button1.Click
' 日付の部分 ("2000/10/22"の様な形式) を 1 日増やす
TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( _
TextBox1.Text, "(?<year>(?:¥d¥d)?¥d¥d)/(?<month>¥d¥d?)/(?<day>¥d¥d?)", _ New System.Text.RegularExpressions.MatchEvaluator(AddressOf IncrementDay)) End Sub
' MatchEvaluator デリゲートメソッド Private Shared Function IncrementDay( _
ByVal m As System.Text.RegularExpressions.Match) As String Dim dt As DateTime ' マッチした文字列を日時に変換 If DateTime.TryParse(m.Value, dt) Then Return dt.AddDays(1).ToShortDateString() ' 1 日増やす Else Return m.Value End If End Function C# // Button1 の Click イベントハンドラ
private void Button1_Click(object sender, System.EventArgs e) { // 日付の部分("2000/10/22"の様な形式)を 1 日増やす TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( TextBox1.Text, @"(?<year>(?:¥d¥d)?¥d¥d)/(?<month>¥d¥d?)/(?<day>¥d¥d?)", new System.Text.RegularExpressions.MatchEvaluator(IncrementDay)); } // MatchEvaluator デリゲートメソッド
private static string IncrementDay(System.Text.RegularExpressions.Match m) { DateTime dt; // マッチした文字列を日時に変換 if (DateTime.TryParse(m.Value, out dt)) { return dt.AddDays(1).ToShortDateString(); // 1 日増やす } else { return m.Value; } }