/ / Регулярний вираз, який відповідає рядку, що не містить слова? - регулярний вираз, заперечення регулярних виразів, регулярні вирази-пошуки, регулярні вирази-жадібні, регулярні вирази-групи

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

Я знаю, що можна зіставити слово, а потім змінити відповідність за допомогою інших інструментів (наприклад, grep -v). Однак я хотів би знати, чи можна збігати такі рядки не треба містять конкретне слово (наприклад, hede), використовуючи регулярний вираз.

Вхід:

hoho
hihi
haha
hede

Код:

grep "<Regex for "doesn"t contain hede">" input

Бажаний вихід:

hoho
hihi
haha

Відповіді:

для відповіді № 1

Думка про те, що регулярний вираз не підтримує зворотне узгодження, не зовсім відповідає дійсності. Ви можете імітувати таку поведінку, використовуючи негативні огляди:

^((?!hede).)*$

Вираз регулярного виразу буде відповідати будь-якому рядку або рядку без розриву рядка, ні містить (під) рядок "hede". Як вже згадувалося, це не те, що регулярний вираз є "добрим" (або повинен робити), але все-таки це є можливий

І якщо вам також потрібно зрівняти символи розриву рядка, використовуйте Модифікатор DOT-ALL (кінцевий s за наступним зразком):

/^((?!hede).)*$/s

або використовуйте вбудовано:

/(?s)^((?!hede).)*$/

(де /.../ є роздільниками регулярних виразів, тобто не є частиною шаблону)

Якщо модифікатор DOT-ALL недоступний, ви можете імітувати однакову поведінку з класом символів [sS]:

/^((?!hede)[sS])*$/

Пояснення

Рядок - це лише список n символів. До і після кожного символу є порожній рядок. Отже, список n символів n+1 порожні рядки. Розгляньте рядок "ABhedeCD":

    ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐
S = │e1│ A │e2│ B │e3│ h │e4│ e │e5│ d │e6│ e │e7│ C │e8│ D │e9│
└──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┘

index    0      1      2      3      4      5      6      7

де e"s - це порожні рядки. Звичайний вираз (?!hede). дивиться вперед, щоб побачити, чи немає підрядка "hede" щоб бути поміченим, і якщо це так (так бачиться щось інше), то . (крапка) буде відповідати будь-якому символу, крім розриву рядка. Оглядові сторони також називаються твердження нульової ширини тому що вони не "т споживати будь-які символи. Вони лише стверджують / підтверджують щось.

Отже, у моєму прикладі кожен порожній рядок спочатку перевіряється, щоб перевірити, чи немає "hede" вперед, перед тим, як символ споживається символом . (крапка). Регулярний вираз (?!hede). зробить це лише один раз, тому його загортають у групу і повторюють нуль або більше разів: ((?!hede).)*. Нарешті, початок і кінець введення закріплюються, щоб переконатися, що споживається весь вхід: ^((?!hede).)*$

Як бачите, вхідні дані "ABhedeCD" не вдасться, тому що на e3, регулярний вираз (?!hede) не вдається (там є "hede" вперед!).


603 для відповіді №2

Зверніть увагу, що рішення не починати з “Хеде”:

^(?!hede).*$

як правило, набагато ефективніше, ніж рішення не містити “Хеде”:

^((?!hede).)*$

Перший перевіряє наявність "hede" лише у першій позиції вхідного рядка, а не в кожній позиції.


163 для відповіді № 3

Якщо Ви просто використовуєте його для grep, можете використовувати grep -v hede отримати всі рядки, які не містять hede.

ETA О, перечитуючи питання, grep -v це, мабуть, те, що ви мали на увазі під "опціями інструментів".


121 для відповіді № 4

Відповідь:

^((?!hede).)*$

Пояснення:

^початок рядка, ( згрупувати та захопити до 1 (0 або більше разів (збігаючись з якомога більшою кількістю)),
(?! загляньте вперед, чи немає,

hede твій рядок,

) кінець перспективи, . будь-який символ, крім n,
)* кінець 1 (Примітка: оскільки ви використовуєте квантор для цього захоплення, лише 1 ОСТАННЕ повторення захопленого шаблону буде збережено в 1)
$ перед необов'язковим n і кінцем рядка


89 за відповідь № 5

Наведені відповіді цілком чудові, лише академічна думка:

Регулярні вирази у значенні теоретичних інформатик НЕ МОЖЛИВІ робити це так. Для них це мало виглядати приблизно так:

^([^h].*$)|(h([^e].*$|$))|(he([^h].*$|$))|(heh([^e].*$|$))|(hehe.+$)

Це відповідає лише ПОЛНОМУ збігу. Робити це для підматчів було б навіть незручніше.


48 для відповіді № 6

Якщо ви хочете, щоб тест регулярних виразів тільки не вдається, якщо цілий рядок збігів, буде працювати наступне:

^(?!hede$).*

напр. - Якщо ви хочете дозволити всі значення, крім "foo" (тобто "foofoo", "barfoo" і "foobar" пройде, але "foo" не вдасться), використовуйте: ^(?!foo$).*

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

myStr !== "foo"

Можна навіть заперечити назовні тест, якщо вам потрібні будь-які функції регулярного виразу (тут, нечутливість до регістру та відповідність діапазону):

!/^[a-f]oo$/i.test(myStr)

Рішення регулярних виразів у верхній частині може бути корисним, однак, у ситуаціях, коли потрібен позитивний тест регулярного виразу (можливо, API).


47 для відповіді № 7

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


43 для відповіді № 8

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

Vcsn підтримує цей оператор (який він позначає {c}, постфікс).

Спочатку ви визначаєте тип своїх виразів: мітки буквою (lal_char) на вибір a до z наприклад (визначення алфавіту при роботі з доповненням, звичайно, дуже важливе), і "значення", обчислене для кожного слова, є лише логічним значенням: true слово прийнято, false, відхилено.

У Python:

In [5]: import vcsn
c = vcsn.context("lal_char(a-z), b")
c
Out[5]: {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z} →