javascript regex – uita-te în spatele alternativă? (Programare, Javascript, Regex)

daniel a intrebat.

Aici este un regex care funcționează bine în majoritatea implementărilor regex:

(?<!filename).js$

Aceasta se potrivește cu .js pentru un șir de caractere care se termină cu .js, cu excepția filename.js

Javascript nu are regex lookbehind. Este cineva capabil să pună împreună un regex alternativ care să obțină același rezultat și să funcționeze în javascript?

Iată câteva idei, dar are nevoie de funcții de ajutor. Speram să obțin acest lucru doar cu un regex:http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript

Comentarii

  • dacă trebuie doar să verificați un anumit nume de fișier sau o listă de nume de fișiere, de ce să nu folosiți doar două verificări? verificați dacă se termină în .js și apoi, dacă da, verificați dacă nu se potrivește cu numele fișierului.js sau viceversa. –  > Por si28719e.
  • Actualizare: Cea mai recentă versiune publică de Chrome (v62) include (probabil experimental) lookbehinds din start 😀 Rețineți totuși că lookbehinds sunt încă în stadiul de propunere 3: github.com/tc39/proposal-regexp-lookbehind . Așadar, ar putea dura ceva timp până când JavaScript îl va suporta peste tot. Mai bine fiți atenți la utilizarea în producție! –  > Por Eirik Birkeland.
  • # Actualizare: ES2018 include afirmații de tip lookbehind Plus: – Modul dotAll (steagul s) – Aserțiuni Lookbehind – Grupuri de captură numite – Evadări ale proprietăților Unicode  > Por Ashley Coolman.
  • Folosiți doar (?<=thingy)thingy pentru lookbehind pozitiv și (?<!thingy)thingy pentru lookbehind negativ. Acum le sprijină. –  > Por Константин Ван.
  • @K._ Începând cu februarie 2018 asta nu e adevărat încă!!! Și va fi nevoie de ceva timp, deoarece browserele și motoarele trebuie să implementeze specificația (actuală în proiect). –  > Por Andre Figueiredo.
6 răspunsuri
Benjamin Udink ten Cate

^(?!filename).+.js funcționează pentru mine

testat împotriva:

  • test.js match
  • blabla.js se potrivește
  • filename.js nu se potrivește

O explicație corectă pentru acest regex poate fi găsită la Expresie regulată pentru a potrivi șirul care nu conține un cuvânt?

Look ahead este disponibil din versiunea 1.5 a javascript și este suportată de toate browserele importante

Actualizat pentru a se potrivi cu filename2.js și 2filename.js, dar nu cu filename.js

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

Comentarii

  • Întrebarea la care ați făcut legătura vorbește despre o problemă ușor diferită: potrivirea unui șir de caractere care nu conține cuvântul țintă oriunde. Aceasta este mult mai simplă: potrivirea unui șir de caractere care nu conține cuvântul țintă. începe cu cuvântul țintă. –  > Por Alan Moore.
  • Este foarte frumos, doar că ratează cazuri precum: filename2.js sau filenameddk.js sau similare. Nu se potrivește, dar ar trebui să fie o potrivire. –  > Por daniel.
  • @daniel Ați cerut un look-behind, nu un look-ahead, de ce ați acceptat acest răspuns? –  > Por hek2mgl.
  • cel dat nu se potrivește pe a.js –  > Por inetphantom.
  • Regex-ul original cu lookbehind nu se potrivește 2filename.js, , dar regex-ul dat aici da. O formulă mai potrivită ar fi ^(?!.*filename.js$).*.js$. Aceasta înseamnă că se potrivește cu orice *.js cu excepția *filename.js. –  > Por weibeld.
Tim Pietzcker

EDIT: De la ECMAScript 2018 încoace, aserțiunile lookbehind (chiar și cele fără limită) sunt suportate nativ.

În versiunile anterioare, puteți face acest lucru:

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

Acest lucru face în mod explicit ceea ce expresia lookbehind face în mod implicit: verifică fiecare caracter al șirului dacă expresia lookbehind plus regex-ul de după ea nu se va potrivi și numai atunci permite ca acel caracter să se potrivească.

^                 # 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

O altă modificare:

Mă doare să spun (mai ales că acest răspuns a fost votat atât de mult) că există o modalitate mult mai ușoară de a atinge acest obiectiv. Nu este nevoie să verificați lookahead la fiecare caracter:

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

funcționează la fel de bine:

^                 # 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

Comentarii

  • Funcționează într-o mulțime de cazuri, cu excepția celor în care există caractere premergătoare, de exemplu: filename.js (funcționează-nomatch) filename2.js (funcționează-match) blah.js (funcționează – match) 2filename.js (nu funcționează – nomatch) — Acestea fiind spuse, lookbehind-ul are aceeași limitare de care nu mi-am dat seama până acum… –  > Por daniel.
  • @daniel: Ei bine, nici regex-ul tău (cu lookbehind) nu se potrivește 2filename.js. Regex-ul meu se potrivește exact în aceleași cazuri ca și regex-ul tău de exemplu. –  > Por Tim Pietzcker.
  • Iertați-mi naivitatea, dar există o utilizare pentru grupul care nu captează aici? Întotdeauna am știut că este util doar atunci când încerc să culeg referințe pentru înlocuirea unui șir de caractere. Din câte știu, și acest lucru va funcționa ^(?!filename.js$).*.js$ –  > Por Vreau răspunsuri.
  • Nu chiar, acel regex verifică dacă există „filename.js” doar la începutul șirului. Dar ^(?!.*filename.js$).*.js$ ar funcționa. Încerc să mă gândesc la situații în care ncgroup ar putea fi totuși necesar… –  > Por Tim Pietzcker.
  • Această abordare poate fi rezumată astfel: în loc să vă uitați în spatele lui X, uitați-vă înainte la fiecare caracter care vine înainte de X? –  > Por Sarsaparilla.
Kamil Szot

Să presupunem că doriți să găsiți toate int care nu sunt precedate de unsigned:

Cu suport pentru look-behind negativ:

(?<!unsigned )int

Fără suport pentru căutarea negativă:

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

Practic, ideea este de a lua n caractere precedente și de a exclude potrivirea cu o anticipare negativă, dar și de a potrivi cazurile în care nu există n caractere precedente. (unde n este lungimea de căutare în urmă).

Așadar, regex-ul în cauză:

(?<!filename).js$

s-ar traduce prin:

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

S-ar putea să fie nevoie să vă jucați cu grupurile de captură pentru a găsi locul exact al șirului care vă interesează sau dacă doriți să înlocuiți o anumită parte cu altceva.

Comentarii

  • Tocmai am convertit acest lucru: (?<!barna)(?<!ene)(?<!en)(?<!erne) (?:sin|vår)e?(?:$| (?!egen|egne)) în (?!barna).(?!erne).(?!ene).(?!en).. (?:sin|vår)e?(?:$| (?!egen|egne)) care se potrivește perfect pentru nevoile mele. Doar oferind acest lucru ca un alt scenariu „din lumea reală”. A se vedea link –  > Por Eirik Birkeland.
  • Cred că ați vrut să spuneți: ((?!unsigned ).{9}|^.{0,8})int –  > Por pansay.
  • @pansay Da. Mulțumesc. Tocmai mi-am corectat răspunsul. –  > Por Kamil Szot.
  • Mulțumesc pentru răspunsul mai generalizat, care funcționează chiar și în cazul în care este necesar să se potrivească în profunzimea textului (unde ^ inițial ar fi impracticabil)! –  > Por Milos Mrdovic.
Albert Friend

Dacă puteți să vă uitați înainte, dar și înapoi, ați putea inversa mai întâi șirul și apoi să faceți un lookahead. Desigur, va trebui să se facă mai multă muncă.

Comentarii

  • Acest răspuns ar putea fi îmbunătățit. Mie mi se pare mai degrabă un comentariu. –  > Por mickmackusa.
weibeld

Aceasta este o soluție echivalentă cu răspunsul lui Tim Pietzcker (a se vedea și comentariile aceluiași răspuns):

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

Înseamnă că, potrivirea *.js cu excepția *filename.js.

Pentru a ajunge la această soluție, puteți verifica ce tipare exclude lookbehind negativ și apoi excludeți exact aceste tipare cu un lookahead negativ.

Piotr Berebecki

Mai jos este o alternativă JavaScript de lookbehind pozitiv care arată cum se poate captura numele de familie al persoanelor care au ca prenume „Michael”.

1) Având în vedere acest text:

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?";

obțineți o matrice de nume de familie ale persoanelor cu numele Michael. rezultatul ar trebui să fie ["Jordan","Johnson","Green","Wood"]

2) Soluție: „Așteptați-vă la o soluție:

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) Verificați soluția

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

Demonstrație aici: http://codepen.io/PiotrBerebecki/pen/GjwRoo

De asemenea, o puteți încerca rulând fragmentul de mai jos.