javascript regex - alternatif arkasına bak?


143

Çoğu regex uygulamasında iyi çalışan bir regex:

(?<!filename)\.js$

Bu, filename.js dışında .js ile biten bir dize için .js ile eşleşir.

Javascript'te regex lookbehind yok. Herkes aynı sonucu elde ve javascript çalışır alternatif bir normal regex koyabilir miyim?

İşte bazı düşünceler, ancak yardımcı işlevlere ihtiyacı var. Sadece bir regex ile başarmayı umuyordum: http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript


3
sadece belirli bir dosya adını veya dosya adları listesini kontrol etmeniz gerekiyorsa, neden sadece iki kontrol kullanmıyorsunuz? .js ile bitip bitmediğini kontrol edin ve sonra bitiyorsa filename.js ile eşleşip eşleşmediğini kontrol edin.
si28719e

3
Güncelleme: En son herkese açık Chrome sürümü (v62), kutudan çıktıkları (muhtemelen deneysel) görünümleri içerir: D Ancak görünümlerin hala teklif aşaması 3'te olduğunu unutmayın: github.com/tc39/proposal-regexp-lookbehind . Bu nedenle, her yerde JavaScript tarafından desteklenmesi biraz zaman alabilir. Üretimde kullanım konusunda dikkatli olun!
Eirik Birkeland

2
# Güncelleme: ES2018 lookbehind iddialarını içerir Plus : - dotAll modu (s bayrağı) - Lookbehind iddiaları - Adlandırılmış yakalama grupları - Unicode özelliği kaçar
Ashley Coolman

2
Sadece kullanmak (?<=thingy)thingyiçin Pozitif Geriye İlerleme ve (?<!thingy)thingyiçin Negatif Geriye İlerleme . Şimdi onları destekliyor.
Константин Ван

7
@ K._ Şub 2018 itibariyle bu henüz doğru değil !! Ve biraz zamana ihtiyaç duyacaktır çünkü tarayıcılar ve motorlar spesifikasyonu uygulamalıdır (taslak halinde geçerli).
Andre Figueiredo

Yanıtlar:


64

^(?!filename).+\.js benim için çalışıyor

karşı test edildi:

  • test.js eşleşmesi
  • blabla.js maçı
  • filename.js eşleşmiyor

Bu regex için uygun bir açıklama, bir sözcük içermeyen dize eşleştirmek için Normal ifade bulunabilir ?

Javascript'in 1.5 sürümünden beri kullanılabilir ve tüm büyük tarayıcılar tarafından desteklenmektedir

Filename2.js ve 2filename.js ile eşleşecek şekilde güncellendi , ancak filename.js ile eşleşmedi

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


5
Bağlandığınız bu soru biraz farklı bir sorundan bahsediyor: hedef kelimeyi hiçbir yerde içermeyen bir dize eşleme . Bu çok daha basit: hedef sözcükle başlamayan bir dizeyi eşleştirmek .
Alan Moore

Bu gerçekten güzel, sadece filename2.js veya filenameddk.js veya benzeri gibi durumları kaçırıyor. Bu bir eşleşme değildir, ancak bir eşleşme olmalıdır.
daniel

9
@daniel İleriye bakmak yerine arkaya bakmayı istediniz, bu cevabı neden kabul ettiniz?
hek2mgl

1
verilen eşleşme a.js
eşleşmiyor

1
Lookbehind ile orijinal normal ifade eşleşmiyor 2filename.js, ancak burada verilen normal ifade eşleşiyor. Daha uygun bir tane olurdu ^(?!.*filename\.js$).*\.js$. Bu, herhangi biri *.js dışında eşleştiği anlamına gelir *filename.js.
weibeld

153

DÜZENLEME: ECMAScript 2018'den itibaren, geriye dönük iddialar (sınırsız bile) yerel olarak desteklenmektedir .

Önceki sürümlerde şunları yapabilirsiniz:

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

Bu, lookbehind ifadesinin örtük olarak ne yaptığını açıkça yapar: lookbehind ifadesi artı eşleşmeden sonra normal ifadeyi içeriyorsa dizenin her karakterini kontrol edin ve ancak bu karakterin eşleşmesine izin verin.

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

Başka bir düzenleme:

Bu hedefe ulaşmak için çok daha kolay bir yol olduğunu söylemek beni özellikle rahatsız ediyor (özellikle de bu cevabın çok fazla değerlendirildiği için). Her karakterde ileriye bakmaya gerek yoktur:

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

aynı şekilde çalışır:

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

Önceki karakterlerin olduğu durumlar dışında birçok durumda çalışır, örneğin: filename.js (works-nomatch) filename2.js (works-match) blah.js (works - match) 2filename.js (çalışmıyor - nomatch) --- bunu söyledikten sonra, lookbehind şimdiye kadar fark etmediğim sınırlamaya sahip ...
daniel

9
@daniel: Regex'iniz (lookbehind ile) de uymuyor 2filename.js. Normal ifadem, örnek normal ifadenizle tam olarak aynı durumlarda eşleşir.
Tim Pietzcker

Saflığımı affet ama burada yakalamayan grup için bir fayda var mı? Ben her zaman sadece bir dize değiştirme için referans geri çekilmek için yararlı olduğunu biliyorum. Bildiğim kadarıyla, bu da işe yarayacaktır ^ (?! dosya adı \ .js $). * \. Js $
Cevaplar İstiyorum

1
Pek değil, bu normal ifade sadece dizenin başında "filename.js" olup olmadığını kontrol eder. Ama ^(?!.*filename\.js$).*\.js$işe yarar. Ncgroup'un hala gerekli olabileceği durumları düşünmeye çalışmak ...
Tim Pietzcker

Bu yaklaşım şöyle özetlenebilir: X'in arkasına bakmak yerine, X'ten önce gelen her karaktere bakalım.
Sarsaparilla

25

intÖncelikle öncesinde olmayan her şeyi bulmak istediğinizi varsayalım unsigned:

Olumsuz bakış desteği ile:

(?<!unsigned )int

Olumsuz bakış desteği olmadan:

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

Temel olarak fikir, önceki karakterleri kapmak ve negatif ileriye bakma ile eşleşmeyi hariç tutmak, ancak önceki n karakterin olmadığı durumlarla eşleşmektir. (burada n, geriye bakma uzunluğudur).

Yani söz konusu normal ifade:

(?<!filename)\.js$

şu dile çevirir:

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

İlginizi çeken dizenin tam yerini bulmak için gruplarla oynamanız gerekebilir veya belirli bir parçayı başka bir şeyle değiştirmek istemezsiniz.


Sadece bu dönüştürülen: (?<!barna)(?<!ene)(?<!en)(?<!erne) (?:sin|vår)e?(?:$| (?!egen|egne))için (?!barna).(?!erne).(?!ene).(?!en).. (?:sin|vår)e?(?:$| (?!egen|egne))hangi zaman ihtiyaçları için hile yok. Bunu başka bir "gerçek dünya" senaryosu olarak sunmak. Bkz. Bağlantı
Eirik Birkeland

Sanırım demek ((?!unsigned ).{9}|^.{0,8})int
istedin

@pansay Evet. Teşekkür ederim. Yanıtımı düzelttim.
Kamil Szot

2
Metnin derinliklerinde eşleşmeye ihtiyaç duyulan yerlerde bile işe yarayan daha genelleştirilmiş cevap için teşekkürler (başlangıç ​​^ pratik değil)!
Milos Mrdovic

5

Eğer ileriye ama geriye bakabilirseniz, önce ipi tersine çevirebilir ve sonra bir ileriye bakabilirsiniz. Tabii ki biraz daha iş yapılması gerekecek.


8
Bu cevap gerçekten bazı iyileştirmeler kullanabilir. Bana bir yorum gibi geliyor.
mickmackusa

2

Bu Tim Pietzcker'ın cevabına eşdeğer bir çözümdür (aynı cevabın yorumlarına da bakınız):

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

Bunun anlamı, maç *.jshariç *filename.js.

Bu çözüme ulaşmak için, negatif görünümün hangi kalıpları hariç tuttuğunu kontrol edebilir ve ardından bu kalıpları tam olarak negatif bir gözle hariç tutabilirsiniz.


-1

Aşağıda, 'Michael' olan kişilerin soyadının ilk adı olarak nasıl yakalanacağını gösteren olumlu bir JavaScript arkasıdır.

1) Bu metin verildiğinde:

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

Michael adında bir dizi soyadı alın. Sonuç şöyle olmalıdır:["Jordan","Johnson","Green","Wood"]

2) Çözüm:

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) Çözümü kontrol edin

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

Burada demo: http://codepen.io/PiotrBerebecki/pen/GjwRoo

Aşağıdaki parçacığı çalıştırarak da deneyebilirsiniz.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.