2016-07-20 3 views
2

Hallo, meine Frage ist einfach:Spiel mehrmals eine Gruppe nur in einzelnen Regex

ich nur alle möglichen Hashtags in einem Artikel passen wollen, wenn sie in einem <figcaption> mit PCRE regex sind. Z. B:

<figcaption>blah blah #hashtag1, #hashtag2</figcaption> 

Ich machte einen Versuch, hier https://regex101.com/r/aL9vS8/1 und Entfernen der letzten ? die Erfassung von #hashtag1 zu #hashtag2 würde sich ändern, aber beide nicht erhalten können.

Ich bin nicht einmal sicher, es ist in einem einzigen Regex in PHP machbar.

Irgendeine Idee, um mir zu helfen? :)

Wenn es keine Möglichkeit gibt, in einem einzigen Regex (wirklich? Sogar mit Rekursion (?R)??: P), schlagen Sie bitte die effizienteste Art und Weise möglich Leistung.

Vielen Dank!

[EDIT]

Wenn es keine Möglichkeit gibt, ist mein PHP nächste Idee:

  1. Spiel jeden figcaption mit preg_replace_callback
  2. In dem Callback-Spiel jede Instanz #hashtag.

Kann ich Ihre Meinung dazu erfahren? Gibt es einen besseren Weg? Meine Artikel sind nicht sehr lang.

+0

figcaption ist ein HTML-Tag. Sie können JS verwenden, um den Text in figcaption zu erhalten, und dann die Suche starten, um die Hashtags mithilfe von Regex zu finden. – rmondesilva

+1

Mögliches Duplikat von [Wie erfasse ich eine beliebige Anzahl von Gruppen in JavaScript Regexp?] (Http: // stackoverflow.com/questions/3537878/how-to-capture-an-arbitrary-number-of-groups-in-javascript-regexp) –

+0

Der Punkt hier ist, dass es keine Notwendigkeit gibt, "willkürliche Anzahl von Gruppen" zu entsprechen, ist diese Frage kein Betrogener von Oben. Eigentlich sollte das JS-Tag entfernt werden, der gemeinsame Versuch war ein PCRE-Regex. –

Antwort

2

Bitte schlagen die effizienteste Art und Weise möglich, die Leistung weise

der zuverlässigste Weg, um etwas Text zwischen einigen Begrenzungszeichen mit PCRE regex unter Verwendung der benutzerdefinierten Grenzen mit \G operator ist übereinstimmen. Die abschließende Grenze ist jedoch eine Zeichenfolge mit mehreren Zeichenfolgen, und um einen beliebigen Text zu finden, aber </figcaption>, benötigen Sie eine tempered greedy token. Da dieses Token sehr ressourcenintensiv ist, muss es entrollt werden. Hier

ist ein schneller, zuverlässiger PCRE regex für Ihre Aufgabe:

(?:<figcaption|(?!^)\G)[^<#]*(?:(?:<(?!\/figcaption>)|#\B)[^<#]*)*\K#\w+ 

Siehe regex demo

Einzelheiten:

  • (?:<figcaption|(?!^)\G) - Spiele <figcaption oder das Ende der vorherigen erfolgreiche Übereinstimmung
    Weitere Details:
    (?:<figcaption|(?!^)\G) ist eine Nicht-Erfassung Gruppe ((?:...)), die einzige Gruppe gemeint ist, nicht zu verfolgen, was mit dieser Gruppe angepasst wurde (dkein Wert wird im Gruppenstapel gespeichert, da der Stapel nicht erstellt wurde), der zwei Alternativen entspricht (| ist ein Alternationsoperator): 1) Literaltext <figcaption oder 2) (?!^)\G - ein Ort nach dem vorherigen erfolgreichen Abgleich (beachten Sie, dass \G ebenfalls übereinstimmt Der Anfang der Zeichenfolge, also müssen wir das negative Lookahead (?!^) hinzufügen, um dieses Verhalten auszuschließen).
  • [^<#]* - 0+ Zeichen anders als < und #
  • (?:(?:<(?!\/figcaption>)|#\B)[^<#]*)* - 0+ Sequenzen:
    • (?:<(?!\/figcaption>)|#\B) - ein < nicht gefolgt mit /figcaption># oder nicht mit einem Wort gefolgt char
    • [^<#]* - 0 + Zeichen außer < und #
  • \K - lassen Sie den Text so weit angepasst
  • #\w+-# und 1+ Wort Zeichen

Noch mehr Details:

Die Flucht Sequenz \K verursacht irgendeinen pr Ewig übereinstimmende Zeichen, die nicht in der endgültigen übereinstimmenden Sequenz enthalten sein müssen. Zum Beispiel kann das Muster:

foo\Kbar 

Streichhölzer foobar, aber berichtet, dass es bar abgestimmt. Diese Funktion ähnelt einer Lookbehind-Assertion.

  • (?:(?:<(?!\/figcaption>)|#\B)[^<#]*)*: Hier haben wir eine äußere nicht-einfangende Gruppe (?:...)* eine Folge von Untermustern null oder mehrere Male passend zu ermöglichen (wir können eine quantifier * nur auf eine Gruppierung gesetzt, wenn wir eine wiederholen müssen Sequenz von Untermustern) und die innere nicht-einfangende Gruppe (?:<(?!\/figcaption>)|#\B)[^<#]* ist nur ein Weg, ein längeren <(?!\/figcaption>)[^<#]*|#\B[^<#]* (nur zur Gruppe 2 verschiedene Alternativen <(?!\/figcaption>) und #\B vor einem gemeinsamen „Suffix“ schrumpft [^<#]*
  • Wrapping in einem Tag:. einfach verwenden preg_replace mit dem <span class="highlight">$0</span> Ersatz Muster:

Code:

$re = '~(?:<figcaption|(?!^)\G)[^<#]*(?:(?:<(?!\/figcaption>)|#\B)[^<#]*)*\K#\w+~'; 
$str = "<figcaption>blah # blah #hashtag1, #hashtag2</figcaption> #ee <figcaption>#ddddd"; 
$subst = "<span class=\"highlight\">$0</span>"; 
$result = preg_replace($re, $subst, $str); 
echo $result; 

Siehe PHP IDEONE demo

+0

Waw Vielen Dank! Es klingt großartig und funktioniert ... Kannst du mir bitte helfen, deine Regex Schritt für Schritt besser zu verstehen und mir helfen, den Hashtag für den späteren Austausch zu erfassen? – antoni

+0

Sie müssen * Hashtag * nicht erfassen, es ist auf diese Weise * matched *. Selbst wenn das Tag fehlerhaft ist, werden immer Hashtags nach dem öffnenden Knoten

angezeigt. –

+0

Waw versucht an Ihrem Beispiel Ich kann die Ersetzungen machen, die ich will. Perfekt! Genial! Ich wünschte, du könntest dein Muster in mehr Erklärungen aufteilen, es wird eine Weile dauern, bis du es verstehst. – antoni