2013-07-19 8 views
7

Mam wyrażenie regularne. Zawiera wymaganą nazwaną grupę przechwytywania i opcjonalne nazwane grupy przechwytywania. Przechwytuje pojedyncze dopasowania i analizuje sekcje w nazwanych grupach, których potrzebuję.Powtarzalne, złożone wyrażenie regularne, z kropką "." rozdzielane separatory

Z wyjątkiem tego, teraz potrzebuję go powtórzyć.

Zasadniczo moje wyrażenie regularne reprezentuje pojedynczą jednostkę atomową w ciągu (potencjalnie) znacznie dłuższym. Zamiast dopasowywać dokładnie moje wyrażenie regularne, ciąg docelowy zwykle zawiera powtarzające się instancje wyrażenia regularnego, oddzielone kropką "." postać.

Na przykład, jeżeli jest to, co mój wyrażenie regularne oddaje: <some match>

Rzeczywiste ciąg mógłby wyglądać każdy z nich:

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

Jaki jest najprostszy sposób modyfikowania oryginalnego wyrażenia regularnego, aby uwzględnić powtarzające się wzorce, ignorując kropki?

Nie jestem pewien, czy rzeczywiście jest potrzebny, ale tutaj jest wyrażenie regularne, którego używam do przechwytywania poszczególnych segmentów. Jeszcze raz, chciałbym to ulepszyć, aby uwzględnić opcjonalne dodatkowe segmenty. Chciałbym, aby każdy segment był wyświetlany jako kolejny "mecz" w zestawie wyników;

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

Jest przeznaczony do analizy ścieżki klasy, z maksymalnie trzema opcjonalnymi akcesoriami indeksu. ("member.sub_member[0].sub_sub_member[0][1][2]")

Podejrzewam, że odpowiedź wymaga spojrzenia z wyprzedzeniem lub spojrzenia w tył, co do którego nie jestem do końca zaznajomiony.

Obecnie używam String.Split do oddzielania segmentów ciągów. Ale myślę, że jeśli wzmocnienie do regex jest dość proste, pomijam dodatkowy krok dzielenia i ponownie używam wyrażenia regularnego jako mechanizmu sprawdzania poprawności.

EDIT:

Jako dodatkowy klucz w tryby, chciałbym, aby uniemożliwić jakąkolwiek kropki „” znak od początku lub końca ciągu. Powinny one istnieć tylko jako separatory między segmentami ścieżki.

+2

Uproszczonym podejściem byłoby podzielenie łańcucha na' .', a następnie uruchomienie regex na każdym z nich. –

+0

Obecnie to robię. Pomyślałem, że jeśli poprawka do zwykłego expresison jest wystarczająco prosta, byłbym w stanie zrezygnować z string.Split i dodatkowo być w stanie zweryfikować ciąg przed jego analizą. – BTownTKD

+0

Innymi słowy, szukasz spójnych dopasowań oddzielonych kropką od początku do końca łańcucha i nic więcej, nieprawdaż? –

Odpowiedz

2

Nie musisz używać żadnych rozejść. Możesz umieścić (^|\.) przed głównym wzorem, a następnie po nim +. Umożliwi to powtórzenie, oddzielonej sekwencji .. Polecam również połączenie grup <index> w jedno przechwytywanie dla uproszczenia (użyłem *, aby dopasować dowolną liczbę indeksów, ale równie dobrze można użyć {0,3}, aby dopasować tylko do 3).Ostateczny wzór będzie:

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

Na przykład:

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); 
} 

który wyjściowa:

member 
sub_member 
0 
sub_sub_member 
0 
1 
2 

Aktualizacja: Ten wzór zapewnia, że ​​ciąg nie może mieć wszelkie kropki wiodące lub końcowe. To potwór, ale to powinno działać:

^(?<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})*$ 

Albo ten, chociaż musiała zrezygnować z mojego pomysłu 'no-look-arounds':

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

Podoba mi się uproszczenie. Być może będę musiał zmienić końcowy * na {0,3}, ponieważ istnieje twardy limit 3 indeksujących akcesorów. Ale to nie ma znaczenia. Czy przepisany przez ciebie (^ | \.) Wzór zapewnia, że ​​nie ma kropek z głową lub ogonem? To znaczy. kropki powinny istnieć tylko pomiędzy segmentami ścieżki - nie na początku ani na końcu. – BTownTKD

+0

Po podłączeniu regex, wydaje się, że generuje tylko jedno dopasowanie. Zjada "wszystkie poprzednie segmenty ścieżki", a cała uwaga traktuje jako pojedynczą grupę "członków". – BTownTKD

+0

@BTownTKD Masz rację, pozwala na prowadzenie "." (Będę pracował nad naprawianiem tego), ale zdecydowanie nie powinien "jeść" poprzednich segmentów. Najprawdopodobniej musisz poprawić sposób przeprowadzania iteracji wyników, ponieważ każda grupa może teraz mieć wiele przechwyceń. –

1

Najprostszym sposobem jest podzielenie ciągu znaków za pomocą string.Split na "." znak, a następnie zastosuj wyrażenie regularne do każdego elementu w wynikowej tablicy. Regex, który długo miałby jakąś brutalną wydajność i potencjalne problemy z wyprzedzeniem/za tym.

1

spróbować tej bestii z:

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

Oto próbka aplikacji konsoli:

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); 
     } 
    } 
} 
1

Można użyć \G być pewny, że sąsiadujące ze sobą wyniki i uprzedzona aby sprawdzić, czy wzór jest po kropce lub na końcu łańcucha:

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

z MSDN: z \G „Mecz musi rozpocząć w miejscu, w którym poprzedni mecz zakończył się "

+0

Jak mogę to zmienić, aby nie blokować kropki "." postacie na początku lub na końcu? Chcę się upewnić, że istnieją tylko między segmentami ścieżki. – BTownTKD

+0

Próbowałem podłączyć to do mojego programu testowego (z mojej odpowiedzi) i pokazuje '" member "' jako cały mecz –