Yuanzi に来る前に私が書いた正規表現チュートリアル。codeproject による The 30 Minute Regex Tutorial から部分的に翻訳されました。
コメント内のURLが長いため、このページのレイアウトは少しわかりにくくなっています。読んだ後に質問がある場合は、ここで質問してください。
一言:
正規表現の基本的な知識がない場合は、「ステップバイステップ」チュートリアルに従ってください。ざっと見ただけで理解できないとは言わないでください。このような態度では私が何を書いているのか理解できません。これは「30 分のチュートリアル」です。30 秒で始めようとしないでください。
-
実際、私の隣には、コンピュータに触れたばかりで操作にあまり習熟していない人が、このチュートリアルを独学で学習した後、記事収集システムで正規表現を使用してタスクを完了できるようになりました。 。さらに、彼が書いた表現には、「ゼロ幅アサーション」などの「高度な」テクニックも使用されていました。
したがって、問題について具体的に教えていただければ、喜んでお手伝いさせていただきます。しかし、一言で理解できないとしても、それは私の問題ではありません。
転載は歓迎ですが、作者と出典を明記してください。
-
正規表現に関する 30 分の入門チュートリアル
バージョン: v2.31 (2009-4-11) 作者: deerchao 転載の際は出典を明記してください
目次
目次をスキップ
この記事の目的
- このチュートリアルの使用方法
- 正規表現とは何ですか?
- はじめに
- 正規表現をテストする
- メタキャラクター
- キャラクターエスケープ
- 繰り返し
- キャラクタークラス
- 分岐条件
- 対義語
- グループ
- バックリファレンス
- ゼロ幅アサーション
- 負のゼロ幅アサーション
- メモ
- 貪欲と怠惰
- 処理オプション
- バランスのとれたグループ/再帰的マッチング
- 他にも触れていないことがあります
- 著者に連絡する
- この記事のオンライン リソースと参考文献
- 記録を更新
-
この記事の目的
30 分で、正規表現とは何かを理解し、その基本をある程度理解して、独自のプログラムや Web ページで正規表現を使用できるようになります。
このチュートリアルの使用方法
最も重要なことは、
30 分
ください。正規表現の経験がない場合は、30 秒で始めようとしないでください - 超人でない限り :)
以下の複雑な式に怖がらないでください。ステップバイステップで説明していけば、正規表現は実際には
思っているほど難しくないことがわかるでしょう。もちろん、このチュートリアルを読んだ後、多くのことは理解できても、ほとんど何も思い出せなかったとしても、それは正常です。これまで正規表現に触れたことのない人でも、このチュートリアルを読んだ後はかなりのことを理解できるようになると思います。チュートリアルでは、記載された文法を 80% 以上覚えられる可能性はゼロです。これは基本原則を理解していただくためのものであり、正規表現を上手にマスターするには、今後さらに練習して使用する必要があります。
この記事は、入門チュートリアルであるだけでなく、日常業務で使用できる正規表現構文のリファレンス マニュアルとしても機能します。著者自身の経験に関する限り、この目標はうまく達成されました。ご存知のとおり、すべてを自分で書き留めることはできませんね。
明確な形式 テキスト形式の規則:
専門用語
メタ文字/文法形式 正規表現 正規表現の一部 (分析に使用) 一致するソース文字列 正規表現 数式またはその一部の説明
サイドノートを非表示にする この記事の右側にいくつかのメモがあります。これらは主に、プログラマーの経験がない読者に関連情報を提供したり、基本的な概念を説明したりするために使用され、通常は無視してかまいません。
正規表現とは何ですか?
文字
は、コンピューター ソフトウェアが文字、数字、句読点、スペース、改行、漢字などのテキストを処理する際の最も基本的な単位です。
String は 0 個以上の文字のシーケンスです。 Textはテキスト、文字列です。特定の文字列 が特定の正規表現 に一致すると言うことは、通常、文字列の一部 (またはいくつかの部分) がその式で指定された条件を満たすことができることを意味します。
文字列を処理するプログラムや Web ページを作成する場合、特定の複雑なルールに一致する文字列を検索する必要があることがよくあります。 正規表現
は、これらのルールを記述するために使用されるツールです。言い換えれば、正規表現はテキスト ルールを記録するコードです。
Windows/Dos でのファイル検索に ワイルドカード、つまり * と ? を使用した可能性が非常に高いです。特定のディレクトリ内のすべての Word ドキュメントを検索したい場合は、*.doc を検索します。ここで、 * は任意の文字列として解釈されます。ワイルドカードと同様に、正規表現もテキストの一致に使用されるツールですが、ワイルドカードよりもニーズを正確に記述することができます。もちろん、複雑になりますが、たとえば、 の検索に使用される正規表現を作成できます。すべての文字列は 0 で始まり、その後に 2 ~ 3 桁、次にハイフン「-」、そして最後に 7 桁または 8 桁の ( 010-12345678 や 0376-7654321 など)。
はじめに
正規表現を学習する最良の方法は、例を理解した後、自分で変更して実験することです。以下にいくつかの簡単な例を示し、詳細に説明します。
英語の小説で hi を検索すると仮定すると、正規表現 hi を使用できます。
これは、ほぼ最も単純な正規表現で、次のような文字列と正確に一致します。 は 2 つの文字で構成され、最初の文字は h で、次の文字は i です。通常、正規表現を処理するツールには、大文字と小文字を無視するオプションが用意されており、このオプションが選択されている場合は、 hi、HI、Hi、hI のいずれかのケースに一致します。
残念ながら、him、history、highなど、多くの単語に 2 つの連続した文字 hi が含まれています。 hiで検索すると中のhiも見つかります。 単語 こんにちは を正確に見つけたい場合、bhib を使用する必要があります。
bとは、正規表現で指定される特殊なコード(メタキャラクター、メタキャラクターと呼ぶ人もいますね)で、単語の境界である単語の始まりや終わりを表します。通常、英語の単語はスペース、句読点、または改行で区切られますが、b はこれらの単語区切り文字のいずれにも一致せず、 1 つの位置 にのみ一致します。
より正確にする必要がある場合、
b
は、前後の文字が両方とも一致しない位置 (1 つは存在する、もう 1 つは存在しない、または存在しない) w と一致します。
探しているものが
hiの後にLucy
が続く場合は、bhib.*bLucybを使用する必要があります。
ここで、
.
は別のメタキャラクターであり、改行文字を除く任意の文字に一致します。 * もメタキャラクターですが、文字や位置を表すのではなく、量を表します。これは、式全体を一致させるために、* より前の内容を何度でも再利用できることを指定します。したがって、.* を組み合わせると、改行を含まない 任意の数の文字 を意味します。これで、bhib.*bLucyb の意味は明らかです。最初に単語 hi、次に任意の数の文字 (ただし改行は不可)、そして最後に単語 Lucy があります。
改行文字は「n」、ASCII エンコーディングが 10 (16 進数の 0x0A) である文字です。
他のメタキャラクターを同時に使用すると、より強力な正規表現を構築できます。たとえば、次の例:
0dd-dddddddd
は次のような文字列と一致します:
0 で始まり、次に 2 桁、次にハイフン "-"、最後に 8 桁 (つまり、中国の電話番号。もちろん、この例では市外局番が 3 桁の場合に一致します)。
ここで d
は、
1 桁 (0、または 1、または 2、または...) に一致する新しいメタキャラクターです。 - はメタキャラクターではなく、それ自体、つまりハイフン (またはマイナス記号、ハイフン、または任意の名前) にのみ一致します。
煩わしい繰り返しを避けるために、この式を次のように書くこともできます: 0d{2}-d{8}
。
ここで、
dの後の{2}({8})は、前のdを2回(8回)繰り返して一致させる必要があることを意味します。
正規表現をテストする
その他の利用可能なテストツール:
- 正規表現バディ
- JavaScript正規表現オンラインテストツール
正規表現の読み書きが難しくないと感じたら、あなたは天才か、地球人ではないかのどちらかです。正規表現の構文は、定期的に使用している人であっても混乱を招く可能性があります。正規表現は読み書きが難しく、エラーが発生しやすいため、正規表現をテストするツールを見つける必要があります。
正規表現の詳細は、環境によって異なります。このチュートリアルでは、Microsoft .Net Framework 4.0 での正規表現の動作を紹介します。そのため、私が作成した .Net での正規表現ツールをお勧めします。ソフトウェアをインストールして実行するには、このページの手順を参照してください。
以下は、実行中の Regex Tester のスクリーンショットです:
これで、b、.、*、d などのいくつかの便利なメタキャラクターがわかりました。smatch スペースを含む任意の空白文字など、正規表現にはさらに多くのメタキャラクターがあります。 、タブ、改行、中国語の全角スペースなど。 w文字、数字、アンダースコア、漢字などと一致します。
中国語/漢字の特殊処理は、.Net が提供する正規表現エンジンによってサポートされています。その他の環境での詳細については、関連ドキュメントを確認してください。
以下のその他の例を参照してください:
baw*b は、文字 a で始まる の単語と一致します - 最初に単語の先頭 (b)、次に文字 a、次に任意の数の文字または数字 (w* ) 、そして最後に語尾(b)。
それでは、正規表現内の単語の意味について話しましょう: 少なくとも 1 つの連続した
w。はい、これは英語を学ぶときに覚えなければならない同じ名前の何千ものこととは何の関係もありません:)
d+は 1 つ以上の連続する数字と一致します。ここで + は * に似たメタキャラクターですが、* は任意の回数 (おそらく 0 回) 繰り返された に一致するのに対し、+ は 1 回以上繰り返された に一致する点が異なります。
bw{6}b
は、正確に 6 文字の
単語 に一致します。
表 1. 一般的に使用されるメタキャラクター
コード
手順 |
|
.
改行文字を除く任意の文字と一致します |
|
w
文字、数字、アンダースコア、または漢字と一致します |
|
s
任意の空白文字と一致します |
|
d
数字を一致させる |
|
b
単語の先頭または末尾を一致させます |
|
^
文字列の先頭と一致します |
|
$
文字列の末尾を一致させます |
|
正規表現エンジンは通常、JavaScript の RegExp.test() メソッドや .NET の Regex.IsMatch() メソッドなど、「指定された文字列が正規表現と一致するかどうかをテストする」メソッドを提供します。ここでの一致とは、文字列の中に表現規則に適合する部分があるかどうかを指します。 ^ と $ を使用しない場合、d{5,12} に対して、このメソッドを使用すると、文字列 に 5 から 12 の連続した数字 が含まれることのみが保証され、文字列全体ではありません。5 から 12 です。数字。
メタキャラクター ^ (数字の 6 と同じキー上の記号) と $ はどちらも位置に一致し、b に似ています。 ^ は検索する文字列の先頭に一致し、$ は末尾に一致します。これら 2 つのコードは、入力内容を確認するときに非常に役立ちます。たとえば、Web サイトで入力する QQ 番号が 5 ~ 12 桁である必要がある場合は、^d{5,12}$ を使用できます。
ここでの {5,12} は、前に紹介した {2} と似ていますが、{2}matching は 2 回のみ繰り返すことができます、それ以上でもそれ以下でもありません {5,12 繰り返しの回数は 5 回未満にすることはできず、12 回を超えることはできません。それ以外の場合は一致しません。
^ と $ が使用されているため、入力文字列全体を使用して d{5,12} と一致させる必要があります。つまり、入力全体 は 5 から 12 個の数字 でなければなりません。したがって、入力された QQ 番号がこの正規表現と一致する場合、要件を満たします。
大文字と小文字を無視するオプションと同様に、一部の正規表現処理ツールには複数行を処理するオプションもあります。このオプションをチェックすると、
^と$の意味が行頭と行末を一致させるになります。
キャラクターエスケープ
メタキャラクター自体を検索したい場合、たとえば
. や * を検索する場合、問題があります。メタキャラクターは別のものとして解釈されるため、指定することができません。現時点では、を使用してこれらの文字の特別な意味をキャンセルする必要があります。したがって、. と * を使用する必要があります。もちろん、自体を見つけるには、\を使用する必要があります。
例: unibetter.com
は unibetter.com と一致し、C:\Windows は C:Windows と一致します。
繰り返し
以前の *
、+、{2}、{5,12} のこれらの一致メソッドと反復メソッドを見てきました。以下は正規表現内のすべての修飾子です (*、{5,12} などの指定された数のコード):
表 2. よく使用される修飾子
コード/構文
手順 |
|
*
ゼロ回以上繰り返します |
|
+
1回以上繰り返します |
|
?
ゼロ回または 1 回繰り返します |
|
{n}
n回繰り返します |
|
{n,}
n回以上繰り返します |
|
{n,m}
n回からm回繰り返します |
|
繰り返しの使用例をいくつか示します:
Windowsd+は、Windowsの後に1つ以上の数字が続く
と一致します
^w+match行の最初の単語 (または文字列全体の最初の単語、一致の具体的な意味はオプション設定によって異なります)
キャラクタークラス
これらの文字セットに対応するメタ文字がすでに存在するため、数字、文字、数値を検索する場合、空白は非常に簡単ですが、事前定義されたメタ文字のない文字セット (母音 a、e、i、o、u など) と一致させたい場合は、 )、 私たちは何をすべきか?
とても簡単です。角括弧で囲むだけです。例えば、[aeiou] はあらゆる英語の母音に一致し、[.?!]句読点 (. または ? または !) に一致します 。
文字 range も簡単に指定できます。例えば、[0-9] は d と全く同じ意味です: 1 桁 も同様に [a-z0-9A-Z_ ] も完全に同等ですwへ(英語のみを考慮した場合)。
より複雑な式は次のとおりです: (?0d{2}[) -]?d{8}。
「(」と「)」もメタ文字ですが、後でグループ化セクションで説明するため、ここでエスケープする必要があります。
この式は、(010)88886666、022-22334455、02912345678などの複数の形式の電話番号と一致します。これについて分析してみましょう。最初にエスケープ文字 (、0 回または 1 回出現する可能性があります (?)、次に 0、その後に 2 つの数字 (d{2} ) があります。 、次に ) または - または space のいずれか (1 回出現するかどうか) (?)、最後に 8 つの数字 (d{8}) が続きます。
分岐条件
残念ながら、今の式は 010)12345678 や (022-87654321 など) のような「間違った」形式にも一致する可能性があります。この問題を解決するには、 分岐条件 を使用する必要があります。 正規表現 分岐条件式内の は複数のルールを参照しています。そのいずれかが一致した場合、異なるルールを で区切ります。 例:
0d{2}-d{8}|0d{3}-d{7}この式は、ハイフンで区切られた 2 つの電話番号と一致します。1 つは 3 桁の市外局番と 8 桁の市外局番 ( 010-12345678 など)、1 つは 4 桁の市外局番と 7 桁の市内番号 (0376-2233445) です。
(0d{2})[- ]?d{8}|0d{2}[- ]?d{8}この式 は、3 桁の市外局番を持つ電話番号と一致します。市外局番と市外局番は括弧で囲むか、必須ではありません。区切り文字はハイフンまたはスペースで区切ることもできます。 区切らないこともできます。分岐条件を使用してこの式を拡張し、4 桁の市外局番もサポートできるようにすることができます。
d{5}-d{4}|d{5}この式は、米国の郵便番号と一致するために使用されます。米国の郵便番号の規則は 5 桁、またはハイフンで区切られた 9 桁です。この例が挙げられている理由は、次の問題を説明できるためです。 分岐条件を使用するときは、各条件の順序に注意してください。これを d{5}|d{5}-d{4} に変更すると、5 桁の郵便番号 (および 9 桁の郵便番号の最初の 5 桁) のみが照合されます。その理由は、分岐条件を照合するときに、各条件が左から右にテストされ、特定の分岐が満たされると、他の条件は考慮されないためです。
グループ
単一の文字を繰り返す方法についてはすでに説明しましたが (文字の直後に修飾子を追加するだけです)、複数の文字を繰り返したい場合はどうすればよいでしょうか。括弧を使用して
部分式 (グループ化 とも呼ばれます) を指定し、この部分式の繰り返し数を指定できます。また、部分式に対して他の操作を実行することもできます (後で紹介します)。
(d{1,3}.){3}d{1,3} は、単純な IP アドレス マッチング 式です。この式を理解するには、次の順序で分析してください: d{1,3} は 1 から 3 桁の数値 と一致します , (d{1,3}.){3} は 3 桁の と一致します桁の数字 英語のピリオド (この全体が のグループ化 ) を追加し、それを 3 回繰り返して 、最後に 1 ~ 3 桁の数字 (d{1,3}) を追加します。 IP アドレスの各数字は 255 を超えることはできません。「24」の第 3 シーズンの脚本家に騙されないでください...
残念ながら、これは不可能な IP アドレス 256.300.888.999 にも一致します。算術比較を使用できる場合は、この問題を簡単に解決できる可能性がありますが、正規表現では数学関数が提供されないため、正しい IP アドレスを記述するには、長いグループ化、選択、および文字クラスのみを使用できます: (( 2[0-4]d|25[0-5]|[01]?dd?).){3}(2[0-4]d|25[0-5]|[01]?dd?) 。
この式を理解する鍵は 2[0-4]d|25[0-5]|[01]?dd? を理解することです。ここでは詳しく説明しませんが、分析できるはずです。自分自身の存在意義。
対義語
単純に定義された文字クラスに属さない文字を検索する必要がある場合があります。たとえば、数字以外の文字を検索する場合は、 の反意語を使用する必要があります:
表 3. 一般的に使用される反意語コード
コード/構文 | 手順 |
W
|
文字、数字、アンダースコア、または漢字以外の任意の文字と一致します
|
S
|
空白以外の任意の文字と一致します
|
D
|
数字以外の文字と一致します
|
B
|
単語の先頭または末尾ではない位置と一致します
|
[^x]
|
x を除く任意の文字と一致します
|
[^アイオウ]
|
aeiou の文字を除く任意の文字と一致します
|
例: S+は、空白文字を含まない文字列と一致します。
]+> は、山かっこで囲まれた で始まる文字列 と一致します。
バックリファレンス
括弧を使用して部分式を指定した後、この部分式に一致するテキスト (つまり、このグループによってキャプチャされたコンテンツ) を式または他のプログラムでさらに処理できます。デフォルトでは、各グループには自動的に グループ番号 が付けられます。ルールは、左から右に、グループの左括弧でマークされ、最初に表示されるグループのグループ番号は 1、2 番目のグループ番号は 2 です。等々。
ええと...実際には、グループ番号の割り当ては先ほど述べたほど単純ではありません:
- グループ 0 は正規表現全体に対応します
- 実際、グループ番号割り当てプロセスでは、左から右へ 2 回のスキャンが必要です。最初のパスは名前のないグループにのみ割り当てられ、2 番目のパスは名前付きグループのみに割り当てられます。したがって、すべての名前付きグループのグループ番号は、名前のないもの グループ番号
- (?:exp) のような構文を使用して、グループ番号の割り当てに参加する権利をグループから剥奪することができます。
後方参照は、前のグループに一致するテキストを繰り返し検索するために使用されます。たとえば、1 は、グループ 1 によって一致したテキストを表します。わかりにくいですか?例を参照:
b(w+)bs+1b は、go go や kitty kitty など、繰り返される単語と一致させるために使用できます。この式はまず 単語、つまり 単語の先頭と末尾の間に複数の文字または数字 (b(w+)b) があり、この単語は数字の 1 にキャプチャされます。グループ、次に 1 つまたは複数の空白文字 (s+)、最後に グループ 1 でキャプチャされたコンテンツ (つまり、以前に一致した単語) (1)。
部分式の グループ名 を自分で指定することもできます。部分式のグループ名を指定するには、構文 (?w+) (または山括弧を ' に置き換えます: (?'Word'w+)) を使用します。これにより、グループ名は w+ はWordとして指定されます。このグループ capture の内容を後方参照するには、k を使用できるため、前の例は次のように書くこともできます: b(?w+)bs+kb。
括弧を使用する場合、特殊な目的の構文が多数あります。最も一般的に使用されるもののいくつかを以下に示します:
表 4. 一般的に使用されるグループ化構文
カテゴリ | コード/構文 | 説明 |
キャプチャ
|
(経験値)
|
経験値を照合し、テキストを自動的に名前が付けられたグループにキャプチャします
|
(?経験値)
|
exp を照合し、テキストを name という名前のグループにキャプチャします。(?'name'exp) と書くこともできます。
|
(?:exp)
|
式を一致させ、一致するテキストをキャプチャせず、このグループにグループ番号を割り当てません
|
ゼロ幅アサーション
|
(?=exp)
|
expの前の位置と一致させます
|
(?
|
expの後ろの位置と一致させます
|
(?!経験値)
|
expが続かない位置を一致させます
|
(?
|
exp ではない前の位置と一致します
|
メモ
|
(?#コメント)
|
このタイプのグループ化は正規表現の処理には影響せず、人々が読むためのコメントを提供するために使用されます
|
最初の 2 つの構文についてはすでに説明しました。 3 番目の (?:exp) は正規表現の処理方法を変更しませんが、そのようなグループ に一致するコンテンツは最初の 2 つのようなグループにキャプチャされず、グループ番号 も持ちません。 「なぜこれをしたいのですか? – 良い質問ですが、なぜだと思いますか?」
ゼロ幅アサーション
地球上の人々、これらの専門用語の名前は複雑すぎて覚えるのが難しいと思いますか?私もそれを感じています。そのようなものがあることを知ってください、それは何と呼ばれますか、それを手放してください!人は名前がなければ剣の練習に集中でき、物に名前がなければ自由に選んで去ることができます...
次の 4 つは、何かの前後にあるものを検索するために使用されます (ただし、これらは含まれません)。つまり、b、^、$ のような位置を指定するために使用されます。この場所は特定の条件を満たす必要があります (つまり、アサーション)、そのため、ゼロ幅アサーションとも呼ばれます。例を使用して説明するのが最善です:
アサーションは、真であるべき事実を宣言するために使用されます。正規表現でのマッチングは、アサーションが true の場合にのみ続行されます。
(?=exp) は ゼロ幅正先読みアサーション とも呼ばれ、式 exp が出現する位置以降に一致する可能性があることをアサートします。たとえば、bw+(?=ingb)は、I'm singing while you're dance.を検索する場合、ingで終わる単語の前の部分(ing以外の部分)と一致します。 、歌うと踊るにマッチします。
(?はゼロ幅ポジティブポストレビューアサーションとも呼ばれ、それが出現する位置の前が式expと一致する可能性があることをアサートします。例えば、(?はreで始まる単語の後半(re以外の部分)と一致します。例えば、reading a bookを検索すると、adingと一致します。 。
非常に長い数値の 3 桁ごとにカンマを追加したい場合 (もちろん右から追加します)、次のようにカンマを前後に付けて追加する必要がある部分を見つけることができます: ((? を使用して 1234567890 を検索すると、結果は 234567890 になります。
次の例では、両方のアサーションを使用しています: (?は、空白で区切られた 数値 (ここでも空白を除く) と一致します。
負のゼロ幅アサーション
特定の文字ではない、または特定の文字クラス (反意語) に属さない文字を検索する方法については前に説明しました。しかし、特定の文字が表示されないことを確認したいだけで、一致させたくない場合はどうすればよいでしょうか?たとえば、文字 q が出現するが、q の後に文字 u が続かない単語を検索したい場合は、これを試すことができます:
bw*q[^u]w*bは、の後に文字uではない文字qが続くを含む単語と一致します。しかし、さらにテストを行うと (または十分に鋭敏で直接観察すると)、Iraq、Benq のように、単語の末尾に q が現れる場合、この表現は間違っていることがわかります。これは、[^u] が常に 1 つの文字に一致するため、q が単語の最後の文字である場合、次の [^u] は q の後の単語区切り文字 (スペース、ピリオド、または何か)、次の w*b は次の単語と一致するため、 bw*q[^u]w*b は イラク戦闘 全体と一致することができます。 負のゼロ幅アサーション は、1 つの位置のみに一致し、文字を 消費しないため、この問題を解決できます。さて、この問題は次のように解決できます: bw*q(?!u)w*b。
ゼロ幅の負の先読みアサーション(?!exp)は、式expがこの位置以降では一致できないことをアサートします。例: d{3}(?!d) は 3 つの数字に一致し、これらの 3 つの数字の後に数字 を続けることはできません。 b((?!abc)w)+b は に連続する文字を含まないものに一致します。 abc 単語の文字列 。
同様に、(?、
ゼロ幅ネガティブルックバックアサーションを使用して、式expがこの位置の前で一致できないことをアサートできます: (? は、前に小文字が付いていない 7 桁の数字 と一致します。
请详细分析表达式(?).*(?=),这个表达式最能表现零宽断言的真正用途。
一个更复杂的例子:(?).*(?=)匹配不包含属性的简单HTML标签内里的内容。(?)指定了这样的前缀:被尖括号括起来的单词(比如可能是),然后是.*(任意的字符串),最后是一个后缀(?=)。注意后缀里的\/,它用到了前面提过的字符转义;\1则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)匹配的内容,这样如果前缀实际上是的话,后缀就是了。整个表达式匹配的是和之间的内容(再次提醒,不包括前缀和后缀本身)。
小括号的另一种用途是通过语法(?#comment)来包含注释。例如:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)。
要包含注释的话,最好是启用“忽略模式里的空白符”选项,这样在编写表达式时能任意的添加空格,Tab,换行,而实际使用时这些都将被忽略。启用这个选项后,在#后面到这一行结束的所有文本都将被当成注释忽略掉。例如,我们可以前面的一个表达式写成这样:
(?<= # 断言要匹配的文本的前缀
<(\w+)> # 查找尖括号括起来的字母或数字(即HTML/XML标签)
) # 前缀结束
.* # 匹配任意文本
(?= # 断言要匹配的文本的后缀
<\/\1> # 查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签
) # 后缀结束
贪婪与懒惰
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。
有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:
a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。
为什么第一个匹配是aab(第一到第三个字符)而不是ab(第二到第三个字符)?简单地说,因为正则表达式有另一条规则,比懒惰/贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权——The match that begins earliest wins。
表5.懒惰限定符
代码/语法 |
说明 |
*? |
重复任意次,但尽可能少重复 |
+? |
重复1次或更多次,但尽可能少重复 |
?? |
重复0次或1次,但尽可能少重复 |
{n,m}? |
重复n到m次,但尽可能少重复 |
{n,}? |
重复n次以上,但尽可能少重复 |
処理オプション
C# では、Regex(String, RegexOptions) コンストラクターを使用して正規表現処理オプションを設定できます。例: Regex regex = new Regex(@"baw{6}b", RegexOptions.IgnoreCase);
大文字小文字の無視、複数行の処理など、いくつかのオプションが上で紹介されています。これらのオプションは、正規表現の処理方法を変更するために使用できます。以下は、.Net で一般的に使用される正規表現オプションです:
表 6. 一般的に使用される処理オプション
名前 |
説明 |
IgnoreCase(大文字と小文字を無視) |
マッチングでは大文字と小文字は区別されません。 |
マルチライン(マルチラインモード) |
^ と $ の意味を、文字列全体の先頭と末尾だけではなく、任意の行の先頭と末尾でそれぞれ一致するように変更します。 (このモードでは、$ の正確な意味は、n の前の位置と文字列の終わりの前の位置を一致させることです。) |
シングルライン(シングルラインモード) |
すべての文字 (改行 n を含む) と一致するように . の意味を変更します。 |
IgnorePatternWhitespace(空白を無視) |
式内のエスケープされていない空白を無視し、#でマークされたコメントを有効にします。 |
ExplicitCapture(明示的キャプチャ) |
明示的に名前が付けられたグループのみをキャプチャします。 |
一个经常被问到的问题是:是不是只能同时使用多行模式和单行模式中的一种?答案是:不是。这两个选项之间没有任何关系,除了它们的名字比较相似(以至于让人感到疑惑)以外。
平衡组/递归匹配
这里介绍的平衡组语法是由.Net Framework支持的;其它语言/库不一定支持这种功能,或者支持此功能但需要使用不同的语法。
有时我们需要匹配像( 100 * ( 50 + 15 ) )这样的可嵌套的层次性结构,这时简单地使用\(.+\)则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式,懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等,比如( 5 / ( 3 + 2 ) ) ),那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的,配对的括号之间的内容呢?
为了避免(和\(把你的大脑彻底搞糊涂,我们还是用尖括号代替圆括号吧。现在我们的问题变成了如何把xx aa> yy这样的字符串里,最长的配对的尖括号内的内容捕获出来?
这里需要用到以下的语法构造:
-
(?'group') 把捕获的内容命名为group,并压入堆栈(Stack)
-
(?'-group') 从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败
-
(?(group)yes|no) 如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分
-
(?!) 零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败
如果你不是一个程序员(或者你自称程序员但是不知道堆栈是什么东西),你就这样理解上面的三种语法吧:第一个就是在黑板上写一个"group",第二个就是从黑板上擦掉一个"group",第三个就是看黑板上写的还有没有"group",如果有就继续匹配yes部分,否则就匹配no部分。
我们需要做的是每碰到了左括号,就在压入一个"Open",每碰到一个右括号,就弹出一个,到了最后就看看堆栈是否为空--如果不为空那就证明左括号比右括号多,那匹配就应该失败。正则表达式引擎会进行回溯(放弃最前面或最后面的一些字符),尽量使整个表达式得到匹配。
< #最外层的左括号
[^<>]* #最外层的左括号后面的不是括号的内容
(
(
(?'Open'<) #碰到了左括号,在黑板上写一个"Open"
[^<>]* #匹配左括号后面的不是括号的内容
)+
(
(?'-Open'>) #碰到了右括号,擦掉一个"Open"
[^<>]* #匹配右括号后面不是括号的内容
)+
)*
(?(Open)(?!)) #在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的"Open";如果还有,则匹配失败
> #最外层的右括号
平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配嵌套的标签:
]*>[^]*(((?'Open'
]*>)[^]*)+((?'-Open'
)[^]*)+)*(?(Open)(?!))
.
他にも言及していないことがあります
正規表現を構築するための多数の要素については上で説明しましたが、まだ言及されていないことがたくさんあります。以下に、言及されていないいくつかの要素のリストを、構文と簡単な説明とともに示します。必要に応じて、より詳細なリファレンスをオンラインで見つけて学習することができます。 MSDN ライブラリをインストールしている場合は、.net で正規表現に関する詳細なドキュメントを見つけることもできます。
ここでの紹介は非常に簡単です。さらに詳細な情報が必要で、コンピューターに MSDN ライブラリがインストールされていない場合は、正規表現言語要素に関する MSDN オンライン ドキュメントを参照してください。
表 7. 構文についてはまだ詳しく説明されていません
コード/構文 |
手順 |
あ |
アラーム文字 (印刷の効果はコンピューターからのビープ音です) |
b |
は通常単語の境界位置ですが、文字クラスで使用される場合はバックスペースを表します |
t |
タブ、タブ |
r |
入力 |
v |
垂直タブ文字 |
f |
ページフィード |
ん |
改行 |
え |
脱出 |
| ASCIIコードの8進数コードがnnである文字
|
xnn
| ASCIIコードの16進数コードがnnである文字
|
うんうん
| Unicodeコードの16進数コードがnnnnである文字
|
cN
| ASCII 制御文字。たとえば、cC は Ctrl+C を表します
|
A
| 文字列の開始 (^ に似ていますが、複数行のオプションの処理には影響を受けません)
|
Z
| 文字列の終わりまたは行の終わり (複数行のオプションの処理には影響を受けません)
|
z
| 文字列の終わり ($ に似ていますが、複数行のオプションの処理には影響を受けません)
|
G
| 現在の検索の開始
|
p{名前}
| Unicode の name という名前の文字クラス (p{IsGreek} など)
|
(?>exp)
| 貪欲な部分表現
|
(?-exp)
| バランスセット
|
(?im-nsx:exp)
| 部分式expの処理オプションを変更する
|
(?im-nsx)
| 式の残りの部分の処理オプションを変更します
|
(?(exp)はい|いいえ)
| exp をゼロ幅の前方先読みアサーションとして扱います。この位置で一致する場合は、このグループの式として yes を使用します。それ以外の場合は、no を使用します。
| (?(exp)はい)
上記と同じ、空の式を no として使用するだけです |
| (?(名前)はい|いいえ)
name という名前のグループがコンテンツをキャプチャする場合は、式として yes を使用します。それ以外の場合は、no を使用します |
| (?(名前)はい)
上記と同じ、空の式を no として使用するだけです |
わかりました、私はあなたに嘘をつきました、あなたはこれを読むのに 30 分以上かかったはずです、信じてください、これは私のせいです、あなたがあまりにも愚かだからではありません。自信と忍耐を持って続けてください。これを見たということは、私の陰謀が成功したことを証明しています。騙されるのは気分が良いですよね?
私について文句を言いたい場合、または私が実際にもっとうまくチートできると思う場合は、私の Weibo へようこそ。正規表現について質問がある場合は、stackoverflow Web サイトで質問できます。忘れずに regex タグを追加してください。中国語でのコミュニケーションに慣れている場合は、#正正# タグを使用して Weibo で質問することができます。
この記事のオンライン リソースと参考文献
Microsoft 正規表現チュートリアル-
System.Text. RegularExpressions.Regex クラス (MSDN)-
プロの正規表現教育サイト(英語)-
.Net のバランス グループに関する詳細なディスカッション (英語)-
正規表現をマスターする (第 2 版)-
記録を更新
2006-3-27 初版-
2006-10-12 第 2 版
-
いくつかの詳細なエラーと不正確さを修正しました-
中国語の処理に関する手順を追加しました-
いくつかの用語の翻訳を変更しました(MSDNの翻訳方法を採用)-
バランスグループの紹介を追加-
The Regulatorの導入を放棄し、Regex Testerに切り替えました-
2007-3-12 V2.1
-
いくつかの小さなバグを修正しました-
処理オプション (RegexOptions) の概要を追加しました-
2007-5-28 V2.2
-
ゼロ幅アサーションの再構成された入門-
いくつかの不適切な例を削除し、いくつかの実用的な例を追加しました-
その他の小さな変更点-
2007-8-3 V2.21
-
いくつかのテキストエラーを修正しました-
$,bの正確な説明を修正/追加-
作者が嘘つきであることを認めた-
RegexTesterにSinglelineオプション関連の機能を追加しました-
2008-4-13 v2.3
-
一部の章の順序を調整しました-
ページレイアウトを変更し、専用のリファレンスセクションを削除しました-
読者のフィードバックに応えて一部のコンテンツを調整しました-
2009-4-11 v2.31
-
いくつかのテキストエラーを修正しました-
注釈を追加しました-
一部文言を修正しました-
2011-8-17 v2.32
-
ツールの紹介を変更し、自社開発の正規表現テスターに置き換えました-
|