javascript regex - искать альтернативу?

145

Вот регулярное выражение, которое отлично работает в большинстве реализаций регулярных выражений:

(?<!filename)\.js$

Это соответствует .js строке, которая заканчивается на .js, за исключением filename.js

Javascript не поддерживает поиск назад с помощью регулярных выражений. Может ли кто-нибудь собрать альтернативное регулярное выражение, которое дает тот же результат и работает в javascript?

Вот некоторые мысли, но нужны вспомогательные функции. Я надеялся добиться этого только с помощью регулярного выражения: http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript

Дэниел
источник
3
если вам просто нужно проверить конкретное имя файла или список имен файлов, почему бы просто не использовать две проверки? проверьте, заканчивается ли он на .js, а затем, если да, убедитесь, что он не соответствует filename.js или наоборот.
si28719e
3
Обновление: последняя общедоступная версия Chrome (v62) включает (предположительно экспериментальную) ретроспективу из коробки: D Обратите внимание, что ретроспективы все еще находятся на стадии 3 предложения: github.com/tc39/proposal-regexp-lookbehind . Так что может пройти некоторое время, пока JavaScript повсюду его не поддержит. Лучше будьте осторожны при использовании в продакшене!
Eirik Birkeland
2
# Обновление: ES2018 включает утверждения ретроспективного просмотра Плюс : - режим dotAll (флаг s) - Утверждения ретроспективного просмотра - Именованные группы захвата - Экраны свойств Unicode
Эшли Кулман
2
Просто используйте (?<=thingy)thingyдля положительного просмотра назад и (?<!thingy)thingyдля отрицательного просмотра назад . Теперь он их поддерживает.
Константин Ван
7
@ K._ По состоянию на февраль 2018 года это еще не так !! И для этого потребуется некоторое время, потому что браузеры и движки должны реализовать спецификацию (текущую в черновике).
Андре Фигейредо

Ответы:

64

^(?!filename).+\.js работает для меня

протестировано против:

  • test.js соответствует
  • blabla.js соответствует
  • filename.js не соответствует

Правильное объяснение этого регулярного выражения можно найти в разделе Регулярное выражение для соответствия строке, не содержащей слова?

Прогнозирование доступно с версии 1.5 javascript и поддерживается всеми основными браузерами.

Обновлено для соответствия filename2.js и 2filename.js, но не filename.js

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

Бенджамин Удинк тен Кейт
источник
6
Этот вопрос вы связаны переговоры о нескольких иной проблеме: соответствие строки , которая не содержит целевое слово где - нибудь . Это намного проще: сопоставить строку, которая не начинается с целевого слова.
Алан Мур,
Это действительно хорошо, он пропускает только такие случаи, как: filename2.js или file nameddk.js или аналогичные. Это не совпадение, но совпадение должно быть.
Дэниел
10
@daniel Вы просили посмотреть назад, а не в будущее, почему вы приняли этот ответ?
hek2mgl
1
данный один не соответствует наa.js
inetphantom
1
Исходное регулярное выражение с ретроспективой не совпадает 2filename.js, а вот приведенное здесь регулярное выражение соответствует. Было бы более подходящим ^(?!.*filename\.js$).*\.js$. Это означает, что нужно соответствовать любому, *.js кроме *filename.js .
Weibeld
155

РЕДАКТИРОВАТЬ: Начиная с ECMAScript 2018, утверждения просмотра назад (даже без ограничений) поддерживаются изначально .

В предыдущих версиях это можно было сделать:

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

Это явно делает то, что выражение просмотра назад делает неявно: проверяет каждый символ строки, если выражение просмотра назад плюс регулярное выражение после него не соответствует, и только затем разрешает совпадение этого символа.

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

Другое редактирование:

Мне больно говорить (особенно с учетом того, что за этот ответ так много проголосовали), что есть гораздо более простой способ достичь этой цели. Нет необходимости проверять просмотр вперед для каждого символа:

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

работает так же хорошо:

^                 # 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
Тим Пицкер
источник
Работает во многих случаях, кроме случаев, когда есть предшествующие символы, например: filename.js (works-nomatch) filename2.js (works-match) blah.js (работает - соответствует) 2filename.js (не работает - nomatch) --- Сказав это, ретроспективный взгляд имеет то же ограничение, о котором я не осознавал до сих пор ...
Дэниел
9
@daniel: Ну, ваше регулярное выражение (с ретроспективой) тоже не совпадает 2filename.js. Мое регулярное выражение совпадает в тех же случаях, что и ваше регулярное выражение в примере.
Тим Пицкер,
Простите мою наивность, но есть ли здесь смысл для группы без захвата? Я всегда знал, что это полезно только при поиске обратной ссылки для замены в строке. Насколько я знаю, это тоже сработает ^ (?! filename \ .js $). * \. Js $
I Want Answers
1
Не совсем так, это регулярное выражение проверяет наличие «filename.js» только в начале строки. Но ^(?!.*filename\.js$).*\.js$сработает. Пытаюсь подумать о ситуациях, в которых ncgroup все еще может понадобиться ...
Тим Пицкер
Этот подход можно резюмировать так: вместо того, чтобы смотреть назад X, смотреть вперед на каждый символ, который стоит перед X?
Sarsaparilla
25

Предположим, вы хотите найти все, intчему не предшествуют unsigned:

С поддержкой отрицательного ретроспективного анализа:

(?<!unsigned )int

Без поддержки негативного анализа:

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

В основном идея состоит в том, чтобы захватить n предшествующих символов и исключить совпадение с отрицательным упреждающим просмотром, но также сопоставить случаи, когда нет предшествующих n символов. (где n - длина просмотра назад).

Итак, рассматриваемое регулярное выражение:

(?<!filename)\.js$

переведет на:

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

Возможно, вам придется поиграть с группами захвата, чтобы найти точное место в строке, которое вас интересует, или вы не хотите заменять определенную часть чем-то другим.

Камил Сот
источник
Я только что преобразовал это: (?<!barna)(?<!ene)(?<!en)(?<!erne) (?:sin|vår)e?(?:$| (?!egen|egne))to (?!barna).(?!erne).(?!ene).(?!en).. (?:sin|vår)e?(?:$| (?!egen|egne))which делает трюк для моих нужд. Просто представьте это как еще один сценарий «реального мира». См. Ссылку
Эйрик Биркеланд
Я думаю, вы имели в виду:((?!unsigned ).{9}|^.{0,8})int
pansay
@pansay Да. Спасибо. Я просто поправил свой ответ.
Камил
2
Спасибо за более обобщенный ответ, который работает даже там, где есть необходимость найти соответствие глубоко в тексте (где начальный ^ был бы непрактичным)!
Милош Мрдович
4

Если вы можете смотреть вперед, но назад, вы можете сначала перевернуть строку, а затем выполнить просмотр вперед. Конечно, нужно будет проделать еще немного работы.

Альберт Френд
источник
8
Этот ответ действительно можно улучшить. Мне это больше похоже на комментарий.
mickmackusa
2

Это эквивалентное решение для ответа Тима Пицкера (см. Также комментарии к тому же ответу):

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

Это означает, что матч *.jsкроме *filename.js.

Чтобы найти это решение, вы можете проверить, какие шаблоны исключает отрицательный просмотр назад, а затем исключить именно эти шаблоны с помощью отрицательного просмотра назад.

Weibeld
источник
-1

Ниже приведена альтернатива JavaScript с положительным обзором, показывающая, как записывать фамилии людей, в которых имя «Майкл».

1) Учитывая этот текст:

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

получить массив фамилий людей по имени Майкл. Результат должен быть:["Jordan","Johnson","Green","Wood"]

2) Решение:

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) Проверить решение

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

Демо здесь: http://codepen.io/PiotrBerebecki/pen/GjwRoo

Вы также можете попробовать это, запустив приведенный ниже фрагмент.

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

Петр Беребекский
источник