Javascript Regex - Alternative suchen?

142

Hier ist ein Regex, der in den meisten Regex-Implementierungen einwandfrei funktioniert:

(?<!filename)\.js$

Dies entspricht .js für eine Zeichenfolge, die mit Ausnahme von Dateiname.js mit .js endet

Javascript hat keinen regulären Ausdruck. Kann jemand einen alternativen regulären Ausdruck zusammenstellen, der das gleiche Ergebnis erzielt und in Javascript funktioniert?

Hier sind einige Gedanken, benötigt aber Hilfsfunktionen. Ich hatte gehofft, es nur mit einem regulären Ausdruck zu erreichen: http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript

Daniel
quelle
3
Wenn Sie nur einen bestimmten Dateinamen oder eine Liste von Dateinamen überprüfen müssen, warum nicht einfach zwei Überprüfungen verwenden? Überprüfen Sie, ob es mit .js endet. Wenn dies der Fall ist, überprüfen Sie, ob es nicht mit filename.js übereinstimmt, oder umgekehrt.
Si28719e
3
Update: Die neueste öffentliche Chrome-Version (v62) enthält standardmäßig (vermutlich experimentelle) Lookbehinds: D Beachten Sie jedoch, dass sich Lookbehinds noch in Vorschlagsphase 3 befinden: github.com/tc39/proposal-regexp-lookbehind . Es kann also eine Weile dauern, bis JavaScript es überall unterstützt. Seien Sie besser vorsichtig bei der Verwendung in der Produktion!
Eirik Birkeland
2
# Update: ES2018 enthält Lookbehind-Zusicherungen Plus : - dotAll-Modus (das s-Flag) - Lookbehind-Zusicherungen - Benannte Erfassungsgruppen - Unicode-Eigenschaft wird ausgeblendet
Ashley Coolman
2
Verwenden Sie einfach (?<=thingy)thingyfür positives Aussehen und (?<!thingy)thingyfür negatives Aussehen . Jetzt unterstützt es sie.
8онстантин Ван
7
@ K._ Ab Februar 2018 ist das noch nicht wahr !! Und es wird einige Zeit dauern, da Browser und Engines die Spezifikation implementieren müssen (aktuell im Entwurf).
Andre Figueiredo

Antworten:

64

^(?!filename).+\.js funktioniert bei mir

getestet gegen:

  • test.js Übereinstimmung
  • blabla.js Übereinstimmung
  • Dateiname.js keine Übereinstimmung

Eine richtige Erklärung für diesen regulären Ausdruck finden Sie unter Regulärer Ausdruck, um mit Zeichenfolgen übereinzustimmen, die kein Wort enthalten.

Look Ahead ist seit Version 1.5 von Javascript verfügbar und wird von allen gängigen Browsern unterstützt

Aktualisiert , um mit filename2.js und 2filename.js übereinzustimmen, jedoch nicht mit filename.js

(^(?!filename\.js$).).+\.js

Benjamin Udink zehn Cate
quelle
5
Diese Frage, die Sie mit verknüpft haben, spricht von einem etwas anderen Problem: dem Abgleichen einer Zeichenfolge, die nirgendwo das Zielwort enthält . Dieser ist viel einfacher: eine Zeichenfolge abgleichen, die nicht mit dem Zielwort beginnt .
Alan Moore
Das ist wirklich schön, es fehlen nur Fälle wie: filename2.js oder filenameddk.js oder ähnliches. Dies ist keine Übereinstimmung, sollte aber eine Übereinstimmung sein.
Daniel
9
@daniel Du hast nach einem Rückblick gefragt, nicht nach einem Ausblick. Warum hast du diese Antwort akzeptiert?
hek2mgl
1
das gegebene stimmt nicht ama.js
inetphantom
1
Der ursprüngliche reguläre Ausdruck mit Lookbehind stimmt nicht überein 2filename.js, der hier angegebene reguläre Ausdruck jedoch. Ein passenderer wäre ^(?!.*filename\.js$).*\.js$. Dies bedeutet, dass alle *.js außer übereinstimmen *filename.js.
weibeld
152

BEARBEITEN: Ab ECMAScript 2018 werden Lookbehind-Behauptungen (auch unbegrenzt) nativ unterstützt .

In früheren Versionen können Sie dies tun:

^(?:(?!filename\.js$).)*\.js$

Dies macht explizit das, was der Lookbehind-Ausdruck implizit tut: Überprüfen Sie jedes Zeichen der Zeichenfolge, ob der Lookbehind-Ausdruck plus der reguläre Ausdruck danach nicht übereinstimmen, und lassen Sie erst dann zu, dass dieses Zeichen übereinstimmt.

^                 # Start of string
(?:               # Try to match the following:
 (?!              # First assert that we can't match the following:
  filename\.js    # filename.js 
  $               # and end-of-string
 )                # End of negative lookahead
 .                # Match any character
)*                # Repeat as needed
\.js              # Match .js
$                 # End of string

Eine weitere Bearbeitung:

Es schmerzt mich zu sagen (zumal diese Antwort so sehr positiv bewertet wurde), dass es einen viel einfacheren Weg gibt, dieses Ziel zu erreichen. Es ist nicht erforderlich, den Lookahead bei jedem Charakter zu überprüfen:

^(?!.*filename\.js$).*\.js$

funktioniert genauso gut:

^                 # Start of string
(?!               # Assert that we can't match the following:
 .*               # any string, 
  filename\.js    # followed by filename.js
  $               # and end-of-string
)                 # End of negative lookahead
.*                # Match any string
\.js              # Match .js
$                 # End of string
Tim Pietzcker
quelle
Funktioniert in vielen Fällen, außer wenn vorangestellte Zeichen vorhanden sind, z. B.: Dateiname.js (Works-Nomatch) Dateiname2.js (Works-Match) blah.js (Works-Match) 2Dateiname.js (funktioniert nicht - Nomatch) --- nachdem ich das gesagt habe, hat der Lookbehind die gleiche Einschränkung, die ich bis jetzt nicht erkannt habe ...
Daniel
9
@ Daniel: Nun, dein Regex (mit Lookbehind) stimmt auch nicht überein 2filename.js. Mein Regex stimmt in genau den gleichen Fällen überein wie Ihr Beispiel-Regex.
Tim Pietzcker
Vergib mir meine Naivität, aber gibt es hier eine Verwendung für die nicht erfassende Gruppe? Ich habe immer gewusst, dass dies nur nützlich ist, wenn versucht wird, die Referenz zum Ersetzen in einer Zeichenfolge zurückzugewinnen. Soweit ich weiß, wird auch dies funktionieren ^ (?! Dateiname \ .js $). * \. Js $
Ich möchte Antworten
1
Nicht ganz, dieser Regex sucht nur am Anfang der Zeichenfolge nach "filename.js". Aber ^(?!.*filename\.js$).*\.js$funktionieren würde. Der Versuch, an Situationen zu denken, in denen die NC-Gruppe möglicherweise noch notwendig ist ...
Tim Pietzcker
Dieser Ansatz kann wie folgt zusammengefasst werden: Anstatt hinter X zu schauen, schauen Sie nach vorne auf jedes Zeichen, das vor X steht.
Sarsaparilla
25

Angenommen, Sie möchten alle finden, denen intnicht Folgendes vorangestellt ist unsigned:

Mit Unterstützung für negative Rückblicke:

(?<!unsigned )int

Ohne Unterstützung für negative Rückblicke:

((?!unsigned ).{9}|^.{0,8})int

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:

(?<!filename)\.js$

würde übersetzen zu:

((?!filename).{8}|^.{0,7})\.js$

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 nicht durch etwas anderes ersetzen.

Kamil Szot
quelle
Ich habe das gerade konvertiert: (?<!barna)(?<!ene)(?<!en)(?<!erne) (?:sin|vår)e?(?:$| (?!egen|egne))zu (?!barna).(?!erne).(?!ene).(?!en).. (?:sin|vår)e?(?:$| (?!egen|egne))dem macht der Trick für meine Bedürfnisse. Nur als weiteres "reales" Szenario. Siehe Link
Eirik Birkeland
Ich denke, Sie meinten:((?!unsigned ).{9}|^.{0,8})int
Pansay
@pansay Ja. Danke dir. Ich habe gerade meine Antwort korrigiert.
Kamil Szot
2
Vielen Dank für die allgemeinere Antwort, die auch dann funktioniert, wenn es notwendig ist, tief im Text übereinzustimmen (wo initial ^ unpraktisch wäre)!
Milos Mrdovic
5

Wenn Sie nach vorne, aber nach hinten schauen können, können Sie zuerst die Zeichenfolge umkehren und dann einen Lookahead durchführen. Natürlich muss noch etwas Arbeit geleistet werden.

Albert Freund
quelle
8
Diese Antwort könnte wirklich verbessert werden. Es scheint mir eher ein Kommentar zu sein.
Mickmackusa
2

Dies ist eine äquivalente Lösung zu Tim Pietzckers Antwort (siehe auch Kommentare derselben Antwort):

^(?!.*filename\.js$).*\.js$

Es bedeutet, Übereinstimmung *.jsaußer*filename.js .

Um zu dieser Lösung zu gelangen, können Sie überprüfen, welche Muster das negative Aussehen ausschließt, und dann genau diese Muster mit einem negativen Aussehen ausschließen.

weibeld
quelle
-1

Im Folgenden finden Sie eine positive JavaScript-Alternative, die zeigt, wie der Nachname von Personen mit 'Michael' als Vorname erfasst wird.

1) Angesichts dieses Textes:

const exampleText = "Michael, how are you? - Cool, how is John Williamns and Michael Jordan? I don't know but Michael Johnson is fine. Michael do you still score points with LeBron James, Michael Green Miller and Michael Wood?";

Holen Sie sich eine Reihe von Nachnamen von Personen namens Michael. Das Ergebnis sollte sein:["Jordan","Johnson","Green","Wood"]

2) Lösung:

function getMichaelLastName2(text) {
  return text
    .match(/(?:Michael )([A-Z][a-z]+)/g)
    .map(person => person.slice(person.indexOf(' ')+1));
}

// or even
    .map(person => person.slice(8)); // since we know the length of "Michael "

3) Lösung prüfen

console.log(JSON.stringify(    getMichaelLastName(exampleText)    ));
// ["Jordan","Johnson","Green","Wood"]

Demo hier: http://codepen.io/PiotrBerebecki/pen/GjwRoo

Sie können es auch ausprobieren, indem Sie das folgende Snippet ausführen.

const inputText = "Michael, how are you? - Cool, how is John Williamns and Michael Jordan? I don't know but Michael Johnson is fine. Michael do you still score points with LeBron James, Michael Green Miller and Michael Wood?";



function getMichaelLastName(text) {
  return text
    .match(/(?:Michael )([A-Z][a-z]+)/g)
    .map(person => person.slice(8));
}

console.log(JSON.stringify(    getMichaelLastName(inputText)    ));

Piotr Berebecki
quelle