javascript regex - lihat di belakang alternatif?

143

Berikut adalah regex yang berfungsi dengan baik di sebagian besar implementasi regex:

(?<!filename)\.js$

Ini cocok dengan .js untuk string yang diakhiri dengan .js kecuali untuk filename.js

Javascript tidak memiliki tampilan regex di belakang. Adakah yang bisa menyusun regex alternatif yang mencapai hasil yang sama dan berfungsi dalam javascript?

Berikut adalah beberapa pemikiran, tetapi membutuhkan fungsi pembantu. Saya berharap untuk mencapainya hanya dengan sebuah regex: http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript

daniel
sumber
3
jika Anda hanya perlu memeriksa nama file atau daftar nama file tertentu, mengapa tidak menggunakan dua pemeriksaan saja? periksa apakah itu berakhir dengan .js dan kemudian jika itu benar, periksa apakah itu tidak cocok dengan filename.js atau sebaliknya.
si28719e
3
Pembaruan: Versi Chrome publik terbaru (v62) termasuk (mungkin eksperimental) terlihat di luar kotak: D Namun perhatikan bahwa tampilan masih dalam proposal tahap 3: github.com/tc39/proposal-regexp-lookbehind . Jadi, mungkin perlu waktu hingga JavaScript di mana-mana mendukungnya. Lebih baik berhati-hati dalam menggunakan dalam produksi!
Eirik Birkeland
2
# Pembaruan: ES2018 termasuk pernyataan lookbehind Plus : - mode dotAll (bendera s) - Pernyataan lookbehind - Grup penangkapan yang dinamai - Properti Unicode lolos
Ashley Coolman
2
Cukup gunakan (?<=thingy)thingyuntuk lookbehind positif dan (?<!thingy)thingyuntuk lookbehind negatif . Sekarang ini mendukung mereka.
Константин Ван
7
@ K._ Per Februari 2018 itu belum benar !! Dan itu akan membutuhkan waktu karena browser dan mesin harus mengimplementasikan spesifikasi (saat ini dalam konsep).
Andre Figueiredo

Jawaban:

64

^(?!filename).+\.js bekerja untukku

diuji terhadap:

  • pertandingan test.js
  • cocok blabla.js
  • filename.js tidak cocok

Penjelasan yang tepat untuk regex ini dapat ditemukan di ekspresi Reguler untuk mencocokkan string yang tidak mengandung kata?

Penampilan depan tersedia sejak versi 1.5 dari javascript dan didukung oleh semua browser utama

Diperbarui untuk mencocokkan filename2.js dan 2filename.js tetapi tidak filename.js

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

Benjamin Udink sepuluh Cate
sumber
5
Pertanyaan yang Anda tautkan ke pembicaraan tentang masalah yang sedikit berbeda: mencocokkan string yang tidak mengandung kata target di mana pun . Yang ini lebih sederhana: mencocokkan string yang tidak dimulai dengan kata target.
Alan Moore
Itu sangat bagus, ia hanya melewatkan kasus seperti: filename2.js atau filenameddk.js atau yang serupa. Ini tidak cocok, tetapi harus cocok.
daniel
9
@aniel Anda meminta untuk melihat ke belakang, bukan melihat ke depan, mengapa Anda menerima jawaban ini?
hek2mgl
1
yang diberikan tidak cocok padaa.js
inetphantom
1
Regex asli dengan lookbehind tidak cocok 2filename.js, tetapi regex yang diberikan di sini tidak. Yang lebih tepat adalah ^(?!.*filename\.js$).*\.js$. Ini berarti, cocok dengan *.js kecuali *filename.js .
weibeld
153

EDIT: Dari ECMAScript 2018 dan selanjutnya, pernyataan di balik (bahkan tidak terikat) didukung secara asli .

Di versi sebelumnya, Anda dapat melakukan ini:

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

Ini tidak secara eksplisit apa yang dilakukan ekspresi lookbehind secara implisit: periksa setiap karakter string jika ekspresi lookbehind ditambah regex setelah itu tidak akan cocok, dan hanya kemudian membiarkan karakter itu cocok.

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

Suntingan lain:

Sungguh menyakitkan bagi saya untuk mengatakan (terutama karena jawaban ini telah begitu banyak dipilih) bahwa ada cara yang jauh lebih mudah untuk mencapai tujuan ini. Tidak perlu memeriksa lookahead di setiap karakter:

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

berfungsi dengan baik:

^                 # 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
sumber
Bekerja pada banyak kasus kecuali di mana ada karakter sebelumnya, misalnya: filename.js (works-nomatch) filename2.js (works-match) blah.js (works - match) 2filename.js (tidak berfungsi - nomatch) --- setelah mengatakan itu, penampilannya memiliki batasan yang sama yang aku tidak sadari sampai sekarang ...
daniel
9
@daniel: Ya, regex Anda (dengan lookbehind) juga tidak cocok 2filename.js. Regex saya cocok dengan kasus yang sama persis dengan contoh regex Anda.
Tim Pietzcker
Maafkan kenaifan saya tetapi apakah ada gunanya untuk kelompok yang tidak menangkap di sini? Saya selalu tahu bahwa hanya berguna ketika mencoba mendapatkan kembali referensi untuk penggantian dalam sebuah string. Sejauh yang saya tahu, ini juga akan bekerja ^ (?! nama file \ .js $). * \. Js $
I Want Answers
1
Tidak cukup, regex itu memeriksa "filename.js" hanya di awal string. Tetapi ^(?!.*filename\.js$).*\.js$akan berhasil. Mencoba memikirkan situasi di mana ncgroup mungkin masih diperlukan ...
Tim Pietzcker
Pendekatan ini dapat diringkas sebagai: alih-alih melihat ke belakang X, lihat ke depan pada setiap karakter yang datang sebelum X?
Sarsaparilla
25

Misalkan Anda ingin menemukan semua yang inttidak didahului oleh unsigned:

Dengan dukungan untuk tampilan negatif:

(?<!unsigned )int

Tanpa dukungan untuk pandangan negatif:

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

Ide dasarnya adalah untuk mengambil n karakter sebelumnya dan mengecualikan kecocokan dengan pandangan negatif ke depan, tetapi juga mencocokkan kasus di mana tidak ada n karakter sebelumnya. (di mana n adalah panjang melihat ke belakang).

Jadi regex yang dimaksud:

(?<!filename)\.js$

akan diterjemahkan ke:

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

Anda mungkin perlu bermain dengan menangkap grup untuk menemukan titik yang tepat dari string yang menarik minat Anda atau Anda tidak ingin mengganti bagian tertentu dengan sesuatu yang lain.

Kamil Szot
sumber
Aku hanya dikonversi ini: (?<!barna)(?<!ene)(?<!en)(?<!erne) (?:sin|vår)e?(?:$| (?!egen|egne))untuk (?!barna).(?!erne).(?!ene).(?!en).. (?:sin|vår)e?(?:$| (?!egen|egne))yang melakukan trik untuk kebutuhan saya. Hanya menyediakan ini sebagai skenario "dunia nyata" yang lain. Lihat tautan
Eirik Birkeland
Saya pikir Anda maksud:((?!unsigned ).{9}|^.{0,8})int
pansay
@pansay Ya. Terima kasih. Saya hanya mengoreksi respons saya.
Kamil Szot
2
Terima kasih atas jawaban yang lebih umum yang bekerja bahkan di mana ada kebutuhan untuk mencocokkan jauh di dalam teks (di mana awal ^ tidak praktis)!
Milos Mrdovic
5

Jika Anda dapat melihat ke depan tetapi ke belakang, Anda dapat membalik string terlebih dahulu dan kemudian melakukan lookahead. Beberapa pekerjaan lagi perlu dilakukan, tentu saja.

Albert Friend
sumber
8
Jawaban ini benar-benar dapat menggunakan beberapa perbaikan. Sepertinya lebih seperti komentar untuk saya.
mickmackusa
2

Ini adalah solusi yang setara dengan jawaban Tim Pietzcker (lihat juga komentar dari jawaban yang sama):

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

Artinya, cocok *.jskecuali *filename.js.

Untuk mendapatkan solusi ini, Anda dapat memeriksa pola mana yang tidak termasuk dalam tampilan negatif, dan kemudian mengecualikan pola-pola ini dengan tampilan yang negatif.

weibeld
sumber
-1

Di bawah ini adalah tampilan positif di balik alternatif JavaScript yang menunjukkan cara menangkap nama belakang orang dengan 'Michael' sebagai nama depan mereka.

1) Diberikan teks ini:

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

dapatkan berbagai nama belakang orang yang bernama Michael. Hasilnya harus:["Jordan","Johnson","Green","Wood"]

2) Solusi:

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) Periksa solusinya

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

Demo di sini: http://codepen.io/PiotrBerebecki/pen/GjwRoo

Anda juga dapat mencobanya dengan menjalankan cuplikan di bawah ini.

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
sumber