javascript regex - guarda dietro l'alternativa?


143

Ecco un regex che funziona bene nella maggior parte delle implementazioni regex:

(?<!filename)\.js$

Questo corrisponde a .js per una stringa che termina con .js ad eccezione di nomefile.js

Javascript non ha regex lookbehind. Qualcuno è in grado di mettere insieme una regex alternativa che raggiunge lo stesso risultato e funziona in javascript?

Ecco alcuni pensieri, ma ha bisogno di funzioni di supporto. Speravo di riuscirci solo con un regex: http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript


3
se hai solo bisogno di controllare un nome file specifico o un elenco di nomi di file, perché non usare solo due controlli? controlla se termina in .js e, in tal caso, controlla che non corrisponda a nomefile.js o viceversa.
si28719e

3
Aggiornamento: l'ultima versione pubblica di Chrome (v62) include lookbehind (presumibilmente sperimentali) pronti all'uso: D Nota tuttavia che i lookbehind sono ancora nella fase 3 della proposta: github.com/tc39/proposal-regexp-lookbehind . Quindi, potrebbe volerci un po 'di tempo prima che JavaScript lo supporti ovunque. Meglio stare attenti all'utilizzo in produzione!
Eirik Birkeland,

2
# Aggiornamento: ES2018 include asserzioni lookbehind Plus : - modalità dotAll (la bandiera s) - Asserzioni lookbehind - Gruppi di acquisizione con nome - Fughe di proprietà Unicode
Ashley Coolman

2
Basta usare (?<=thingy)thingyper lookbehind positivo e (?<!thingy)thingyper lookbehind negativo . Ora li supporta.
Константин Ван

7
@ K._ A partire da febbraio 2018 non è ancora vero !! E ci vorrà del tempo perché i browser e i motori devono implementare le specifiche (attualmente in bozza).
Andre Figueiredo,

Risposte:


64

^(?!filename).+\.js per me va bene

testato contro:

  • test.js match
  • partita blabla.js
  • nomefile.js nessuna corrispondenza

Una spiegazione corretta per questa regex può essere trovata nell'espressione regolare per abbinare la stringa che non contiene una parola?

Guarda avanti è disponibile dalla versione 1.5 di javascript ed è supportato da tutti i principali browser

Aggiornato per corrispondere a filename2.js e 2filename.js ma non nomefile.js

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


5
La domanda che hai collegato parla di un problema leggermente diverso: la corrispondenza di una stringa che non contiene la parola target da nessuna parte . Questo è molto più semplice: abbinare una stringa che non inizia con la parola target.
Alan Moore,

È davvero bello, manca solo casi come: nomefile2.js o filenameddk.js o simili. Questa non è una partita, ma dovrebbe essere una partita.
Daniele

9
@daniel Hai chiesto uno sguardo dietro, non uno sguardo avanti, perché hai accettato questa risposta?
hek2mgl,

1
il dato non corrisponde sua.js
inetphantom il

1
La regex originale con lookbehind non corrisponde 2filename.js, ma la regex fornita qui lo fa. Uno più appropriato sarebbe ^(?!.*filename\.js$).*\.js$. Questo significa, abbina qualsiasi *.js tranne *filename.js .
weibeld,

153

EDIT: da ECMAScript 2018 in poi, le asserzioni lookbehind (anche illimitate) sono supportate in modo nativo .

Nelle versioni precedenti, puoi farlo:

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

Questo fa esplicitamente ciò che l'espressione lookbehind sta facendo implicitamente: controlla ogni carattere della stringa se l'espressione lookbehind più la regex dopo che non corrisponderà, e solo allora consenti a quel carattere di corrispondere.

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

Un'altra modifica:

Mi fa male dire (soprattutto perché questa risposta è stata votata così tanto) che esiste un modo molto più semplice per raggiungere questo obiettivo. Non è necessario controllare il lookahead di ogni personaggio:

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

funziona altrettanto bene:

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

Funziona in molti casi, tranne nei casi in cui sono presenti caratteri precedenti, ad esempio: nomefile.js (works-nomatch) nomefile2.js (works-match) blah.js (funziona - corrisponde) 2filename.js (non funziona - nomatch) --- detto questo, lo sguardo dietro ha lo stesso limite che non avevo realizzato fino ad ora ...
Daniel

9
@daniel: Beh, anche la tua regex (con lookbehind) non corrisponde 2filename.js. Il mio regex corrisponde esattamente negli stessi casi del tuo regex di esempio.
Tim Pietzcker,

Perdona la mia ingenuità, ma è utile qui per il gruppo che non cattura? Ho sempre saputo che sarebbe utile solo quando si provasse a recuperare il riferimento per la sostituzione in una stringa. Per quanto ne so, anche questo funzionerà ^ (?! nomefile \ .js $). * \. Js $
Voglio risposte

1
Non del tutto, quel regex controlla "nomefile.js" solo all'inizio della stringa. Ma ^(?!.*filename\.js$).*\.js$funzionerebbe. Cercare di pensare a situazioni in cui il gruppo nc potrebbe essere ancora necessario ...
Tim Pietzcker,

Questo approccio può essere sintetizzato come: invece di guardare dietro X, guarda avanti ogni personaggio che precede X?
Sarsaparilla,

25

Supponiamo che tu voglia trovare tutto ciò che intnon è preceduto da unsigned:

Con supporto per look-behind negativo:

(?<!unsigned )int

Senza supporto per look-behind negativo:

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

Fondamentalmente l'idea è quella di prendere n caratteri precedenti ed escludere la corrispondenza con un aspetto negativo, ma anche abbinare i casi in cui non vi sono n caratteri precedenti. (dove n è la lunghezza del look-behind).

Quindi la regex in questione:

(?<!filename)\.js$

si tradurrebbe in:

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

Potrebbe essere necessario giocare con i gruppi di acquisizione per trovare il punto esatto della stringa che ti interessa o non vuoi sostituire una parte specifica con qualcos'altro.


Ho appena convertito questo: (?<!barna)(?<!ene)(?<!en)(?<!erne) (?:sin|vår)e?(?:$| (?!egen|egne))a (?!barna).(?!erne).(?!ene).(?!en).. (?:sin|vår)e?(?:$| (?!egen|egne))cui fa il trucco per le mie esigenze. Fornendo questo come un altro scenario "reale". Vedi link
Eirik Birkeland

Penso che volevi dire:((?!unsigned ).{9}|^.{0,8})int
pansay

@pansay Sì. Grazie. Ho appena corretto la mia risposta.
Kamil Szot,

2
Grazie per la risposta più generalizzata che funziona anche dove è necessario abbinare in profondità nel testo (dove ^ iniziale sarebbe impraticabile)!
Milos Mrdovic,

5

Se puoi guardare avanti ma indietro, puoi prima invertire la stringa e poi fare uno sguardo. Un po 'più di lavoro dovrà essere fatto, ovviamente.


8
Questa risposta potrebbe davvero usare qualche miglioramento. Mi sembra più un commento.
Mickmackusa,

2

Questa è una soluzione equivalente alla risposta di Tim Pietzcker (vedi anche i commenti della stessa risposta):

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

Significa, match *.jstranne *filename.js.

Per arrivare a questa soluzione, è possibile verificare quali pattern esclude il lookbehind negativo, quindi escludere esattamente questi pattern con un lookahead negativo.


-1

Di seguito è una alternativa positiva a JavaScript che mostra come acquisire il cognome delle persone con "Michael" come nome.

1) Dato questo testo:

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

ottenere una serie di cognomi di persone di nome Michael. Il risultato dovrebbe essere:["Jordan","Johnson","Green","Wood"]

2) Soluzione:

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) Controlla la soluzione

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

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

Puoi anche provarlo eseguendo lo snippet di seguito.

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)    ));

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.