Gibt es eine Möglichkeit, das Äquivalent eines negativen Aussehens in regulären Javascript-Ausdrücken zu erreichen? Ich muss eine Zeichenfolge finden, die nicht mit einem bestimmten Zeichensatz beginnt.
Es scheint, dass ich keinen regulären Ausdruck finden kann, der dies ohne Fehler tut, wenn der übereinstimmende Teil am Anfang der Zeichenfolge gefunden wird. Negative Lookbehinds scheinen die einzige Antwort zu sein, aber Javascript hat keine.
EDIT: Dies ist der reguläre Ausdruck, an dem ich gerne arbeiten würde, aber nicht:
(?<!([abcdefg]))m
Es würde also mit dem 'm' in 'jim' oder 'm' übereinstimmen, aber nicht mit 'jam'
javascript
regex
negative-lookbehind
Andrew Ensley
quelle
quelle
(?:[^abcdefg]|^)(m)
? Wie in"mango".match(/(?:[^abcdefg]|^)(m)/)[1]
Antworten:
Lookbehind Assertions wurde angenommen in der ECMAScript - Spezifikation im Jahr 2018.
Positiver Lookbehind-Gebrauch:
Negativer Lookbehind-Gebrauch:
Plattformunterstützung:
quelle
Seit 2018 sind Lookbehind-Zusicherungen Teil der ECMAScript-Sprachspezifikation .
Antwort vor 2018
Da Javascript negative Lookahead unterstützt , besteht eine Möglichkeit darin:
Umkehren der Eingabezeichenfolge
Übereinstimmung mit einem umgekehrten regulären Ausdruck
Stornieren und formatieren Sie die Übereinstimmungen neu
Beispiel 1:
Folgende Frage von @ andrew-ensley:
Ausgänge:
Beispiel 2:
Folgender @ neaumusic-Kommentar (Übereinstimmung,
max-height
aber nichtline-height
, das Token istheight
):Ausgänge:
quelle
max-height
line-height
height
''(?!\()
wird die Apostrophe''(''test'''''''test
vom anderen Ende ersetzen und somit(''test'NNNtest
eher verlassen als(''testNNN'test
.Angenommen, Sie möchten alle finden, denen
int
nicht Folgendes vorangestellt istunsigned
:Mit Unterstützung für negative Rückblicke:
Ohne Unterstützung für negative Rückblicke:
Grundsätzlich besteht die Idee darin, n vorhergehende Zeichen zu erfassen und Übereinstimmungen mit negativem Look-Ahead auszuschließen, aber auch die Fälle abzugleichen, in denen keine vorangestellten n Zeichen vorhanden sind. (wobei n die Länge des Rückblicks ist).
Also der fragliche Regex:
würde übersetzen zu:
Möglicherweise müssen Sie mit der Erfassung von Gruppen spielen, um die genaue Stelle der Zeichenfolge zu finden, die Sie interessiert, oder Sie möchten einen bestimmten Teil durch etwas anderes ersetzen.
quelle
"So it would match the 'm' in 'jim' or 'm', but not 'jam'".replace(/(j(?!([abcdefg])).|^)m/g, "$1[MATCH]")
Rückkehr"So it would match the 'm' in 'ji[MATCH]' or 'm', but not 'jam'"
Es ist ziemlich einfach und es funktioniert!Die Strategie von Mijoja funktioniert für Ihren speziellen Fall, aber nicht allgemein:
Hier ist ein Beispiel, bei dem das Ziel darin besteht, einem Doppel-L zu entsprechen, jedoch nicht, wenn "ba" vorangestellt ist. Beachten Sie das Wort "balll" - echtes Aussehen sollte die ersten 2 l unterdrücken, aber mit dem zweiten Paar übereinstimmen. Wenn Sie jedoch die ersten 2 ls abgleichen und diese Übereinstimmung dann als falsch positiv ignorieren, geht die Regexp-Engine vom Ende dieser Übereinstimmung aus und ignoriert alle Zeichen innerhalb des falsch positiven Werts .
quelle
Verwenden
quelle
newString
wird immer gleich seinstring
. Warum so viele positive Stimmen?"Jim Jam Momm m".replace(/([abcdefg])?m/g, function($0, $1){ return $1 ? $0 : '[match]'; });
. Es sollte zurückkehrenJi[match] Jam Mo[match][match] [match]
. Beachten Sie aber auch, dass es, wie Jason unten erwähnte, in bestimmten Randfällen fehlschlagen kann.Sie können eine nicht erfassende Gruppe definieren, indem Sie Ihren Zeichensatz negieren:
... die mit jedem
m
NICHT übereinstimmen würden, dem einer dieser Buchstaben vorangestellt ist.quelle
(?:[^a-g]|^)m
. Ein Beispiel finden Sie unter regex101.com/r/jL1iW6/2 .So habe ich es
str.split(/(?<!^)@/)
für Node.js 8 erreicht (das Lookbehind nicht unterstützt):Funktioniert? Ja (Unicode ungetestet). Unangenehm? Ja.
quelle
Ich folgte der Idee von Mijoja und schöpfte aus den von JasonS aufgedeckten Problemen. Ich habe ein bisschen nachgesehen, bin mir aber nicht sicher, daher wäre eine Überprüfung durch jemanden, der mehr Experten als ich in js regex ist, großartig :)
meine persönliche Ausgabe:
Das Prinzip besteht darin,
checker
an jedem Punkt in der Zeichenfolge zwischen zwei beliebigen Zeichen aufzurufen , wenn diese Position der Ausgangspunkt von:--- jede Teilzeichenfolge von der Größe dessen, was nicht erwünscht ist (hier
'ba'
also..
) (wenn diese Größe bekannt ist; sonst muss es vielleicht schwieriger sein, dies zu tun)--- --- oder kleiner als das, wenn es der Anfang der Zeichenfolge ist:
^.?
und danach
--- was ist eigentlich zu suchen (hier
'll'
).Bei jedem Aufruf von
checker
wird ein Test durchgeführt, um zu überprüfen, ob der vorherige Wertll
nicht dem entspricht, was wir nicht wollen (!== 'ba'
). Wenn dies der Fall ist, rufen wir eine andere Funktion auf, und es muss diese (doer
) sein, die die Änderungen an str vornimmt. Wenn der Zweck dies ist, oder allgemeiner, werden die erforderlichen Daten für die manuelle Verarbeitung eingegeben die Ergebnisse des Scannens vonstr
.Hier ändern wir die Zeichenfolge, sodass wir den Längenunterschied verfolgen müssen, um die Positionen zu versetzen, die durch
replace
alle berechnet werdenstr
und die sich selbst nie ändern.Da primitive Zeichenfolgen unveränderlich sind, hätten wir die Variable verwenden können
str
, um das Ergebnis der gesamten Operation zu speichern, aber ich dachte, das Beispiel, das bereits durch die Ersetzungen kompliziert wurde, wäre mit einer anderen Variablen klarer (str_done
) .Ich denke, dass es in Bezug auf die Leistung ziemlich hart sein muss: all diese sinnlosen Ersetzungen von '' in '',
this str.length-1
Zeiten, plus hier manuelles Ersetzen durch Macher, was viel Schneiden bedeutet ... wahrscheinlich in diesem speziellen obigen Fall, das könnte gruppiert werden, indem die Schnur nur einmal in Stücke geschnitten wird, um die wir sie einfügen[match]
und.join()
mit sich[match]
selbst verbinden möchten .Die andere Sache ist, dass ich nicht weiß, wie es mit komplexeren Fällen umgehen würde, dh mit komplexen Werten für das falsche Aussehen ... die Länge ist vielleicht die problematischste Daten, die es zu bekommen gilt.
und
checker
im Falle mehrerer Möglichkeiten von unerwünschten Werten für $ Behind müssen wir einen Test mit einem weiteren regulären Ausdruck (der zwischengespeichert (erstellt))checker
ist, am besten durchführen, um zu vermeiden, dass dasselbe reguläre Ausdrucksobjekt erstellt wird bei jedem Aufrufchecker
zu wissen, ob es das ist, was wir vermeiden wollen oder nicht.hoffe ich war klar; Wenn nicht, zögern Sie nicht, ich werde es besser versuchen. :) :)
quelle
Wenn Sie in Ihrem Fall etwas ersetzen möchten
m
, konvertieren Sie es beispielsweise in GroßbuchstabenM
, können Sie den Satz in der Erfassungsgruppe negieren.übereinstimmen
([^a-g])m
, ersetzen durch$1M
([^a-g])
stimmt mit jedem Zeichen überein, das nicht (^
) ima-g
Bereich liegt, und speichert es in der ersten Erfassungsgruppe, damit Sie mit darauf zugreifen können$1
.So finden wir
im
injim
und ersetzen sie durchiM
in der die ErgebnissejiM
.quelle
Wie bereits erwähnt, erlaubt JavaScript jetzt Lookbehinds. In älteren Browsern benötigen Sie noch eine Problemumgehung.
Ich wette, es gibt keine Möglichkeit, einen regulären Ausdruck ohne Lookbehind zu finden, der genau das Ergebnis liefert. Sie können nur mit Gruppen arbeiten. Angenommen, Sie haben eine Regex
(?<!Before)Wanted
, wobeiWanted
es sich um die Regex handelt, die Sie abgleichen möchten, undBefore
um die Regex, die zählt, was nicht vor der Übereinstimmung stehen soll. Das Beste, was Sie tun können, ist, den regulärenBefore
Ausdruck zu negieren und den regulären Ausdruck zu verwendenNotBefore(Wanted)
. Das gewünschte Ergebnis ist die erste Gruppe$1
.In Ihrem Fall
Before=[abcdefg]
ist das leicht zu negierenNotBefore=[^abcdefg]
. Also wäre der reguläre Ausdruck[^abcdefg](m)
. Wenn Sie die Position von benötigenWanted
, müssen Sie gruppierenNotBefore
, damit das gewünschte Ergebnis die zweite Gruppe ist.Wenn Übereinstimmungen des
Before
Musters eine feste Länge habenn
, dh wenn das Muster keine sich wiederholenden Token enthält, können Sie das Negieren desBefore
Musters vermeiden und den regulären Ausdruck verwenden(?!Before).{n}(Wanted)
, müssen jedoch weiterhin die erste Gruppe oder den regulären Ausdruck(?!Before)(.{n})(Wanted)
und den zweiten verwenden Gruppe. In diesem Beispiel hat das MusterBefore
tatsächlich eine feste Länge, nämlich 1, verwenden Sie also den regulären Ausdruck(?![abcdefg]).(m)
oder(?![abcdefg])(.)(m)
. Wenn Sie an allen Übereinstimmungen interessiert sind, fügen Sie dieg
Flagge hinzu, siehe mein Code-Snippet:quelle
Dies macht es effektiv
Beispiel suchen und ersetzen
Beachten Sie, dass die negative Look-Behind-Zeichenfolge 1 Zeichen lang sein muss, damit dies funktioniert.
quelle
"m".match(/[^a-g]m/)
ihrnull
auch. Ich möchte auch in diesem Fall das "m"./(?![abcdefg])[^abcdefg]m/gi
Ja, das ist ein Trick.quelle
(?![abcdefg])
ist völlig redundant, da sie[^abcdefg]
bereits ihre Aufgabe erfüllt, um zu verhindern, dass diese Zeichen übereinstimmen.