Frage

Gibt es eine Möglichkeit, um anzugeben, dass zwei oder mehrere regex Ausdrücke können in einer beliebigen Reihenfolge?Zum Beispiel, XML-Attribute geschrieben werden können, in beliebiger Reihenfolge.Sagen, ich habe das folgende XML:

<a href="home.php" class="link" title="Home">Home</a>
<a href="home.php" title="Home" class="link">Home</a>

Wie würde ich das schreiben, ein Spiel, das überprüft, der Klasse und der Titel und arbeitet für die beiden Fälle?Ich bin hauptsächlich auf der Suche für die syntax, die mir erlaubt, um zu überprüfen, in beliebiger Reihenfolge, nicht nur anpassen der Klasse und der Titel, wie ich das tun kann.Gibt es eine Möglichkeit, außer nur einschließlich Kombinationen und verbinden Sie Sie mit einem '|'?

Bearbeiten:Meine Präferenz wäre, es zu tun in einem einzigen regex-wie Baue ich es programmatisch und auch unit-Tests ist es.

War es hilfreich?

Lösung

Nein, ich glaube, der beste Weg, es zu tun mit einem einzelnen WIEDER genau so ist, wie Sie beschreiben.Leider bekommen sehr unordentlich, wenn Ihre XML kann haben 5 verschiedene Attribute, so dass Sie eine große Anzahl der verschiedenen REs zu überprüfen.

Auf der anderen Seite, würde ich es nicht tun dies mit einer RE, seit Sie sind nicht dazu gedacht, werden Programmiersprachen.Was ist falsch mit dem altmodischen Ansatz der Verwendung einer XML-Verarbeitung Bibliothek?

Wenn Sie erforderlich zu verwenden RE, diese Antwort wird wahrscheinlich nicht viel helfen, aber ich glaube, dass bei der Verwendung der richtigen Werkzeuge für den job.

Andere Tipps

Haben Sie als xpath?(wobei die Reihenfolge der attribute spielt keine Rolle)

//a[@class and @title]

Wählen Sie beide <a> Knoten als gültig matches.Der einzige VORBEHALT ist, dass die Eingabe muß xhtml (well formed xml).

Sie können erstellen ein lookahead für jedes der Attribute und stecken Sie Sie in eine regex für den ganzen tag.Für Beispiel, die regex für den tag sein könnte

<a\b[^<>]*>

Wenn Sie dieses auf XML müssen Sie wahrscheinlich etwas aufwändiger.Von selbst, diese Basis regex match zu einem tag mit null oder mehr Parametern.Dann fügen Sie einen lookhead für jedes der Attribute, die Sie wollen zu entsprechen:

(?=[^<>]*\s+class="link")
(?=[^<>]*\s+title="Home")

Die [^<>]* können Sie Scannen, vor der für das Attribut, aber nicht lassen Sie es, sich jenseits der schließenden Spitzen Klammer.Passend zu den führenden Leerzeichen hier in der lookahead dient zwei Zwecken:es ist mehr flexible als die Anpassung in der Basis regex, und sicherzustellen, dass wir passend zu einem ganzen Attribut name.Die Kombination von Ihnen, die wir bekommen:

<a\b(?=[^<>]*\s+class="link")(?=[^<>]*\s+title="Home")[^<>]+>[^<>]+</a>

Natürlich, ich habe einige vereinfachende Annahmen für die Klarstellung.Ich hatte keine Leerzeichen um das Gleichheitszeichen für einfache Anführungszeichen oder ohne Anführungszeichen um die Werte der attribute oder für die Spitzen Klammern in der Attribut-Werte (die ich höre, ist legal, aber ich habe nie gesehen, es getan).Das Stopfen diese Lecks (wenn Sie benötigen) wird die regex hässlicher, aber nicht erfordern änderungen an der grundlegenden Struktur.

Sie nutzen könnten, benannte Gruppen zu ziehen, die Attribute aus dem tag.Führen Sie die regex und dann Schleife über die Gruppen, die das tun, was auch immer die tests, die Sie benötigen.

So etwas (ungetestet, über .net regex-syntax mit \w für Wort, Zeichen und \s für ein Leerzeichen):

<a ((?<key>\w+)\s?=\s?['"](?<value>\w+)['"])+ />

Die einfachste Möglichkeit wäre, zu schreiben, eine regex, die picks up die <a .... > Teil, und dann schreiben zwei weitere regexes, um ziehen Sie die Klasse und den Titel.Obwohl Sie wohl tun könnte ihn mit einem einzigen regex, es wäre sehr kompliziert, und wahrscheinlich viel mehr fehleranfällig.

Mit einer einzigen regex müssten Sie so etwas wie

<a[^>]*((class="([^"]*)")|(title="([^"]*)"))?((title="([^"]*)")|(class="([^"]*)"))?[^>]*>

Das ist nur ein Erster hand zu erraten, ohne zu überprüfen, um zu sehen, ob es noch gültig ist.Viel einfacher-einfach teilen und erobern das problem.

Eine erste ad-hoc-Lösung könnte sein, das folgende zu tun.

((class|title)="[^"]*?" *)+

Dies ist weit von perfekt, denn es erlaubt jedem Attribut mehr als einmal auftreten.Ich könnte mir vorstellen, dass dies vielleicht solveable mit Behauptungen.Aber wenn Sie wollen einfach nur, um die Attribute extrahieren, könnte dies bereits ausreichend.

Wenn Sie anpassen möchten eine permutation einer Menge von Elementen ist, Sie können verwenden eine Kombination von Rücken-Referenzen und null-Breite negative vorwärts matching.

Sagen Sie, Sie wollen für jede dieser sechs Zeilen:

123-abc-456-def-789-ghi-0AB
123-abc-456-ghi-789-def-0AB
123-def-456-abc-789-ghi-0AB
123-def-456-ghi-789-abc-0AB
123-ghi-456-abc-789-def-0AB
123-ghi-456-def-789-abc-0AB

Tun Sie dies mit der folgenden regex:

/123-(abc|def|ghi)-456-(?!\1)(abc|def|ghi)-789-(?!\1|\2)(abc|def|ghi)-0AB/

Die Rückverweise (\1, \2), lassen Sie bitte Ihre vorherigen Spiele, und die null Breite forward-matching ((?!...) ) können Sie zu negieren einen positionellen Spiel, sagen nicht übereinstimmen, wenn die enthaltene Spiele auf dieser position.Die Kombination der zwei macht sicher, dass Ihr match ein echtes permutation von den Elementen, mit jeder Möglichkeit nur einmal vorkommenden.

So zum Beispiel in ruby:

input = <<LINES
123-abc-456-abc-789-abc-0AB
123-abc-456-abc-789-def-0AB
123-abc-456-abc-789-ghi-0AB
123-abc-456-def-789-abc-0AB
123-abc-456-def-789-def-0AB
123-abc-456-def-789-ghi-0AB
123-abc-456-ghi-789-abc-0AB
123-abc-456-ghi-789-def-0AB
123-abc-456-ghi-789-ghi-0AB
123-def-456-abc-789-abc-0AB
123-def-456-abc-789-def-0AB
123-def-456-abc-789-ghi-0AB
123-def-456-def-789-abc-0AB
123-def-456-def-789-def-0AB
123-def-456-def-789-ghi-0AB
123-def-456-ghi-789-abc-0AB
123-def-456-ghi-789-def-0AB
123-def-456-ghi-789-ghi-0AB
123-ghi-456-abc-789-abc-0AB
123-ghi-456-abc-789-def-0AB
123-ghi-456-abc-789-ghi-0AB
123-ghi-456-def-789-abc-0AB
123-ghi-456-def-789-def-0AB
123-ghi-456-def-789-ghi-0AB
123-ghi-456-ghi-789-abc-0AB
123-ghi-456-ghi-789-def-0AB
123-ghi-456-ghi-789-ghi-0AB
LINES

# outputs only the permutations
puts input.grep(/123-(abc|def|ghi)-456-(?!\1)(abc|def|ghi)-789-(?!\1|\2)(abc|def|ghi)-0AB/)

Für eine permutation der fünf Elemente, wäre es:

/1-(abc|def|ghi|jkl|mno)-
 2-(?!\1)(abc|def|ghi|jkl|mno)-
 3-(?!\1|\2)(abc|def|ghi|jkl|mno)-
 4-(?!\1|\2|\3)(abc|def|ghi|jkl|mno)-
 5-(?!\1|\2|\3|\4)(abc|def|ghi|jkl|mno)-6/x

Für Ihr Beispiel die regex würde

/<a href="home.php" (class="link"|title="Home") (?!\1)(class="link"|title="Home")>Home<\/a>/
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top