Я знаю, що можна зіставити слово, а потім змінити відповідність за допомогою інших інструментів (наприклад, 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} →