Vraag Regex: afstemmen op groepen in verschillende volgorde zonder de groep te herhalen


Laten we zeggen dat ik twee snaren als deze heb:

XABY
XBAY

Een eenvoudige regex die overeenkomt met beide zou als volgt gaan:

X(AB|BA)Y

Ik heb echter een geval waarin A en B ingewikkelde reeksen zijn, en ik ben op zoek naar een manier om te voorkomen dat ik ze elk twee keer moet opgeven (aan elke kant van de |). Is er een manier om dit te doen (dat is vermoedelijk eenvoudiger dan twee keer op te geven)?

Bedankt


13
2018-04-08 00:48


oorsprong


antwoorden:


X(?:A()|B()){2}\1\2Y

In principe gebruik je een lege capturing-groep om elk item af te vinken wanneer het is gematcht, waarna de back-referenties ervoor zorgen dat alles is uitgecheckt.

Houd er rekening mee dat dit afhankelijk is van ongedocumenteerd regex-gedrag, dus er is geen garantie dat dit in uw regex-smaak zal werken - en als dat het geval is, is er geen garantie dat dit zal gebeuren doorgaan met werken als die smaak evolueert. Maar voor zover ik weet, werkt het in elke smaak die back-referenties ondersteunt. (EDIT: het werkt niet in JavaScript.)

BEWERK: U zegt dat u benoemde groepen gebruikt om delen van de wedstrijd te veroveren, wat een hoop visuele rommel toevoegt aan de regex, zo niet echte complexiteit. Welnu, als u toevallig .NET-regexes gebruikt, kunt u nog steeds eenvoudig genummerde groepen gebruiken voor de "selectievakjes". Hier is een simplistisch voorbeeld dat een aantal maandelijkse reeksen vindt en uit elkaar haalt zonder de interne volgorde te kennen:

  Regex r = new Regex(
    @"(?:
        (?<MONTH>Jan|Feb|Mar|Apr|May|Jun|Jul|Sep|Oct|Nov|Dec)()
        |
        (?<DAY>\d+)()
      ){2}
      \1\2",
    RegexOptions.IgnorePatternWhitespace);

  string input = @"30Jan Feb12 Mar23 4Apr May09 11Jun";
  foreach (Match m in r.Matches(input))
  {
    Console.WriteLine("{0} {1}", m.Groups["MONTH"], m.Groups["DAY"]);
  }

Dit werkt omdat in .NET de aanwezigheid van benoemde groepen geen effect heeft op de volgorde van de niet-benoemde groepen. Benoemde groepen hebben nummers toegewezen, maar die nummers beginnen na de laatste van de niet-genoemde groepen. (Ik weet dat dat onnodig ingewikkeld lijkt, maar er zijn goede redenen om het op die manier te doen.)

Normaal gesproken wilt u voorkomen dat benoemde en niet-benoemde capturing-groepen samen worden gebruikt, vooral als u back-referenties gebruikt, maar ik denk dat deze case een legitieme uitzondering kan zijn.


19
2018-04-08 01:25



U kunt regex-stukken in variabelen opslaan en doen:

A=/* relevant regex pattern */
B=/* other regex pattern */
regex = X($A$B|$B$A)Y

Op deze manier hoeft u slechts één keer een regex op te geven, op zijn eigen regel, die het onderhoud eenvoudiger moet maken.

Sidenote: U probeert permutaties te vinden, wat ok is, omdat u slechts naar 2 subregexes kijkt. Maar als je een derde (of vierde) wilde toevoegen, dan groeien je regex-permutaties drastisch - (erger nog, abc | acb | bac | bca | cab | cba) - of erger. Als je de weg van permutaties moet afleggen, is hier een goede discussie over stackoverflow. Het is voor letterpermutatie en de oplossingen gebruiken awk / bash / perl, maar dat geeft je tenminste een startpunt.


4
2018-04-08 03:20



probeer dit

X((A|B){2})Y

1
2018-04-08 03:40



Als er meerdere strings zijn, met elk type personages, ben je beter met:

X(.)+Y

Alleen dan cijfers

X([0-9])+Y

Alleen brieven

X([a-zA-Z])+Y

Letters en cijfers

X([a-zA-Z][0-9])+Y

0
2018-04-08 00:56