7

私は正規表現を持っています。これには、必須の名前付きキャプチャ グループと、いくつかのオプションの名前付きキャプチャ グループが含まれています。個々の一致をキャプチャし、セクションを必要な名前付きグループに解析します。

ただし、今は繰り返す必要があります。

基本的に、私の正規表現は、(潜在的に) はるかに長い文字列内の単一の原子単位を表します。私の正規表現と正確に一致する代わりに、ターゲット文字列には通常、ドット「.」で区切られた正規表現の繰り返しインスタンスが含まれます。キャラクター。

たとえば、これが私の正規表現がキャプチャするものである場合:<some match>

実際の文字列は、次のいずれかのようになります。

  • <some match>
  • <some match>.<some other match>
  • <some match>.<some other match>.<yet another match>

ドットを無視しながら、繰り返しパターンを説明するために、元の正規表現を変更する最も簡単な方法は何ですか?

実際に必要かどうかはわかりませんが、個々のセグメントをキャプチャするために使用している正規表現を次に示します。繰り返しになりますが、オプションの追加セグメントを考慮してこれを強化したいと思います。結果セットで各セグメントを別の「一致」として表示したいと思います。

^(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])?(?:\[(?<index2>[0-9]+)\])?(?:\[(?<index3>[0-9]+)\])?$

最大 3 つのオプションのインデックス アクセサーを使用して、クラス パスを解析することを目的としています。(すなわち " member.sub_member[0].sub_sub_member[0][1][2]")

答えには先読みまたは後読みが含まれているのではないかと思いますが、それについては私はよく知りません。

現在、String.Split を使用して文字列セグメントを分離しています。しかし、正規表現の拡張が十分に単純である場合は、余分な分割ステップをスキップし、正規表現を検証メカニズムとして再利用することも考えています。

編集:

ギアの追加のレンチとして、ドット「.」を禁止したいと思います。文字列の先頭または末尾の文字。これらは、パス セグメント間のセパレータとしてのみ存在する必要があります。

4

4 に答える 4

3

ルックアラウンドを使用する必要はありません。(^|\.)メイン パターンの前にa を配置し、その後に a を配置できます+。これにより、 - で区切られた繰り返し.シーケンスを作成できます。<index>簡単にするために、グループを 1 つのキャプチャに結合することもお勧めします(以前*は任意の数のインデックスに一致させていましたが、最大 3 つまでの一致に簡単に使用できます{0,3})。最終的なパターンは次のようになります。

(?:(?:^|\.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])*)+$

例えば:

var input = "member.sub_member[0].sub_sub_member[0][1][2]";
var pattern = @"(?:(?:^|\.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])*)+$";
var match = Regex.Match(input, pattern);
var parts = 
    (from Group g in match.Groups
     from Capture c in g.Captures
     orderby c.Index
     select c.Value)
    .Skip(1);

foreach(var part in parts)
{
    Console.WriteLine(part);
}

どちらが出力されますか:

member
sub_member
0
sub_sub_member
0
1
2

更新:このパターンにより、文字列の先頭または末尾にドットを含めることができなくなります。それは怪物ですが、うまくいくはずです:

^(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\]){0,3}(?:\.(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\]){0,3})*$

または、これは、「見回さない」という考えをあきらめなければなりませんでしたが:

^(?!\.)(?:(?:^|\.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\]){0,3})*$
于 2013-07-19T12:20:34.107 に答える
1

最も簡単な方法はstring.Split、「.」を使用して文字列を分割することです。文字を入力し、結果の配列の各要素に正規表現を適用します。とにかく、残忍なパフォーマンスと潜在的な先読み/背後の問題を長い間持つ正規表現。

于 2013-07-19T12:19:41.870 に答える
1

Try this beast out:

(?<=^|\.)?((?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])?(?:\[(?<index2>[0-9]+)\])?(?:\[(?<index3>[0-9]+)\])?)(?=\.){0,3}$?

Here's a sample console application:

class Program
{
    public static void Main()
    {
        var input = @"member.sub_member[0].sub_sub_member[0][1][2]";
        var matches = Regex.Matches(input, @"(?<=^|\.)?((?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])?(?:\[(?<index2>[0-9]+)\])?(?:\[(?<index3>[0-9]+)\])?)(?=\.){0,3}$?");
        foreach (Match match in matches)
        {
            Console.Write("Member: {0} Index {1} Index2: {2} Index3 {3}\r\n", 
                match.Groups["member"].Value,
                match.Groups["index"].Value,
                match.Groups["index2"].Value,
                match.Groups["index3"].Value);
        }
    }
}
于 2013-07-19T12:22:01.190 に答える
1

\Gパターンの後にドットまたは文字列の末尾が続くかどうかを確認するために、連続した結果と先読みを確認するために使用できます。

var pattern = @"(?:^|\G\.)(?<member>[A-Za-z_][A-Za-z0-9_]*)(?:\[(?<index>[0-9]+)\])?(?:\[(?<index2>[0-9]+)])?(?:\[(?<index3>[0-9]+)])?(?=\.|$)";

msdn から: \G 「試合は前の試合が終了した位置から開始する必要があります」

于 2013-07-19T12:25:31.527 に答える