原則として、正規表現は左端の最も長い ruleに従って一致し、その正式な表現 (Posix 標準から) は次のとおりです。
検索は、文字列の可能なすべてのサフィックスがパターンに一致するプレフィックスについてテストされたかのように実行されます。一致するプレフィックスを含む最長のサフィックスが選択され、選択されたサフィックスの可能な最長の一致するプレフィックスが一致するシーケンスとして識別されます。
あなたの 3 つの可能性はそれぞれ、前の可能性の拡張です。3番目で最も長いものから始めます:
[A-Z]{2,3}-[A-Z][A-Z0-9]{1,2}-[A-Z0-9]{2,3}
これには 3 つのコンポーネントがあり、それぞれが独自の正規表現です。
[A-Z]{2,3}
-[A-Z][A-Z0-9]{1,2}
-[A-Z0-9]{2,3}
まず、それぞれをグループ化する必要があります。
([A-Z]{2,3})
(-[A-Z][A-Z0-9]{1,2})
(-[A-Z0-9]{2,3})
次に、最後の 2 つを組み合わせて、より長い正規表現にすることができます。
([A-Z]{2,3})
(-[A-Z][A-Z0-9]{1,2})(-[A-Z0-9]{2,3})
2 番目のセグメントがある場合、3 番目のセグメントはオプションであることに注意してください。そうするために:
([A-Z]{2,3})
(-[A-Z][A-Z0-9]{1,2})(-[A-Z0-9]{2,3})?
次に、2 番目のコンポーネント全体をグループ化して、それが不可欠な部分であることを示します。
([A-Z]{2,3})
((-[A-Z][A-Z0-9]{1,2})(-[A-Z0-9]{2,3})?)
最初のコンポーネントがある場合、その 2 番目のコンポーネント全体がオプションであるため、接尾辞演算子を使用してオプションであること?
を示します。
([A-Z]{2,3})
((-[A-Z][A-Z0-9]{1,2})(-[A-Z0-9]{2,3})?)?
最後に、2 つの正規表現を連結して最終的な表現を作成します。
([A-Z]{2,3})((-[A-Z][A-Z0-9]{1,2})(-[A-Z0-9]{2,3})?)?
ほらね。正規表現エンジンでは、後戻りがなく、最小限の先読みが必要です。
以下のOPのコメントから、目的の一致は文字列全体であるように見えます。そう...
デフォルトでは、正規表現はソース文字列の左端で最も長い一致を見つけます。文字列全体または行全体と一致させたい場合は、式をメタパターンで固定する必要があります^
。これにより、一致がその位置で行頭に$
固定され、一致がその位置で行末に固定されます。 . そう...
^abc
、プレフィックスに一致し、abc
( abc
、abcabc
、abcc
、aabcdefg
など) で始まる任意の文字列に一致します。、 などxyzabc
には一致しません。ab
abc$
、同様に、サフィックスに一致し、abc
( abc
、xyzabc
など) で終わる任意の行に一致します。、、 などab
には一致しません。xyzab
abcxyz
^abc$
文字列のみに一致し、他には何も一致しabc
ません。
行全体に一致させるには、上記の正規表現を使用してアンカーをドロップします。
^([A-Z]{2,3})((-[A-Z][A-Z0-9]{1,2})(-[A-Z0-9]{2,3})?)?$
それだけです。ただし、 、 、 の動作は.
、または 正規表現がorオプションでコンパイルされ^
て$
いるかどうかに依存することに注意してください。は、文字列全体の先頭と末尾のみに一致し、 以外の任意の文字に一致することを意味します。は、文字列内の任意の行の先頭と末尾に一致し、 を含む任意の文字に一致することを意味します。Multiline
SingleLine
SingleLine
^
$
.
\n
MultiLine
^
$
.
\n
一致したさまざまなコンポーネントを見つけたい場合は、正規表現にマークアップを追加して、名前付きグループを作成できます。
(?<prefix>[A-Z]{2,3})((-(?<middle>[A-Z][A-Z0-9]{1,2}))(-(?<suffix>[A-Z0-9]{2,3}))?)?
これにより、一致したグループに名前でアクセスできるようになり、コードが読みやすくなります。
Regex rx = new Regex( @"(?<prefix>[A-Z]{2,3})((-(?<middle>[A-Z][A-Z0-9]{1,2}))(-(?<suffix>[A-Z0-9]{2,3}))?)?" , RegexOptions.ExplicitCapture );
Match m = rx.Match(s) ;
if ( m.Success )
{
string prefix = m.Groups["prefix"].Value ;
string middle = m.Groups["middle"].Value ;
string suffix = m.Groups["suffix"].Value ;
Console.WriteLine( "prefix: {0}" , prefix ) ;
Console.WriteLine( "middle: {0}" , middle ) ;
Console.WriteLine( "suffix: {0}", suffix ) ;
}
パフォーマンスのヒント:名前付きグループを使用して正規表現をコンパイルするとRegexOptions.ExplicitCapture
、特に正規表現が複雑になる場合に大きな助けになります。
正規表現に慣れていない場合 (そうでない場合でも!)、Jeffrey Friedlの最も優れた作品であるMastering Regular Expressionsを読む必要があります。