今回はC#で正規表現を扱う際の基本の語彙ともいえるエスケープ文字、文字クラス、量指定子、アンカーについて見ていこう。
前回は、C#で正規表現を使用するためのRegexクラスとそのメソッドについて見た。今回は、エスケープ文字、文字クラスなど、C#で正規表現を利用する上での基本を見ていく。
正規表現は「メタ文字」と「リテラル」の2種類で構成される。メタ文字とは「何か特殊な意味を持つ文字」のことで、例えば「\n」は「改行文字を意味するメタ文字」だ。一方、リテラルはこうした意味を持たない(literally=見たままの)文字のことで、例えば「a」は「aという文字」として正規表現内では解釈される。よって、「a\n」という正規表現があったとすると、それは「文字aに続けて改行文字」として解釈される。
「文字クラス」(指定した範囲に含まれる任意の1文字)を表す「[]」や「\w」(単語に使われる文字を意味する)、入力の先頭と末尾を意味する「^」と「$」、直前に書かれた正規表現の繰り返し回数を指定する量指定子として使われる「+」「*」「{}」などもメタ文字だ。つまり、正規表現中でプログラマーが何かを表現するために使用するリテラル以外の文字は全てメタ文字となる。
正規表現中で、特定の文字を意味するエスケープ文字も今述べたメタ文字の一種だ。C#(.NET Framework)では以下のようなエスケープ文字がサポートされている。
エスケープ文字 | 説明 |
---|---|
\a | ベル(ビープ音) |
\b | バックスペース |
\t | タブ文字 |
\r | キャリッジリターン |
\v | 垂直タブ |
\f | フォームフィード |
\n | 改行文字 |
\e | ESC文字 |
\nnn | 8進表記の文字 |
\xnn | 16進表記の文字 |
\cX | Xで指定される制御文字。例えば、ベルを表す「\a」は「\cG」としても表記できる(制御文字G=CTRL+Gはベルを意味する) |
\uXXXX | XXXXで指定される値をコードポイントとするUnicode文字。例えば、ベルを表す「\a」は「\u0007」としても表記できる |
\ | 正規表現で使用される特殊な意味を持つ文字をエスケープするのに使用する。例えば、入力の末尾を意味する「$」をドル記号として使いたい場合には「\$」と表記する |
.NET Frameworkでサポートされているエスケープ文字 |
以下に例を示す(「using System.Text.RegularExpressions;」が必要)。
string input = "abc def \a ghi jkl"; // \u0007はベル文字
string pattern = @"\a"; // \aもベル文字
Console.WriteLine(Regex.IsMatch(input, pattern)); // True
pattern = @"\u0007"; // \aもベル文字
Console.WriteLine(Regex.IsMatch(input, pattern)); // True
pattern = @"\cG";
Console.WriteLine(Regex.IsMatch(input, pattern)); // True
ベル文字はさまざまな形で表現できることを表中で示したが、上のコードはそれが本当かどうかを試している。正規表現でマッチの対象とする入力文字列にはベル文字(\a)が埋め込まれている(これをコンソールに出力すると、「abc」などの文字列とともに警告音が出力される)。後は変数patternの内容を上で示したエスケープ表記を使ったものにしながら、Regex.IsMatchメソッドを使って、マッチするかどうかを試している。
文字クラスとは「指定された範囲に含まれる文字」を表し、その中に含まれる文字のいずれか1文字にマッチする。文字クラスを表すのによく使われるメタ文字が「[]」だ。これは、かっこ内に文字クラスとして指定したい文字のリストを記述していく。単語に使われる文字を意味する「\w」や数字を意味する「\d」なども文字クラスを表すメタ文字である。
よく見る文字クラスの例としては「[a-zA-Z0-9]」がある。これは「文字a〜z、文字A〜Z、文字0〜9」のいずれかにマッチする。つまり、英大文字小文字と数字のいずれかにマッチする。これは「[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]」と書くのと同値だが、[]内では「-」を使って文字の範囲を指定できることから「[a-zA-Z0-9]」のように省略して表記できる。
なお、[]内の先頭に「^」を書くと「その文字クラスに含まれない文字」にマッチする(これを「否定文字クラス」と呼ぶ)。また、[]の先頭に「-」を書くと、文字の範囲ではなくマイナス記号そのものを意味するようになる。
[]を使用した場合の文字クラスの表記を以下にまとめる。
文字クラス表記 | 説明 | 例 |
---|---|---|
[文字クラスを構成する文字のリスト] | 「文字クラスを構成する文字のリスト」に含まれる任意の1文字にマッチ | [abc](「a」「b」「c」のいずれかにマッチ) |
[^文字クラスを構成しない文字のリスト] | 「文字クラスを構成しない文字のリスト」以外の任意の1文字にマッチ | [^abc](「a」「b」「c」以外の任意の1文字にマッチ) |
[start-last] | 「start」から「last」までに範囲に含まれる任意の1文字にマッチ | [a-z](任意の英小文字にマッチ) |
[-...] | マイナス記号を文字クラスに含めるにはリストの先頭に置く | [-0-9](マイナス記号と数字にマッチする) |
[]を使用した文字クラスの表記 |
既に述べたが、単語に使われる文字や数字、空白文字など(およびその否定集合)を表す文字クラスも利用できる。これらを以下にまとめる。
文字クラス | 説明 |
---|---|
\w | 単語に使われる任意の1文字にマッチ |
\W | \wで表される単語に使われる文字以外の任意の1文字にマッチ |
\s | 空白文字にマッチ |
\S | 空白文字以外にマッチ |
\d | 数字にマッチ |
\D | 数字以外にマッチ |
\p{unicode_category} | unicode_categoryに示したUnicode一般カテゴリー(Unicode General Category)に含まれる任意の1文字にマッチ |
\P{unicode_category} | unicode_categoryに示したUnicode一般カテゴリー(Unicode General Category)に含まれる文字以外の任意の1文字にマッチ |
その他の文字クラス |
ある範囲の文字を表す文字クラスは小文字で、その否定となる文字クラスは大文字で表記されることは覚えておくようにしよう。「\p{...}」では{}内にUnicode一般カテゴリーを指定する。「Unicode一般カテゴリー」とは「大文字」「小文字」「句読点」などの分類を表すもの。例えば、大文字は「Lu」(Letter uppercase)、小文字は「Ll」(Letter lowercase)、句読点全般は「P」(Punctuation)として表記できる。詳細なカテゴリーについては「General Category Values」ページを参照のこと。
string input = "insider.net";
string pattern = @"\w+"; // 単語に使われる文字が1文字以上
Console.WriteLine(Regex.Match(input, pattern)); // insider
pattern = @"\p{P}"; // 1文字の句読点
Console.WriteLine(Regex.Match(input, pattern)); // .
pattern = @"(\w+)\p{P}(\w+)"; // 句読点で区切られた単語を
string replacement = @"$1_$2"; // アンダースコアでつなぎ直す
Console.WriteLine(Regex.Replace(input, pattern, replacement)); // insider_net
この例では「insider.net」という文字列を対象に、マッチする部分の取り出しと置換を行っている。最初に試しているのは「\w+」というパターンだ。これは「単語に使われる任意の1文字」に「1文字以上」を意味する「+」記号を付加することで、「単語に使われる文字の1文字以上の連続」つまり「単語」を表す。よって、Matchメソッドの結果は「insider」となる。「.」は単語に含まれる文字ではないからだ。なお、「+」記号は「量指定子」と呼ばれるものだ(後述)。
次に試しているのは「\p{P}」というパターン。上でも述べたが、「\p{}」ではかっこ内にUnicode一般カテゴリーで規定されるカテゴリーを指定する。ここでは「句読点全般」を意味する「P」を指定している。句読点全般に含まれる文字としては「ピリオドやカンマ、かっこ、疑問符」などがある。よって、Regex.Matchメソッドの結果は「.」となる。このカテゴリーには日本語の句読点も含まれるので、興味のある方は入力文字列を「insider。net」「insider(net」などにして、実行してみてほしい。
そして、最後に上で見た「\w+」と「\p{P}」を組み合わせて置換を行っている。ここでは「\w+」をかっこで囲み(「(\w+)」)、これにマッチする部分をグループ化し、その結果を「キャプチャー」している。キャプチャーした内容は、置換文字列の中で「$1」「$2」のようにして参照できる。「\p{P}」はかっこで囲んでないが、これは置換時にその内容を参照しておらず、必要がないからだ。置換文字列は「$1_$2」となっているので、置換後の文字列は「insider_net」となる。
Copyright© Digital Advantage Corp. All Rights Reserved.