jage regex - шукаєте альтернативу?


143

Ось регулярний вираз, який прекрасно працює в більшості програм regex:

(?<!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/proposed-regexp-lookbehind . Отже, може пройти деякий час, поки JavaScript скрізь його не підтримує. Краще обережно використовуйте у виробництві!
Ейрік Біркеланд

2
# Оновлення: ES2018 включає в себе вигляд за твердженнями Плюс : - Режим dotAll (прапор s) - Попередження тверджень - Групи захоплення іменованих назв - Властивість Unicode втече
Ешлі Coolman

2
Просто використовуйте (?<=thingy)thingyдля позитивного перегляду назад і (?<!thingy)thingyдля негативного перегляду назад . Тепер він їх підтримує.
Константин Ван

7
@ K._ Станом на лютий 2018 року , це ще не вірно !! І знадобиться певний час, тому що браузери та двигуни повинні реалізувати специфікацію (поточну в чернеті).
Andre Figueiredo

Відповіді:


64

^(?!filename).+\.js працює для мене

перевірено на:

  • матч test.js
  • blabla.js матч
  • filename.js не відповідає

Правильне пояснення цього регулярного виразів можна знайти в регулярному виразі, щоб відповідати рядку, що не містить слова?

Попередження доступне з версії 1.5 JavaScript і підтримується всіма основними браузерами

Оновлено, щоб відповідати filename2.js та 2filename.js, але не filename.js

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


5
Це питання ви пов'язані переговори про декілька іншої проблеми: відповідність рядка , яка не містить цільове слово де - небудь . Це набагато простіше: відповідність рядку, який не починається з цільового слова.
Алан Мур

Це дуже добре, він пропускає лише у таких випадках, як: filename2.js або filenameddk.js або подібні. Це не збіг, але має бути збіг.
Даніель

9
@daniel Ви попросили оглядатись, а не дивитися вперед, чому ви прийняли цю відповідь?
hek2mgl

1
даний не відповідаєa.js
inetphantom

1
Оригінальний регулярний вираз з перспективою не відповідає 2filename.js, але наведений тут регулярний вираз. Більш підходящим був би ^(?!.*filename\.js$).*\.js$. Це означає, що відповідати будь-якому, *.js крім *filename.js .
weibeld

153

EDIT: Починаючи з ECMAScript 2018 року, заперечення тверджень (навіть без обмежень) підтримуються на самому світі .

У попередніх версіях ви можете це зробити:

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

Це явно робить те, що експрес-вираз виконує неявно: перевіряйте кожен символ рядка, якщо вираз lookbehind плюс регулярний вираз після нього не збігаються, і лише тоді дозволяйте цьому символу збігатися.

^                 # 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. Мій регекс збігається в абсолютно тих же випадках, що і у вашому прикладі.
Тім Піцкер

Пробачте мою наївність, але чи є тут користь для групи, яка не захоплює? Я завжди знав, що бути корисним лише при спробі отримати зворотну посилання на заміну в рядку. Наскільки я знаю, це теж спрацює ^ (?! ім'я файлу \ .js $). * \. Js $
Я хочу відповіді

1
Не зовсім те, що регулярне вираження перевіряє "filename.js" лише на початку рядка. Але ^(?!.*filename\.js$).*\.js$працювали б. Намагаючись думати про ситуації, коли ncgroup все ще може знадобитися ...
Тім Піткер

Такий підхід можна назвати так: замість того, щоб озиратися за X, дивитись вперед на кожного персонажа, що постає перед X?
Сарсапарілья

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))на (?!barna).(?!erne).(?!ene).(?!en).. (?:sin|vår)e?(?:$| (?!egen|egne))що робить фокус для моїх потреб. Просто надання цього як іншого "реального" сценарію. Дивіться посилання
Ейрік Біркеланд

Я думаю, ти мав на увазі:((?!unsigned ).{9}|^.{0,8})int
pansay

@pansay Так. Дякую. Я просто виправив свою відповідь.
Каміль Шот

2
Дякую за більш узагальнену відповідь, яка працює навіть там, де є необхідність відповідати глибоко в тексті (де початковий ^ було б недоцільно)!
Мілош Мрдович

5

Якщо ви можете дивитися вперед, але назад, ви можете спершу змінити рядок, а потім виконати пошук. Зрозуміло, потрібно буде ще трохи працювати.


8
Ця відповідь справді могла б вдосконалити деяке вдосконалення. Мені це здається більше коментарем.
mickmackusa

2

Це рівноцінне рішення відповіді Тіма Піцкера (див. Також коментарі до тієї самої відповіді):

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

Це означає, *.jsкрім матчу *filename.js.

Щоб дійти до цього рішення, ви можете перевірити, які зразки виключає негативний вигляд, а потім виключити саме ці шаблони з негативним знаком пошуку.


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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.