2017-07-27 4 views
2

Ich versuche, einen regulären Ausdruck zu verwenden, um eine variierende Zeichenfolge mit PHP zu analysieren, kann diese Zeichenfolge beispielsweise sein;Variable Größe Lookahead konsumieren

"twoX // threeY" 

oder

"twoX /// threeY" 

So gibt es ein Link Schlüsselwort, ein divider bestehend aus 2 oder 3 Schrägstrichen und ein rechten Schlüsselwort. Dies sind auch die Teile, die ich getrennt konsumieren möchte.

"/((?<left>.+)?)(?=(?<divider>[\/]{2,3}))([\/]{2,3})((?<right>.+)?)/"; 

Als ich diesen regulären Ausdruck auf der ersten Zeichenfolge verwenden, wird alles korrekt analysiert, so;

links: twoX

Teiler: //

rechts: threeY

aber wenn ich laufe diesen Ausdruck auf der zweiten Saite, die links und der Teiler wird nicht korrekt analysiert. Das Ergebnis, das ich dann bekommen habe, ist;

links: twoX/

Teilers: //

rechts: threeY

verwende ich die {2,3} in der regulärer Ausdruck, um entweder 2 oder 3 Schrägstriche für den Teiler auszuwählen. Aber das scheint irgendwie nicht mit dem Match All Charakter zu funktionieren.

Gibt es eine Möglichkeit, die Regex entweder 2 oder 3 Schrägstriche analysieren zu lassen, ohne die gesamte Sequenz zu duplizieren?

+0

Ja, es ist einfach, müssen Sie '' statt '' –

+0

Warum kann‘ tst du die Aussage einfach mit '\ s */+ \ s *'? Anstatt '\ s' zu verwenden, können Sie auch' '(literales Leerzeichen) verwenden, da' \ s' auch anderen Leerzeichen entspricht. – Asunez

Antwort

4

Das (.+)? ist ein gieriges Punktabgleichmuster und entspricht so vielen Zeichen wie möglich, wobei 1 das Minimum ist. Also, da das nächste Muster nur 2 Zeichen erfordert, nur 2 Zeichen in die nächste Gruppe erfasst wird, wird der erste / zur Gruppe gehören 1.

Verwenden Sie ein faul Muster in der ersten Gruppe:

'~(?<left>.*?)(?<divider>/{2,3})(?<right>.*)~' 
      ^^^ 

Siehe regex demo. Fügen Sie ^ und $ Anker um das Muster hinzu, um die gesamte Zeichenfolge bei Bedarf anzupassen.

Hinweis: Sie müssen nicht das gleiche Muster im Lookahead und im verbrauchenden Musterteil wiederholen, es macht das Muster nur umständlich, (?=(?<divider>[\/]{2,3}))([\/]{2,3}) = (?<divider>[\/]{2,3}).

Einzelheiten

  • (?<left>.*?) - Gruppe „links“, das passt alle 0+ Zeichen außer Zeilenumbruch Zeichen als wenige wie möglich
  • (?<divider>/{2,3})-2 oder 3 Schrägstriche (keine Notwendigkeit zu entkommen seit ~ wird als Regex-Begrenzer verwendet)
  • (?<right>.*) - Gruppe "rechts" passend alle 0+ Zeichen außer Zeilenumbruch Zeichen wie viele wie möglich (bis zum Ende der Zeile).

Und ein natrual schau Spaltung Ansatz findet eine PHP demo:

$s = "twoX // threeY"; 
print_r(preg_split('~\s*(/{2,3})\s*~', $s, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY)); 
// => Array ([0] => twoX [1] => // [2] => threeY) 

Du die Namen verlieren, aber Sie können sie zu einem späteren Schritt hinzuzufügen.

+0

Vielen Dank für die klare Erklärung und die Alternative _ (. _.) _ – Thys

2

Der + Quantifizierer ist standardmäßig gierig, was bedeutet, dass er versuchen wird, so viele Zeichen wie möglich zu finden. So wollen Sie die erste + faul machen, so wird es nicht versuchen, und die erste / durch Hinzufügen der ? Quantifizierer können Sie die + faul machen: +?.
Dies ist in der folgenden regex führen: (?.? *) (?. +)?

((?<left>.+?)?)(?=(?<divider>[\/]{2,3}))([\/]{2,3})((?<right>.+)?) 
+0

Und was ist der Zweck der Lookahead hier? Sie wiederholen den gleichen Fehler wie OP. Es ist überflüssig, das Lookahead-Muster kann in dem konsumierenden Muster verwendet werden und die gesamte Regex wird viel sauberer und lesbarer aussehen. –

+0

Auch warum '(? . +?)?'? Du benötigst mindestens 1 Char und sagst dann "ok, match 1 char, aber 1 oder 0 mal". Ist es nicht natürlicher zu sagen "pass auf 0 oder mehr Zeichen", "(? . *?)"? –

+1

@Wiktor Ich habe nur die ursprüngliche Regex angepasst, um das Problem in der Frage zu beheben, und habe die anderen Teile der Regex nicht wirklich angeschaut. Wenn ich es nochmal ansehe (und auf deine Antwort schaue), sehe ich, was du meinst. Während dies auch das Problem in der Frage löst, denke ich, dass Ihre Antwort bei weitem die bessere Antwort ist. – ScintillatingSpider