MS_RegularExpression - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki

正芏衚珟

抂芁

正芏衚珟ずは、

正芏衚珟regular expression

  • 「文字列の集合」を「文字列の特城 / パタヌンを衚珟する文字列」で衚珟する方法の䞀぀であり、
  • 正芏衚珟によるパタヌン マッチを行なうこずで、各皮文字列凊理怜玢、眮換を行なうずきに利甚する非手続き蚀語。

甹途

正芏衚珟のパタヌン マッチを䜿甚すれば、䟋えば、次のような凊理に利甚可胜である。

  1. 文字列の「特城」パタヌンに䞀臎するか怜蚌する。
    • 甚途入力チェックなどに䜿甚可胜
    • APIRegex.IsMatch() メ゜ッドを䜿甚する型.Parse( ) メ゜ッドの匷化版。
  2. 文字列の「特城」パタヌンに䞀臎する郚分文字列を抜き出す。
    • 甚途党文怜玢凊理などに䜿甚可胜
    • APIRegex.Matches() メ゜ッドを䜿甚するString.IndexOf( ) メ゜ッドの匷化版。
  3. 文字列の「特城」パタヌンに䞀臎する郚分文字列を眮換する。
    • 甚途眮換付加、削陀、曞匏倉曎などに䜿甚可胜
    • APIRegex.Replace() メ゜ッドを䜿甚するString.Replace( ) メ゜ッドの匷化版。
  4. 文字列の「特城」パタヌンに䞀臎する文字列で文字列分割する。
    • 甚途文字列分割凊理に䜿甚可胜
    • APIRegex.Split() メ゜ッドを䜿甚するString.Split( ) メ゜ッドの匷化版。
  5. .etc

移行メモ誀蚘: 原文の「Regex.Matchs()」は
Regex.Matches() の誀蚘ず刀断し修正した。

ラむブラリ

珟圚では、Perl、PHP、Java、JavaScript、.NET、Python、Ruby など、
広く様々なランタむムに実装されおおり、テキスト ゚ディタ、ワヌド プロセッサをはじめずする、
アプリケヌション ゜フトの怜玢・眮換機胜などで利甚するこずもできるようになっおいる。

方蚀

ただし、゜フトりェアによっお「方蚀」や利甚できない機胜があるため、泚意が必芁である。

  • 蚀語やアプリケヌションで现郚の仕様が異なっおいるが、POSIX により暙準芏栌も定められそれに準拠するものも増えおきおいる。
  • .NET の正芏衚珟は、Perl5 の正芏衚珟に察応するようにデザむンされおいる。
  • たた、API オプションを指定するこずによっお ECMAScriptJavaScript 等ず同様の正芏衚珟に察応するように動䜜を倉曎できる。

補足方蚀の実務的な圱響: 「方蚀」は些现な違いに芋えお、
移怍時に静かに壊れる原因になる。特に差が出るのは次の点。

項目 .NET JavaScript POSIX (grep)
埌読み (?<=) 可倉長も可 可ES2018+ 䞍可
名前付きグルヌプ (?<name>) (?<name>)ES2018+ 䞍可
\d の範囲 Unicode 数字党郚党角も ASCII のみ ロケヌル䟝存
文字グルヌプ枛算 [a-z-[aeiou]] あり なし なし
$ の䜍眮 末尟の \n の前にも䞀臎 末尟のみ 行末

\d が党角数字「」にも䞀臎するのは .NET 特有で、
入力チェックで想定倖の倀を通す原因になりやすい。
ASCII だけを意図するなら [0-9] ず明蚘するか、
RegexOptions.ECMAScript を指定する。

同様に $ は末尟の改行の前にも䞀臎するため、
厳密な入力チェックでは \z改行を含たない末尟を䜿う。

// "abc\n" にも䞀臎しおしたう
Regex.IsMatch(input, @"^[a-z]+$");

// 厳密
Regex.IsMatch(input, @"\A[a-z]+\z");

正芏衚珟の曞き方

正芏衚珟は、

  • 通垞の文字ず、
  • 「メタ文字」
  • 「゚スケヌプ文字」

を組み合わせお衚蚘される。

正芏衚珟の曞き方を習埗するには、これらの芁玠を芚える必芁がある。

メタ文字

特別な意味を持った蚘号。

区分

動䜜

  • 実際にどのように動䜜するかは、API オプションを理解する必芁がある。
  • API オプションの指定によっお、䞊蚘芁玠の意味が倉曎されるこずがあるため

䞀芧

以䞋が、.NET Framework の正芏衚珟で䜿甚できるメタ文字。

項番 区分 メタ文字 説明 / 泚釈
1 䜍眮指定子 䜍眮指定子 「 ^ 」、「 $ 」の䞡方を指定するこずで党文のマッチを匷制できる。
゚スケヌプ文字に含たれる䜍眮指定子もある。
1-1 䜍眮指定子 ^ 文字列の先頭を衚す䞭間からのマッチを拒吊
※ 正芏衚珟、郚分匏の先頭のものしかメタ文字ずしお認識されない。
1-2 䜍眮指定子 $ 文字列の末尟を衚す䞭間からのマッチを拒吊
※ 正芏衚珟、郚分匏の終端のものしかメタ文字ずしお認識されない。
2 代替構成䜓 代替構成䜓 詳现は代替構成䜓を参照
2-1 代替構成䜓 | 「 | 」 で区切られた文字列のいずれか。
通垞、䞋蚘、5-2 の䞞括匧ず䜵甚するが、単独で利甚するこずも可胜。
3 量指定子 量指定子 正芏衚珟での量指定子
https://learn.microsoft.com/ja-jp/dotnet/standard/base-types/quantifiers-in-regular-expressions
3-1 量指定子 * 前の文字列が 0 回以䞊連続にマッチする = {0,}。
3-2 量指定子 + 前の文字列が 1 回以䞊連続にマッチする = {1,}。
3-3 量指定子 ? 前の文字列が 0 or 1 回マッチする = {0,1}。
3-4 量指定子 {n} 前の文字列が回連続にマッチする。
3-5 量指定子 {n,} 前の文字列が回以䞊連続にマッチする。
3-6 量指定子 {n, m} 前の文字列が-回連続にマッチする。
3-7 量指定子 *? ,etc. *、+、?、{ } の埌に「 ? 」を぀けお「最短マッチ」を衚す。
4 文字クラス 文字クラス 正芏衚珟での文字クラス
https://learn.microsoft.com/ja-jp/dotnet/standard/base-types/character-classes-in-regular-expressions
4-1 文字クラス .ピリオド 改行\n以倖の任意の文字
4-2 文字クラス [ ]角括匧 䞋蚘、5-1 に該圓
4-3 文字クラス \s スペヌスやタブなどの空癜文字
4-4 文字クラス \S \s 以倖[^\s] ず同矩
4-5 文字クラス \d 10 進数[0-9] ず同矩
4-6 文字クラス \D \d 以倖[^\d] ず同矩
4-7 文字クラス \w 単語に䜿甚される任意の文字
[\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}\p{Lm}] ず同矩
4-8 文字クラス \W \w 以倖[^\w] ず同矩
5 括匧
5-1 括匧 [ ] 角括匧
詳现は「角括匧による文字グルヌプ」を参照。
䞋蚘の角括匧内に指定した文字にマッチする。
・文字範囲Unicode の文字コヌド衚、
・文字グルヌプ
以䞋は、角括匧内でのみ䜿われる特殊なメタ文字である。
・「 - 」範囲指定、䟋えば [a-z] で半角英小文字の文字グルヌプを衚す。
・「 ^ 」先頭で䜿われたずき、「含たれない」ず条件を反転する。
5-2 括匧 ( ) 䞞括匧
詳现は「䞞括匧による構成䜓」を参照
䞞括匧内に指定した文字、文字範囲、文字グルヌプに完党にマッチする。
グルヌプ化構成䜓、代替構成䜓、その他の構成䜓を構成する。
6 日本語文字クラス\p{xxxx} 日本語文字クラス .NET TIPS 文字列のひらがなカタカナをチェックするには - C# - IT
http://www.atmarkit.co.jp/fdotnet/dotnettips/054iskana/iskana.html
6-1 日本語文字クラス \p{IsHiragana} 平仮名
6-2 日本語文字クラス \p{IsKatakana} 片仮名
6-3 日本語文字クラス \p{IsCJKUnifiedIdeographs} 挢字
6-4 日本語文字クラス \P{xxxx} \p{xxxx} 以倖

移行メモ衚の展開: 原文は PukiWiki のセル結合> / ~を
䜿甚しおいたが、GitHub Markdown にセル結合が無いため、
同じ倀を展開しお掲茉した。
たた、4-4 の説明「\S 以倖」は \s 以倖の誀蚘、
6-4 の「P{xxxx}」は \P{xxxx} の衚蚘挏れず刀断し修正した。

補足\d \w は Unicode 党䜓を指す: 前述の通り、
.NET の既定では

  • \d 
 [0-9] だけでなく、党角数字・アラビア数字なども含む
  • \w 
 日本語の挢字・かなも「単語構成文字」に含む

衚の「\d は [0-9] ず同矩」ずいう蚘述は
RegexOptions.ECMAScript を指定した堎合に限っお正しい。
既定では同矩ではない点に泚意する。

゚スケヌプ文字

゚スケヌプ文字 には次のようなものがある。

項番 区分 文字の゚スケヌプ 説明 / 泚釈
1 䜍眮指定子 䜍眮指定子
1-1 䜍眮指定子 \b ワヌドの境界\w 文字ず \W 文字の間。
䟋えば「\bVB\b」で単語ずしおの「VB」ずなる。
既定では日本語ず英語の境界は「\b」に含たれない。
埓っお、「\bVB\b」ずいう正芏衚珟で、
「これは、VB です」ずいう文字列䞭の VB を怜玢できない。
ただし、これに぀いおは、ECMAScript オプションで動䜜を倉曎できる。
角括匧の䞭にある堎合、眮換パタヌンの堎合は、䞋蚘、3-2 を参照。
1-2 䜍眮指定子 \B \b 以倖
1-3 䜍眮指定子 \A Multiline オプションを無芖した文字列の先頭
1-4 䜍眮指定子 \z Multiline オプションを無芖した文字列の末尟
1-5 䜍眮指定子 \Z Multiline オプションを無芖した文字列の末尟たたは文字列の末尟の「\n」の前
1-6 䜍眮指定子 \G 前回の䞀臎が終了した䜍眮で䞀臎する必芁があるこずを指定する。
2 メタ文字の゚スケヌプ メタ文字の゚スケヌプ 単玔に、前に \ 蚘号を付䞎する。
2-1 メタ文字の゚スケヌプ \. .
2-2 メタ文字の゚スケヌプ \^ ^
2-3 メタ文字の゚スケヌプ \$ $
2-4 メタ文字の゚スケヌプ \* *
2-5 メタ文字の゚スケヌプ \+ +
2-6 メタ文字の゚スケヌプ \? ?
2-7 メタ文字の゚スケヌプ \[ [
2-8 メタ文字の゚スケヌプ \] ]
2-9 メタ文字の゚スケヌプ \( (
2-10 メタ文字の゚スケヌプ |゚スケヌプ |
2-11 メタ文字の゚スケヌプ \) )
2-12 メタ文字の゚スケヌプ \{ {
2-13 メタ文字の゚スケヌプ \} }
2-14 メタ文字の゚スケヌプ \\ \
3 制埡文字 制埡文字 各皮 制埡文字を正芏衚珟䞭の文字列で衚す堎合。
3-1 制埡文字 \a ベルアラヌムの \u0007
3-2 制埡文字 \b 角括匧の䞭にある堎合、眮換パタヌンの堎合は、\u0008
3-3 制埡文字 \t タブの \u0009
3-4 制埡文字 \r キャリッゞ リタヌンの \u000D
3-5 制埡文字 \v 垂盎タブの \u000B
3-6 制埡文字 \f フォヌム フィヌドの \u000C
3-7 制埡文字 \n 改行文字の \u000A
3-8 制埡文字 \e ゚スケヌプ文字の \u001B
3-9 制埡文字 \cC ASCII 制埡文字 ず䞀臎\cC は Ctrl + C
http://ja.wikipedia.org/wiki/ASCII#ASCII.E5.88.B6.E5.BE.A1.E6.96.87.E5.AD.97
4 コヌドポむント コヌドポむント 各皮 コヌドポむントを正芏衚珟䞭の文字列で衚す堎合。
4-1 コヌドポむント \040 8 進数3 桁たでで衚される ASCII 文字ず䞀臎
4-2 コヌドポむント \x20 16 進数2 桁で衚される ASCII 文字ず䞀臎
4-3 コヌドポむント \u0020 16 進数(4 桁)で衚される Unicode 文字ず䞀臎

補足\b が日本語で効かない理由: 衚の 1-1 が述べる通り、
\b は「\w ず \W の境界」である。
既定では日本語かな・挢字も \w に含たれるため、
「これは、VB です」の「、VB で」の郚分に境界が生たれない。

RegexOptions.ECMAScript を指定するず \w が
[a-zA-Z_0-9] に狭たるため、日本語ずの境界が \b になる。

ただし ECMAScript オプションは
同時に指定できるオプションが限られるIgnoreCase、Multiline、
Compiled のみため、副䜜甚に泚意する。
代替ずしお、明瀺的に境界を曞く方法もある。

// ECMAScript を䜿わずに「前埌が英数字でない VB」を探す
Regex.IsMatch(s, @"(?<![a-zA-Z0-9])VB(?![a-zA-Z0-9])");

補足C# のリテラルでの゚スケヌプ: 正芏衚珟の \ は、
C# の文字列リテラルでも \ が゚スケヌプ文字であるため、
二重に゚スケヌプが必芁になり読みにくくなる。

var a = "\\d+";              // 通垞の文字列リテラル読みにくい
var b = @"\d+";              // 逐語的文字列リテラル掚奚
var c = """\d+""";           // 生文字列リテラルC# 11+。" も曞ける

@"" を䜿うのが定石。" を含むパタヌンでは
C# 11 の生文字列リテラル """...""" が䟿利である。

角括匧による文字グルヌプ

角括匧を䜿甚した文字グルヌプの定矩には次のようなものがある。

※ 䞋蚘の、ChnCh1、Ch2、Ch3、Ch4 などは文字を衚す。
xx_ChGroupBase_ChGroup、Excluded_ChGroupは文字グルヌプを衚す。

文字の連結

[Ch1Ch2]

文字範囲範囲指定

[Ch1-Ch2]

文字範囲の連結

[Ch1-Ch2Ch3-Ch4]

文字グルヌプ枛算匏

[Base_ChGroup-[Excluded_ChGroup]]

.etc

文字グルヌプず文字クラスの枛算匏

[\p{xxxx}-[Excluded_ChGroup]]
[Base_ChGroup-[Ch1-Ch2\p{xxxx}]]

, etc.

補足文字グルヌプ枛算は .NET 独自: [a-z-[aeiou]]
英小文字から母音を陀くずいう枛算匏は .NET 固有の機胜であり、
JavaScript や Java には無い。
移怍性が芁る堎面では、吊定先読みで代替する。

.NET       [a-z-[aeiou]]
汎甚       (?![aeiou])[a-z]

䞞括匧による構成䜓

䞞括匧を䜿甚した

に぀いお説明する。

グルヌプ化構成䜓

  • グルヌプ化構成䜓は、正芏衚珟の郚分匏を衚すグルヌプ化。

  • 正芏衚珟にマッチした箇所はキャプチャされ、
    キャプチャ文字列ずしお、プログラム䞭で利甚できる。

  • このグルヌプ化構成䜓によるグルヌプ化よっお、
    正芏衚珟にマッチした箇所を郚分的にキャプチャするこずもできる。

  • 以䞋の衚は、

    • グルヌプ化構成䜓の䞀芧で、衚䞭の「expression」は、正芏衚珟の郚分匏を意味する。
項番 区分 グルヌプ化構成 説明 / 正芏衚珟の䟋 マッチする郚分文字列 / キャプチャ文字列
1 グルヌプ化
1-1 グルヌプ化 (expression) グルヌプ化する箇所䞞括匧内をキャプチャする。
1-1 グルヌプ化 (expression) "倧森(侀郎|二郎)" 倧森䞀郎たたは 倧森二郎 にマッチ
1-1 グルヌプ化 (expression) キャプチャ文字列 倧森䞀郎、倧森二郎以倖に䞀郎、二郎が远加でキャプチャされる。
1-2 グルヌプ化 (?:expression) グルヌプ化する箇所䞞括匧内をキャプチャしない。
1-2 グルヌプ化 (?:expression) "倧森(?:侀郎|二郎)" 倧森䞀郎たたは 倧森二郎 にマッチ
1-2 グルヌプ化 (?:expression) キャプチャ文字列 倧森䞀郎、倧森二郎がキャプチャされ、䞀郎、二郎はキャプチャされない
1-3 グルヌプ化 (?<name>expression)
※ < > は ' でも良い。
グルヌプ化する箇所名前を付けお䞞括匧内をキャプチャする。
1-3 グルヌプ化 (?<name>expression) "倧森(?<name>侀郎|二郎)" 倧森䞀郎たたは 倧森二郎 にマッチ
1-3 グルヌプ化 (?<name>expression) キャプチャ文字列 倧森䞀郎、倧森二郎以倖に䞀郎、二郎が远加でキャプチャされる。
※ このキャプチャ文字列は、グルヌプ名nameを䜿甚しお参照できる。
1-4 グルヌプ化 (?imnsx-imnsx: expression) 指定したAPI オプションを郚分匏に適甚imnsx の郚分たたは無効-imnsx の郚分にする。
正芏衚珟のAPI オプション
https://learn.microsoft.com/ja-jp/dotnet/standard/base-types/regular-expression-options
1-5 グルヌプ化 (?<name1-name2>expression) グルヌプ定矩を均等化する。
1-6 グルヌプ化 (?>expression) 非バックトラッキング郚分匏。
2 先読み・埌読み(戻り読み)
2-1 先読み (?=expression) 盎埌にこのパタヌンが珟れるこずを確認する。
2-1 先読み (?=expression) "\d+(?=%)" 埌ろに「%」が続く数字の連続にマッチ
2-1 先読み (?=expression) キャプチャ文字列 「%」の郚分はキャプチャされない。䟋えば 100% で 100 がキャプチャされる。
2-2 埌読み (?<=expression) 盎前にこのパタヌンが珟れるこずを確認する。
2-2 埌読み (?<=expression) "(?<=\\)\d+" 「\」に続く数字の連続にマッチ。
2-2 埌読み (?<=expression) キャプチャ文字列 「\」の郚分はキャプチャされない。䟋えば \100 で 100 がキャプチャされる。
2-3 吊定先読み (?!expression) 盎埌にこのパタヌンが珟れないこずを確認する。
2-3 吊定先読み (?!expression) "\d+(?![\d%])" 埌ろに「%」が続かない数字の連続にマッチ。
2-3 吊定先読み (?!expression) キャプチャ文字列 「%」の郚分はキャプチャされない。䟋えば 100KS で 100 がキャプチャされる。
2-4 吊定埌読み (?<!expression) 盎前にこのパタヌンが珟れないこずを確認する。
2-4 吊定埌読み (?<!expression) "(?<![\d\\])\d+" 「\」に続かない数字の連続にマッチ。
2-4 吊定埌読み (?<!expression) キャプチャ文字列 「\」の郚分はキャプチャされない。䟋えば $100 で 100 がキャプチャされる。

移行メモ: 原文はセル結合ず &color() による
「リテラル䞭の \ の゚スケヌプ」の匷調を甚いおいたが、
GitHub Markdown ではいずれも衚珟できないため、
セルを展開し、正芏衚珟はコヌド衚蚘に眮き換えた
\\ は C# リテラル䞭での゚スケヌプを衚す。

補足(?:) ず (?>) の実務䞊の䟡倀:

  • (?:expression)非キャプチャ
    キャプチャ䞍芁なグルヌプには必ず付ける。
    グルヌプ番号がずれるのを防ぎ、性胜も良くなる。

  • (?>expression)アトミック グルヌプ
    䞀床マッチした箇所を埌戻りバックトラックさせない。
    埌述の性胜問題ReDoSの䞻芁な察策である。

危険   (a+)+$          → バックトラックが爆発する
安党   (?>a+)+$        → 埌戻りしないので爆発しない
  • グルヌプ番号
    キャプチャ文字列には、其々グルヌプ番号が䞎えられる。
    • 正芏衚珟にマッチした箇所党䜓のキャプチャ文字列は、グルヌプ番号ずなる。

    • グルヌプ化により、远加でキャプチャされるキャプチャ文字列のグルヌプ番号には、
      グルヌプの䜍眮順巊から右にから始たる番号が䞎えられる。

    • 䟋えば

      • "(ab)(cd)(ef)" ずいう正芏衚珟にマッチした堎合、
<----------0---------->
( a b ) ( c d ) ( e f )
<--1--> <--2--> <--3-->
- 各グルヌプのキャプチャ文字列に割り圓おられる番号は次のようになる。
入力  xxxabcdefxxx
・グルヌプ0  abcdef
・グルヌプ1  ab
・グルヌプ2  cd
・グルヌプ3  ef

移行メモ誀蚘: 原文の「・グルヌプ1  ad」は、
正芏衚珟 (ab) に察応するので ab の誀蚘ず刀断し修正した。

  • 入れ子にグルヌプ化された堎合、
    グルヌプのキャプチャ文字列に割り圓おられる番号は、
    倖偎から内偎に順にから始たる番号が䞎えられる。

  • 䟋えば

    • "(a(b(c)(d)(e(f))))" ずいう正芏衚珟にマッチした堎合、
<----------------0---------------->
( a ( b ( c ) ( d ) ( e ( f ) ) ) )
                        <-6->
        <-3-> <-4-> <----5---->
    <-------------2------------->
<----------------1---------------->
- 各グルヌプのキャプチャ文字列に割り圓おられる番号は次のようになる。
入力  xxxabcdefxxx
・グルヌプ0  abcdef
・グルヌプ1  abcdef
・グルヌプ2  bcdef
・グルヌプ3  c
・グルヌプ4  d
・グルヌプ5  ef
・グルヌプ6  f

移行メモ誀蚘: 原文は最埌の 2 行がいずれも
「・グルヌプ5」ずなっおいたが、図からグルヌプ6が正しいず刀断し修正した。

  • なお、グルヌプ番号は、グルヌプ名の付䞎の圱響を受けない。

移行メモ正誀: 最埌の䞀文「グルヌプ番号は、グルヌプ名の付䞎の
圱響を受けない」は、.NET では成り立たない。

.NET では、

  1. 番号付きグルヌプ無名に先に 1 から採番され、
  2. その埌で、名前付きグルヌプに続きの番号が採番される。
var m = Regex.Match("abc", @"(?<x>a)(b)(?<y>c)");
// グルヌプ1 = "b"    ← 無名グルヌプが先
// グルヌプ2 = "a"    ← 名前付きは埌回し
// グルヌプ3 = "c"

番号ず名前を混圚させるず、番号がずれる。
混圚させる堎合は

  • 番号で参照しない名前で参照する、たたは
  • RegexOptions.ExplicitCapture で無名グルヌプのキャプチャを止める、

のいずれかを培底するのが安党である。

代替構成䜓

  • 代替構成䜓は、遞択、条件分岐を衚す。
項番 代替構成䜓 説明 / 正芏衚珟の䟋 マッチする郚分文字列 / キャプチャ文字列
1 (?(expression1)expression2) expression1 に䞀臎した堎合、そこから expression2 で怜玢
1 (?(expression1)expression2) "(?(^倧森).*郎(\r?\n|$))" 倧森䞀郎、倧森二郎、倧森䞉郎、などの行
1 (?(expression1)expression2) キャプチャ文字列 先頭が「倧森」の堎合、末尟が「xxx 郎」の行があれば、その行がキャプチャされる。
2 (?(expression)yes_exp|no_exp) expression に䞀臎した堎合、そこから yes_exp で怜玢
䞀臎しなかった堎合、そこから no_exp で怜玢
2 (?(expression)yes_exp|no_exp) "(?(^倧森).*郎(\r?\n|$)|^品川.*郎(\r?\n|$))" 倧森䞀郎、倧森二郎、倧森䞉郎、品川䞀郎、品川二郎、品川䞉郎、などの行
2 (?(expression)yes_exp|no_exp) キャプチャ文字列 先頭が「倧森」の堎合、末尟が「xxx 郎」の行があれば、その行がキャプチャされる。
たた、先頭が「倧森」でない堎合、先頭「品川」末尟「xxx 郎」の行がキャプチャされる。
3 (?(name)yes_exp|no_exp) 割愛

その他の構成䜓

その他の構成䜓は、正芏衚珟を倉曎する郚分匏API オプション、コメントなどを衚す。

項番 その他の構成䜓 説明
1 (?imnsx-imnsx) パタヌンの途䞭でAPI オプションを適甚imnsx の郚分たたは無効-imnsx の郚分にする。
2 (?# ) 正芏衚珟に挿入するむンラむン コメント。コメントは、最初の右かっこ文字で終了する。
3 #行末たで X モヌド コメント。コメントは行末たで継続する。
このコメントを認識させるには、以䞋の䜕れかのAPI オプションを有効にする。
・x オプション
・IgnorePatternWhitespace オプション

キャプチャの利甚

で参照利甚できる。

぀いお説明する。

前埌方参照

前埌方参照は、぀連続する文字文字グルヌプのパタヌンを怜玢する堎合などに䜿甚する。

  • 前埌方参照には、以䞋の぀の前埌方参照構成䜓を䜿甚する方法がある。

    • グルヌプ番号\number

      • 「\1」から「\9」たでの匏は垞に前埌方参照を衚し、8 進の ASCII コヌドにはならない。
      • 「\11」以降の耇数桁の匏は、その番号に察応する前埌方参照がある堎合には、前埌方参照ず芋なされる。
      • それ以倖の堎合は、8 進の ASCII コヌドず解釈される。
        ただし、先頭の桁が 8 たたは 9 の堎合を陀く。
        その堎合はリテラルの "8" および "9" ずしお扱われる。
    • グルヌプ名\k<name>

  • 正芏衚珟の䞭に、未定矩のグルヌプ番号ぞの前埌方参照が含たれる堎合は、
    解析゚ラヌず芋なされる。曖昧さが問題ずなる堎合は、名前を䜿甚しお前埌方参照する。

  • 䞋蚘は、

    • ぀連続する文字文字グルヌプのパタヌンを怜玢する「前埌方参照」を䜿甚した正芏衚珟の䟋である。

    • 「前埌方参照」を䜿甚した正芏衚珟の䟋

      • ぀連続する文字のパタヌンを怜玢する
グルヌプ番号を䜿甚 グルヌプ名を䜿甚
正芏衚珟 前埌方参照 "(\S)\1" "(?<ch>\S)\k<ch>"
- ぀連続する文字グルヌプのパタヌンを怜玢する
グルヌプ番号を䜿甚 グルヌプ名を䜿甚
正芏衚珟 前埌方参照 "\b(\S+)\s+\1\b" "\b(?<str>\S+)\s+\k<str>\b"

移行メモ誀蚘: 原文の芋出し「぀連続する文字クルヌプ」は
文字グルヌプの誀字ず刀断し修正した。

文字列眮換

  • 文字列眮換は、

    • 正芏衚珟にマッチした箇所のキャプチャ文字列を䜿甚しお、
      文字列の眮換付加、削陀、曞匏倉曎などを行うこずができる。
    • APIを䜿甚しお、正芏衚珟、眮換パタヌン、API オプションを指定しお、
      付加、削陀、曞匏倉曎などの凊理を実行できる。
  • 眮換パタヌンに指定する眮換構成䜓には、次のものがある。

項番 眮換構成䜓 説明
1 $number グルヌプ番号ず䞀臎した郚分文字列
2 ${name} グルヌプ名nameず䞀臎した最埌の郚分文字列
3 $& 䞀臎したパタヌン党䜓の文字列
4 $+ キャプチャされた最埌の文字列
5 $_ 入力文字列党䜓
6 $` 䞀臎した堎所より前にある入力文字列
7 $' 䞀臎した堎所より埌にある入力文字列
8 $$ 単䞀の "$" リテラル゚スケヌプ
  • 次に、正芏衚珟による文字列眮換の䟋を瀺す。

    • 付加
      • HTML 䞭の URL にリンクを付ける。
        ※ 正芏衚珟にマッチした箇所党䜓のキャプチャ文字列は、眮換構成䜓「$0」でも「$&」でも参照できる。
版 版
正芏衚珟 "s?https?://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+" 同巊
眮換パタヌン "<a href=\"$0\">$0</a>" "<a href=\"$&\">$&</a>"

補足この眮換は実務では危険: 䞊蚘のような「URL を芋぀けお
<a> タグに倉換する」眮換は、そのたた HTML に出力するず
XSS の枩床になる
。

  • 元の文字列に含たれる < > " & を先に゚スケヌプしおいない
  • javascript: などのスキヌムを匟いおいない

珟圚は、HTML の生成に正芏衚珟を䜿わないのが原則であり、
Razor の @ 出力自動゚スケヌプや
HtmlSanitizer のようなラむブラリを䜿う。

- 文曞䞭の行頭に匕甚蚘号を挿入する。\
  ※ 正芏衚珟に䜍眮指定子アトミック れロ幅アサヌションを単独で䜿甚した堎合もキャプチャ → 眮換ができる。
文字列
正芏衚珟 "^"
眮換パタヌン "> "
  • 削陀
    • 文曞䞭の行末の空癜文字を削陀する。
      ※ 削陀する堎合、眮換パタヌンに空文字列を指定する。
      ※ 実行時、Multiline オプションを蚭定する必芁がある。
文字列
正芏衚珟 "[ \t]+(?=\r?\n|$)"
眮換パタヌン "" (空文字列)
- 無効な文字を削陀する。\
  ※ 削陀する堎合、眮換パタヌンに空文字列を指定する。\
  ※ `@`、`-` (ハむフン)、および `.` (ピリオド) 以倖のすべおの非英数文字を取り陀いた文字列を返す。
文字列
正芏衚珟 "[^\w\.@-]"
眮換パタヌン "" (空文字列)
- 文曞䞭の連続する同じ行を削陀する。\
  ※ 䞊蚘は、[前埌方参照](#前埌方参照)を䜵甚しおいる。\
  ※ 実行時、Multiline オプションを蚭定する必芁がある。
グルヌプ番号を䜿甚 グルヌプ名を䜿甚
正芏衚珟 "^(.*)(\r?\n\1)+$" "^(?<line>.*)(\r?\n\k<line>)+$"
眮換パタヌン "$1" "${line}"
  • 曞匏倉曎
    • 日付のフォヌマットを倉曎する
      ※ 文章䞭から怜玢、倉換する堎合は、前埌に「\b」を付䞎する必芁がある。
       たた、日本語文章䞭の堎合は、実行時、ECMAScript オプションを蚭定する必芁がある。
グルヌプ名を䜿甚
正芏衚珟 "(?<year>\d{2,4})/(?<month>\d{1,2})/(?<day>\d{1,2})"
眮換パタヌン "${year}幎${month}月${day}日"
  • 日付のフォヌマットを倉曎する
    ※ 文章䞭から怜玢、倉換する堎合は、前埌に「\b」を付䞎する必芁がある。
     たた、日本語文章䞭の堎合は、実行時、ECMAScript オプションを蚭定する必芁がある。
グルヌプ名を䜿甚
正芏衚珟 "(?<month>\d{1,2})/(?<day>\d{1,2})/(?<year>\d{2,4})"
眮換パタヌン "${day}-${month}-${year}"
  • その他、MatchEvaluator デリゲヌトを䜿甚しお眮換倉換するずいう方法もあるが、
    これに぀いおは、「API」で説明する。

最長 / 最短マッチ

デフォルトでは「最長マッチ」ずなるため、必芁に応じお「最短マッチ」を䜿甚する。

最長マッチ

  • 「最長マッチ」ずは、怜玢される文字列が最長になるように凊理するこずである。

  • 䟋えば、カギかっこ「」で囲たれた文字列を怜玢する堎合、

    • 次のように正芏衚珟を衚蚘した堎合に、
"「.*」"
  • カギかっこが耇数あった堎合、問題が起こる。
    • 䟋えば、入力文字列に、以䞋のように入力されおいるならば、
"・・・「あ」、「い」、「う」・・・"
- 怜玢される郚分文字列は、以䞋の 1 ぀だけになる。
"「あ」、「い」、「う」"
  • これを、以䞋の 3 ぀の文字列が別々に怜玢されるようにするには、最短マッチを䜿甚する。
"「あ」"、"「い」"、"「う」"

最短マッチ

  • 「最短マッチ」ずは、怜玢される文字列が最短になるように凊理するこずである。
  • 「最長マッチ」を「最短マッチ」にする堎合、以䞋のように、曞き換える必芁がある。
"「.*」" → "「.*?」"
  • ただし、䞊蚘のような䟋であれば、
    「最短マッチ」を䜿甚しなくおも、"「[^」]*」" ず曞けばほが同じこずができる。

移行メモ誀蚘: 原文の「「最短マッチ」を「最短マッチ」にする堎合」は
「最長マッチ」を「最短マッチ」にする堎合の誀蚘ず刀断し修正した。

補足最埌の䞀文が実は最重芁: 原文が「ほが同じこずができる」ず
控えめに曞いおいる **"「[^」]*」"吊定文字クラス**は、
最短マッチより望たしい曞き方である。

「.*?」 「[^」]*」
動䜜 1 文字進めおは閉じ括匧を詊すバックトラック 䞀気に読む埌戻りしない
速床 遅い 速い
ReDoS 起こり埗る 起きにくい

**「最短マッチより、吊定文字クラス」**は
正芏衚珟の性胜改善における定石である。
詳现は性胜ず ReDoSを参照。

パタヌン マッチの䟋

正芏衚珟を䜿甚したパタヌン マッチの䟋を瀺す。

メヌルアドレスを怜玢する

※ IgnoreCase倧文字ず小文字を区別しないオプションを蚭定する必芁がある。
※ 文章䞭から怜玢する堎合は、前埌に「\b」を付䞎する必芁がある。
 たた、日本語文章䞭の堎合は、実行時、ECMAScript オプションを蚭定する必芁がある。

正芏衚珟
正芏衚珟 "[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}"
正芏衚珟 "([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([A-Z]{2,4}|[0-9]{1,3})(\]?)"

補足メヌルアドレスの怜蚌に正芏衚珟を䜿わない: 原文自身も
衚珟できないケヌスがあるで
同じ趣旚を述べおいるが、珟圚の .NET には明確な代替がある。

// 掚奚MailAddress に任せるRFC に沿った解釈
bool ok = System.Net.Mail.MailAddress.TryCreate(input, out _);

// ASP.NET Core / デヌタ泚釈
[EmailAddress] public string Email { get; set; }

䞊蚘の衚の 2 番目のような長倧なパタヌンは、

  • RFC 5322 を正しく衚珟できおいない匕甚笊付きロヌカル郚など
  • TLD を {2,4} に決め打ちしおいる.museum .travel に非察応
  • バックトラックが爆発しやすいReDoS のリスク

ずいう䞉重の問題を抱える。
「圢匏が劥圓か」を厳密に刀定する意味は薄く、
最終的には確認メヌルを送るしかない
ずいうのが珟圚の合意である。

HTML 内のリンク先を怜玢する

※ 䞊蚘は、前方参照、最小マッチを䜵甚しおいる。

正芏衚珟
正芏衚珟 "href\s*=\s*(?:(?<quot>[\"'])(?<url>.*?)\k<quot>)"
→「クォヌテヌション無し」を考慮しおいない䟋。
正芏衚珟 "href\s*=\s*(?:\"(?<1>[^\"]*)\"|(?<1>\S+))"
→「シングル クォヌテヌション」を考慮しおいない䟋。

HTML 内の芋出し、<H1><H6> タグを怜玢する

※ 䞊蚘は、前方参照、最小マッチを䜵甚しおいる。
※ 実行時、Singleline「.」に、\n を含めるオプションを蚭定する必芁がある。

正芏衚珟
正芏衚珟 "<(h[1-6])\b[^>]*>(.*?)</\1>"

HTML 内のリンク、<a> タグから情報を抜出する

※ 䞊蚘は、前方参照、最小マッチを䜵甚しおいる。たた、url、text などの郚分キャプチャを行なっおいる。
※ 実行時、IgnoreCase倧 / 小文字を区別しない、Singleline「.」に、\n を含めるオプションを蚭定する必芁がある。

正芏衚珟
正芏衚珟 "<a\s+[^>]*href\s*=\s*(?:(?<quot>[\"'])(?<url>.*?)\k<quot>|(?<url>[^\s>]+))[^>]*>(?<text>.*?)</a>"

補足HTML の解析に正芏衚珟を䜿わない: 䞊蚘 3 ぀はいずれも
HTML を正芏衚珟で解析する䟋だが、これは兞型的なアンチパタヌンである。

HTML は正芏蚀語ではない入れ子構造を持぀ため、
正芏衚珟では原理的に正しく解析できない。実際、䞊蚘の䟋も

  • 属性倀䞭の >、コメント <!-- -->、<script> 内のテキスト
  • 属性の順序違い、改行を挟む属性
  • 入れ子の <h1> や䞍正な閉じタグ

で容易に砎綻する。原文も泚蚘で
「〜を考慮しおいない䟋」ず限界を明瀺しおいる通りである。

珟圚の .NET では、HTML パヌサヌを䜿う。

ラむブラリ 特城
AngleSharp W3C 準拠。CSS セレクタヌ、DOM API
HtmlAgilityPack 叀参。XPath で蟿れる。壊れた HTML に寛容
var doc = await new HtmlParser().ParseDocumentAsync(html);
var urls = doc.QuerySelectorAll("a[href]").Select(a => a.GetAttribute("href"));

「䜿い捚おのスクリプトで、入力の圢が完党に分かっおいる」堎合を陀き、
HTML には正芏衚珟を䜿わない。

URL 文字列から情報を抜出する

※ 最小マッチを䜿甚しおいる。たた、プロトコル、ポヌト番号などの郚分キャプチャを行なっおいる。

正芏衚珟
正芏衚珟 "^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/"

補足: URL の分解も、System.Uri を䜿うのが確実である。

if (Uri.TryCreate(s, UriKind.Absolute, out var uri))
{
    var proto = uri.Scheme;   // "https"
    var port  = uri.Port;     // 443省略時も既定倀が入る
    var host  = uri.Host;
}

ク゚リ文字列の解析には Microsoft.AspNetCore.WebUtilities.QueryHelpers や
System.Web.HttpUtility.ParseQueryString を䜿う。

利甚する API、オプション

正芏衚珟の凊理に利甚する API ず、そのオプションに぀いお説明する。

API

正芏衚珟にお䞭心的圹割を担うクラスにRegex クラスずMatch クラスがある。

Regex クラス

Regex クラスは、正芏衚珟パタヌンを栌玍し、パタヌン マッチングを実行するメ゜ッドを備えたクラスである。
このオブゞェクトからキャプチャ文字列の倀を取り出しお、匕き続き、「手続き型の凊理」を実装できる。

  • 以䞋に、Regex クラスの䞻芁なプロパティ / メ゜ッドを䞀芧する。
項番 区分 名前 説明
1 プロパティ
1-1 プロパティ Options Regex コンストラクタに枡されたオプションオプションを参照
2 メ゜ッド
2-1 メ゜ッド IsMatch 正芏衚珟ず䞀臎する察象が入力文字列内で芋぀かったかどうかを瀺す。
䞻に、入力チェックを実装する堎合に利甚し、入力チェックでは、
正芏衚珟の先頭ず末尟に「 ^ 」ず「 $ 」を付䞎しお䞭間からのマッチを拒吊するず良い。
2-2 メ゜ッド Match 入力文字内で正芏衚珟ず䞀臎する察象を぀怜玢し、結果をMatch オブゞェクトずしお返す。
取埗したMatch オブゞェクトの NextMatch メ゜ッド埌述が呌び出された堎合、次の結果をMatch オブゞェクトずしお返す。
2-3 メ゜ッド Matches 入力文字列内で正芏衚珟ず䞀臎する察象をすべお怜玢し、
結果の耇数のMatch オブゞェクト芋぀かった察象をすべお返すを MatchCollection ずしお返す。
2-4 メ゜ッド Replace 第䞀匕数の正芏衚珟パタヌンに䞀臎する文字列を、第二匕数の眮換パタヌンで眮換する。
第二匕数には MatchEvaluator デリゲヌトを䜿甚しお眮換倉換するこずもできる埌述。
2-5 メ゜ッド Split 入力文字列を、正芏衚珟によっお定矩されおいる䜍眮で配列に分割する。

移行メモ正誀: 2-1 の「入力チェックでは ^ ず $ を付䞎」は、
$ が末尟の \n の前にも䞀臎するため、厳密には䞍十分である
前述の方蚀を参照。
入力チェックでは \A ず \z を䜿う方が確実である。

  • オブゞェクト階局は次のようになっおいる。
    • Matches メ゜ッドで取埗できる MatchCollection オブゞェクト
    • Match メ゜ッドで取埗できるMatch オブゞェクト
オブゞェクト名                        䞋䜍オブゞェクトの取埗方法   キャプチャ文字列の詳现デヌタ
MatchCollectionオブゞェクト           むンデクサ番号
┗ Matchオブゞェクト                  Groupsプロパティ
 ┗ GroupsCollectionオブゞェクト     むンデクサ番号、名称
  ┗ Groupsオブゞェクト             Capturesプロパティ
  ┗ CaptureCollectionオブゞェクト  むンデクサ番号
   ┗ Captureオブゞェクト          各皮プロパティ
    ┣ Valuestring                                           キャプチャ文字列の倀
    ┣ Lengthint                                             キャプチャ文字列の文字列長
    ┗ Indexint                                              入力文字列を基にした䜍眮むンデックス

移行メモ誀蚘: 原文の「キャプチャ文字列の長文字列」は
文字列長の誀蚘ず刀断し修正した。

  • 其々のオブゞェクトの説明
項番 オブゞェクト名 説明
1 Match オブゞェクト 正芏衚珟により「怜玢された぀の文字列」ず察応する結果を栌玍。
2 Groups オブゞェクト 䞊蚘「怜玢文字列」のキャプチャ、グルヌプ化による远加キャプチャの情報を栌玍。
3 Capture オブゞェクト キャプチャ文字列の詳现デヌタを栌玍
  • ぀のグルヌプが耇数の文字列をキャプチャする䟋
    正芏衚珟によっおは、぀のグルヌプが耇数の文字列をキャプチャするこずがある。
    このような正芏衚珟の䟋を以䞋、説明する。

    • 正芏衚珟の䟋
正芏衚珟 "(123)(\d)+(789)"
入力文字列 "123456789-123456789"
  • 䞊蚘を実行した結果、
    以䞋のオブゞェクトが返される。
    • Match オブゞェクト぀
      ・前の "123456789" にマッチ
      ・埌ろの "123456789" にマッチ
    • Groups オブゞェクト぀
      ・党䜓123456789のキャプチャ
      ・グルヌプ 1123のキャプチャ
      ・グルヌプ 2"\d"=4のキャプチャ
      ・グルヌプ 3"\d"=5のキャプチャ
      ・グルヌプ 4"\d"=6のキャプチャ
      ・グルヌプ 5789のキャプチャ

移行メモ正誀: 原文の蚘述はやや䞍正確なので補足する。

  • 「Groups オブゞェクト぀」ずあるが、
    列挙されおいるのは 6 件であり、数が合わない。
  • たた、正芏衚珟 (123)(\d)+(789) のグルヌプは 3 ぀であり、
    グルヌプ 4・5 は存圚しない。

実際の挙動は次の通りで、たさにこれが
本節が説明しようずしおいる Captures の意矩である。

Groups[0] = "123456789"    党䜓
Groups[1] = "123"
Groups[2] = "6"            ← Value は「最埌の」キャプチャだけ
  Groups[2].Captures = ["4", "5", "6"]   ← 3 回分すべおがここに残る
Groups[3] = "789"

芁点: (\d)+ のように量指定子の付いたグルヌプは
耇数回キャプチャするが、Group.Value は最埌の 1 回しか返さない。
すべおを取り出すには Group.Captures を列挙する。
原文が「グルヌプ 2〜4」ず曞いたのは、この 3 回分の
キャプチャを指す意図だったず読める。

  • MatchEvaluator デリゲヌトを䜿甚しお眮換倉換する䟋
    • たた、Regex.Replace ( ) メ゜ッドの特殊な䜿い方に、
      MatchEvaluator デリゲヌトを䜿甚した眮換倉換方法がある。
    • これを䜿甚するず、非手続の「眮換パタヌン」を䜿甚した眮換倉換ではなく、
      手続き型蚀語C#、VBを䜿甚した眮換倉換が可胜になる。
public class Test_Regex {

  // 正芏衚珟を䜿甚しお眮換倉換するメ゜ッド
  public string Regex_Replace(string yyyymmdd)
  {
    // 日付yyyy/mm/dd圢匏を正芏衚珟を甚いお日増やす
    return Regex.Replace(yyyymmdd,
      @"(?<year>\d{4})/(?<month>\d{2})/(?<day>\d{2})",
      new MatchEvaluator(this.IncrementDay));
  }
  
  // MatchEvaluatorデリゲヌトメ゜ッド
  private string IncrementDay(Match m)
  {
    // 日付ワヌク
    DateTime dt;

    // 日付yyyy/mm/dd圢匏をDateTime型に倉換
    if (DateTime.TryParse(m.Value, out dt)) {
      // DateTimeクラスを䜿甚しお日増やし、
      // 日付yyyy/mm/dd圢匏に戻す。
      return dt.AddDays(1).ToShortDateString();
    }
    else {
      // 倉換できなかった堎合、䜕もしないで戻す。
      return m.Value;
    }
  }
}

補足MatchEvaluator は「逃げ道」ずしお重芁: 正芏衚珟だけでは
衚珟できない倉換蚈算、蟞曞匕き、条件分岐が必芁になったずき、
無理に正芏衚珟を耇雑化せず、この方匏に切り替えるのが定石である。

珟圚はラムダ匏で簡朔に曞ける。

var s = Regex.Replace(input, @"\d{4}/\d{2}/\d{2}",
    m => DateTime.TryParse(m.Value, out var d)
         ? d.AddDays(1).ToString("yyyy/MM/dd")
         : m.Value);

なお䞊蚘の原文の䟋で䜿われおいる ToShortDateString()
はカルチャ䟝存実行環境の地域蚭定で曞匏が倉わるため、
曞匏を固定したいなら ToString("yyyy/MM/dd") を明瀺する方がよい。

Match クラス

Match クラスは、Regex クラスで実行されたパタヌン マッチングの結果を栌玍するクラスである。

  • 以䞋に、Match クラスのプロパティ / メ゜ッドを䞀芧する。
項番 区分 名前 説明
1 プロパティ
1-1 プロパティ Success 䞀臎した察象が芋぀かったかどうかを瀺す bool 倀を取埗する。
䟋えば、量指定子「 * 」を指定したグルヌプ構成䜓は、芋぀からないこずが有り埗る。
1-2 プロパティ Groups 正芏衚珟による「怜玢文字列」の
・キャプチャグルヌプ、
・グルヌプ化による远加キャプチャグルヌプ  
の情報を栌玍。
1-3 プロパティ Captures グルヌプのキャプチャ
1-4 プロパティ Value グルヌプのキャプチャ文字列の倀
1-5 プロパティ Length グルヌプのキャプチャ文字列の文字列長
1-6 プロパティ Index グルヌプの入力文字列を基にした䜍眮むンデックス
2 メ゜ッド
2-1 メ゜ッド NextMatch 次の結果を Match オブゞェクトずしお返す。
2-2 メ゜ッド Result 指定された眮換パタヌンを返す結果毎に眮換パタヌンを倉曎できる。

補足アロケヌションを避ける新 API: Match / Group は
いずれも string を生成するため、倧量凊理では確保が積み䞊がる。

.NET 7 以降では、Span<char> ベヌスの API が远加されおいる。

API 内容
Regex.EnumerateMatches(ReadOnlySpan<char>) 文字列を䜜らずに䜍眮ず長さだけ列挙
Regex.Count() 䞀臎数だけを数える.NET 7+
ValueMatch Index ず Length のみを持぀構造䜓
foreach (var m in Regex.EnumerateMatches(span, pattern))
    Process(span.Slice(m.Index, m.Length));   // 文字列生成なし

オプション

以䞋、Regex クラスのオプションに぀いお説明する。
これによっお䞀郚、動䜜凊理結果が倉曎される。

項番 RegexOptions 列挙䜓のメンバ 説明
1 None オプションが䜕も蚭定されないこずを指定する。
2 ECMAScript ECMAScript 準拠の動䜜ずする。䞀郚のメタ文字の意味が倉曎される。
・ECMAScript の暙準䞀臎の動䜜
 https://learn.microsoft.com/ja-jp/dotnet/standard/base-types/regular-expression-options
3 Singleline ワむルドカヌドである .ピリオドの意味を、「\n」を含めたすべおの文字の意味に倉曎する。
4 Multiline 「^」ず「$」の意味を
・「^」「文字列の先頭」 → 「行の先頭」
・「$」「文字列の末尟」 → 「行の末尟」
に倉曎する。
「^」ず「$」の代わりに「\A」ず「\Z」を䜿甚するず、
Multiline の圱響を受けずに「文字列の先頭」、「文字列の末尟」を指定できる。
5 IgnoreCase 倧文字ず小文字を区別しない。
6 CultureInvariant 蚀語カルチャの違いを無芖する。
・RegularExpressions 名前空間でのカルチャを認識しない操䜜の実行
 https://learn.microsoft.com/ja-jp/dotnet/standard/base-types/regular-expression-options
7 RightToLeft 怜玢が巊から右→ではなく右から巊←に行われるように指定する。
8 Compiled 正芏衚珟をコンパむルしお実行速床を䞊げる。ただし、起動時間は長くなる。
・正芏衚珟におけるコンパむルず再利甚
 https://learn.microsoft.com/ja-jp/dotnet/standard/base-types/compilation-and-reuse-in-regular-expressions
9 ExplicitCapture 明瀺的に名前を指定されたグルヌプだけが有効なキャプチャであるこずを指定する。
10 IgnorePatternWhitespace ・正芏衚珟のパタヌン内にコメント文を蚘述するにはC#、VB - IT
 http://www.atmarkit.co.jp/fdotnet/dotnettips/582regexcomment/regexcomment.html

補足珟圚远加されたオプション最新化: 䞊蚘に加えお、
珟圚は次の 2 ぀が重芁である。

オプション 内容
NonBacktracking.NET 7+ バックトラックしない゚ンゞンを䜿う。ReDoS を原理的に防ぐ
RegexOptions.Compiled 珟圚も有効だが、゜ヌス生成の方が䞊䜍

NonBacktracking は入力長に察しお線圢時間を保蚌する
オヌトマトン方匏の゚ンゞンを䜿う。
ただし埌方参照・先読み/埌読みが䜿えないずいう制玄がある。

// 信頌できない入力を扱うなら、これが最も安党
new Regex(pattern, RegexOptions.NonBacktracking);

補足[GeneratedRegex]珟圚の掚奚圢最新化: .NET 7 以降、
゜ヌス ゞェネレヌタヌによる正芏衚珟が䜿える。

public partial class Validator
{
    [GeneratedRegex(@"\A[a-z0-9_]+\z", RegexOptions.IgnoreCase)]
    private static partial Regex UserName();

    public bool IsValid(string s) => UserName().IsMatch(s);
}
方匏 生成タむミング 起動 実行 AOT
new Regex(...)解釈 実行時 速い 遅い ○
RegexOptions.Compiled 実行時に IL 生成 遅い 速い ×
[GeneratedRegex] コンパむル時に C# 生成 速い 速い ○

[GeneratedRegex] が党面的に優れおいる
起動が速く、実行も速く、トリミング/Native AOT でも動き、
生成された C# コヌドをデバッグで远える。
静的なパタヌンには、これを䜿うのが珟圚の第䞀候補である。

なお、動的に組み立おるパタヌンには䜿えないため、
その堎合は Regex むンスタンスをstatic フィヌルドにキャッシュする
毎回 new する、あるいは静的メ゜ッド Regex.IsMatch(s, pattern) を
ルヌプ内で呌ぶのは避ける。

性胜ず ReDoS

補足原文に無い節。珟圚は必須の知識: 本ペヌゞ執筆時点では
話題になっおいなかったが、正芏衚珟には
**ReDoSRegular expression Denial of Service**ずいう
セキュリティ䞊の問題がある。

原理: バックトラック型の゚ンゞンは、
䞀臎しない入力に察しおすべおの分割を詊すこずがあり、
入力長に察しお指数関数的に時間がかかる堎合がある。

// 危険なパタヌン「入れ子の量指定子」
var re = new Regex(@"^(a+)+$");
re.IsMatch(new string('a', 30) + "!");   // 数十秒〜フリヌズ

a が 1 個増えるごずに詊行回数が倍増する。
攻撃者が入力を送れる箇所フォヌム、URL、ヘッダヌで
このようなパタヌンを䜿うず、CPU を占有されおサヌビスが止たる。

危険なパタヌンの兆候:

圢 䟋
入れ子の量指定子 (a+)+、(a*)*、(.*)*
重なり合う遞択肢 (a|a)*、(a|ab)+
最短マッチ + 貪欲の混圚 .*?.*

察策䞊から順に怜蚎する:

察策 内容
そもそも正芏衚珟を䜿わない メヌル→MailAddress、URL→Uri、HTML→パヌサヌ
RegexOptions.NonBacktracking 線圢時間を保蚌.NET 7+
タむムアりトを蚭定する new Regex(p, opts, TimeSpan.FromSeconds(1))
吊定文字クラスを䜿う .*? より [^"]*
アトミック グルヌプ (?>a+)+ で埌戻りを犁止
入力長を制限する 怜蚌前に長さで匟く

タむムアりトの指定は、倖郚入力を扱うすべおの Regex で
事実䞊必須
である。指定がないず既定は無限InfiniteMatchTimeout。

private static readonly Regex _re =
    new(pattern, RegexOptions.None, TimeSpan.FromMilliseconds(200));

超過するず RegexMatchTimeoutException が送出されるので、
捕捉しお「䞍正な入力」ずしお扱う。

なお、原文のたずめが指摘する
「劥圓性の怜蚌が困難」ずいう論点は、
この ReDoS の存圚によっお䞀局重みを増しおいる。
「動くこず」だけでなく「䞀臎しない入力で暎走しないこず」も
テストの察象になる。

たずめ

正芏衚珟により解決できる点

正芏衚珟を䜿甚するず、高床な、

  • 入力チェック
  • 党文怜玢
  • 眮換付加、削陀、曞匏倉曎
  • 文字列分割

などの凊理を、高い生産性で実装するこずができる。

正芏衚珟により解決できない点

ただし、以䞋の点は、正芏衚珟により解決できない。

劥圓性の怜蚌が困難

以䞋のように難解なため、劥圓性の怜蚌が困難である。

  • 蚘述凊理の実装ステップ数は、短かくなるが、

    • 正芏衚珟を習埗する必芁がある。
    • アサむンする技術者には正芏衚珟の知識が必芁になる。
  • 「非手続き蚀語」の特城ずしお、開発したステップ数に察するテスト ケヌスが倚い。

    • それを怜蚌するテスト工数の削枛はできないし、
    • テストケヌスが網矅的であるかどうか、カバレヌゞを指暙に利甚できない。

補足この指摘は珟圚も有効: 「1 行のコヌドだが、
カバレッゞでは 1 行ずしおしか数えられない」ずいう指摘は本質的である。

緩和策ずしおは、

手段 内容
IgnorePatternWhitespace でコメントを曞く パタヌン自䜓を読めるようにする
[GeneratedRegex] 生成コヌドをステップ実行で远える
境界倀のテストを明瀺的に列挙 䞀臎する䟋・䞀臎しない䟋の䞡方
regex101.com 等での可芖化 マッチ過皋を確認する
// x モヌドパタヌンにコメントを入れる
[GeneratedRegex("""
    \A                 # 先頭
    (?<user>[\w.+-]+)  # ロヌカル郚
    @
    (?<host>[\w-]+(\.[\w-]+)+)  # ドメむン
    \z                 # 末尟
    """, RegexOptions.IgnorePatternWhitespace)]
private static partial Regex Mail();

衚珟できないケヌスがある

  • 「手続き蚀語」で実装しないず衚珟できないケヌスもある。
    䟋えば、メヌル フォヌマット チェックなどを䟋に挙げお説明するず、
    • RFC に準拠したメヌル アドレスだけ蚱可するのか
    • 携垯メヌルなどに芋られる RFC 非準拠のメヌル アドレスも蚱可するのか
    • たた、電子メヌルの配送先 IP アドレスの盎接指定を蚱可するのかなど。

利䟿性ず汎甚的の䞡立は䟝然ずしお困難

  • 正芏衚珟は、
    • 入力チェック凊理や、
    • 眮換曞匏倉曎などの

共通凊理を、比范的容易に開発できる。

  • しかし、利䟿性ず汎甚性を䞡立する API 仕様を怜蚎するこずは倉わらず難しい。
    このため、匷床を䞊げるなら、汎甚性を犠牲にする以倖に方法が無い。

補足結論: 本ペヌゞ党䜓を通じた実務䞊の指針を纏める。

  1. 専甚の型があるものには、正芏衚珟を䜿わない
    メヌル → MailAddress、URL → Uri、日付 → DateTime.TryParse、
    HTML/XML/JSON → 各パヌサヌ
  2. 静的なパタヌンは [GeneratedRegex]
  3. 倖郚入力を扱うなら、タむムアりトか NonBacktracking
  4. .*? より吊定文字クラス [^x]*
  5. キャプチャ䞍芁なら (?:)、名前ず番号を混ぜない
  6. 䞀臎しない入力のテストを曞く性胜も含めお

参考

Microsoft Learn


Tags: 移行, .NET開発, その他、開発の色々

⚠ **GitHub.com Fallback** ⚠