Регекс, який ніколи нічим не відповідає


131

Це може здатися дурним питанням, але я довго спілкувався з деякими моїми колегами-розробниками, і це звучало як цікаве придумати.

Так; як ви думаєте - як виглядає Regex, який ніколи не буде відповідати жодному рядку!

Редагувати : Чому я хочу це? Ну, по-перше, тому, що мені цікаво придумати такий вираз, а по-друге, тому що мені це потрібно для сценарію.

У цьому сценарії я визначаю словник як Dictionary<string, Regex>. Він містить, як бачите, рядок і вираз.

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

Якщо вираз збігається, Dictionary<string, long>додається інше значення, яке повертається виразом. Таким чином, для лову будь-яких журнальних повідомлень, які не співпадають із виразом у словнику, я створив нову групу під назвою "невідомо".

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

Таким чином, у вас є моя причина цього "не справжнього питання" ...


1
Зауважте, що довести негатив дуже важко.
Лассе В. Карлсен

5
Цікаво. Де ви б використали такий регекс?
Чарлі Сольс

1
Я зазначу тут для запису, що багато коментарів, що були вище, і відповіді на це питання, були спочатку з stackoverflow.com/questions/1845078/…, про який я запитував. Марк Гравелл об'єднав їх, що, на мою думку, робить багато таких відповідей химерними без точного оригінального контексту, доки деякі коментарі не мають сенсу. (Можливо, теж вкрадемо потенційні майбутні точки повторення.) Я б припустив, що питання з таким докладним фоном ніколи не можуть бути "точними дублікатами". Що б не було ...
Пітер Хансен

2
Це запитання було додано до поширених запитань про регулярні вирази стека в розділі "Розширений Regex-Fu".
aliteralmind

3
"Зауважте, що довести негатив дуже важко" - це широко вважається, але абсолютно і очевидно помилковим ... як ми знаємо принаймні з того часу, як Евклід довів, що немає найбільшого простого. І будь-який доказ Р - доказ заперечення (не Р). Щоправда, це те, що важко довести емпіричний універсальний, позитивний чи негативний, наприклад, "всі вороні чорні" або "жоден ворон не білий". Алгоритми є аналітичними, а не емпіричними, тому це особливо погане неправильне застосування помилкового правила. наприклад, доказ того, що шаблон "a" не відповідає жодному рядку, який починається з "b", не є "дуже важким".
Джим Балтер

Відповіді:


66

Це насправді досить просто, хоча це залежить від реалізації / прапорів *:

$a

Відповідає символу aпісля закінчення рядка. Удачі.

ПОПЕРЕДЖЕННЯ:
Цей вираз дорогий - він буде сканувати весь рядок, знаходити кінцевий якір і лише потім не знаходити aта повертати негативну відповідність. (Детальніше див. У коментарі нижче.)


* Спочатку я не багато роздумував над багаторядковим режимом regexp, де $також відповідає кінці рядка. Насправді, він би відповідав порожній рядку безпосередньо перед новим рядком , тому звичайний символ, як aніколи, не може з’являтися після цього $.


50
Цей вираз дорогий - він буде сканувати весь рядок, знаходити кінцевий якір і лише тоді не знаходити "а" і повертати негативну відповідність. Я бачу, що для сканування файлу рядків ~ 275k потрібно ~ 480 мс. Зворотне "a ^" займає приблизно той самий час, навіть якщо це може здатися більш ефективним. З іншого боку, негативному пошуку не потрібно нічого сканувати: "(?! X) x" (все, за яким не йде x, а також x, тобто нічого) займає приблизно 30 мс або менше 7% часу. (Вимірюється часом гну та зграєю.)
Аранцій

1
У Perl це відповідатиме поточному значенню $a. Еквівалент Perl $(?:a)також дуже повільний perl -Mre=debug -e'$_=a x 50; /$(?:a)/'.
Бред Гілберт

@ Arantius, будь ласка, дивіться мою відповідь щодо термінів , оскільки я виявив прямо протилежне, виміряне з timeitта python3.
nivk

Не шокує те, що шість років і основна версія Python можуть змінити щось.
аранцій

1
У синтаксисі POSIX BRE $aбуде відповідати буквальному тексту $a, оскільки він $є невід'ємним якорем у цьому шаблоні.
філс

76

Позиція negative lookahead:

>>> import re
>>> x=r'(?!x)x'
>>> r=re.compile(x)
>>> r.match('')
>>> r.match('x')
>>> r.match('y')

ця РЕ є суперечливістю термінів, і тому ніколи нічого не відповідатиме.

ПРИМІТКА:
У Python re.match () неявно додає achor з початковим рядком ( \A) до початку регулярного виразу. Цей якір важливий для продуктивності: без нього буде скановано весь рядок. Ті, хто не використовує Python, хочуть чітко додати якір:

\A(?!x)x

@Chris, так - (?=x)(?!x)і так далі (об'єднання суперечливих диспетчерів і те саме для lookbehinds), і багато з них також працюють для довільних значень x(lookbehinds потребують xs, що відповідають рядкам фіксованої довжини).
Алекс Мартеллі

1
Здається, добре працює. А як же просто (?!) Замість цього? Оскільки () завжди відповідатиме, чи не гарантується (?!), Що ніколи не буде відповідати?
Пітер Хансен

2
@Peter, так, якщо Python приймає цей синтаксис (і, здається, останні випуски), то це також буде суперечливим. Ще одна ідея (не настільки елегантна, але чим більше ідей вам схоже, вам потрібно знайти одну, що працює у всіх RE-двигунах, що цікавлять): r'a\bc'шукаючи межу слів, негайно оточену буквами з обох сторін (варіант: символи без слова на обидві сторони).
Алекс Мартеллі

1
Цікаво, що мій оригінал із простим літералом, який я "знаю", не з’явиться у моєму вході, виявляється найшвидшим у Python. За допомогою вхідного рядка 5 МБ та використання цього в операції sub (), (?! X) x займає 21% більше, (?! ()) На 16%, а ($ ^) на 6% довше. Може бути значним у деяких випадках, хоча і не в моєму.
Пітер Хансен

2
Це може бути досить повільним perl -Mre=debug -e'$_=x x 8; /(?!x)x/'. Ви можете зробити це швидше, закріпивши його на початку \A(?!x)xабо в кінці (?!x)x\z. perl -Mre=debug -e'$_=x x 8; /(?!x)x\z/; /\A(?!x)x/'
Бред Гілберт

43

Те, що було пропущено:

^\b$

Він не може збігатися, оскільки порожній рядок не містить межі слова. Тестовано на Python 2.5.


7
Це найкраща відповідь. Він не використовує lookaheads, не розбивається під деякими реагекс-реалізаціями, не використовує конкретного символу (наприклад, 'a') і не працює в межах максимум 3 етапів обробки (згідно з regex101.com) без сканування цілого. вхідний рядок. Це також легко зрозуміти з першого погляду.
CubicleSoft

1
Це фактично не в Emacs у певних умовах (якщо на початку або в кінці буфера є порожній рядок), однак \`\b\'працює, що замінює синтаксис Emacs на "початок / кінець тексту" (на відміну від "початок / кінець тексту" рядка ").
філс

35

озернись:

(?=a)b

Для новачків-регексів: Позитивний вигляд вперед (?=a)гарантує, що наступний символ є a, але не змінює місце пошуку (або не включає 'a' у відповідне рядок). Тепер, коли наступним символом підтверджено a, що залишилася частина регулярного вираження ( b) відповідає лише тому, що є наступним символом b. Таким чином, цей регулярний вираз відповідає лише тому, що персонаж є одночасно aі bодночасно.


30

a\bc, де \bвираз нульової ширини, що відповідає межі слова.

Він не може з’являтися в середині слова, до чого ми його змушуємо.


Якщо ваш випадок використання дозволяє прив’язати шаблон до початку рядка, то це вдосконалення не дозволить механізму регулярного вибору шукати та перевіряти кожен екземпляр aтексту.
філс

20

$.

.^

$.^

(?!)


1
Симпатичний! Моя підсвідомість відводила мене від таких ідей, як перші три, оскільки вони "незаконні" ... концептуально, але, очевидно, не до регексу. Я не визнаю (!) Одного ... доведеться дивитись на це.
Пітер Хансен

1
Гаразд, мені подобається (?!) Відповідь ... ефективно те, що запропонував Алекс. Зауважте, що в stackoverflow.com/questions/1723182 (на який вказував Amarghosh вище) хтось стверджує, що "деякі смаки" регулярного вираження вважають, що синтаксична помилка. Python любить це чудово, хоча. Зауважте, що всі ваші інші пропозиції не зможуть виконати режими re.DOTALL | re.MULTILINE в Python.
Пітер Хансен

1
Це перевірено? Я міг би припустити, що ^він має особливе значення як перший символ регулярного виразу, і $має лише особливе значення в кінці регулярного вираження, якщо тільки регулярний вираз не є багаторядковим виразом.
ПП.

Насправді в Perl /$./означає щось зовсім інше. Це означає, що відповідає поточному значенню $.(номер рядка вводу) . Навіть /$(.)/міг би щось відповідати, якби ти писав use re '/s';раніше. ( perl -E'say "\n" =~ /$(.)/s || 0')
Бред Гілберт

У синтаксисі POSIX BRE, ^і $спеціальні тільки на початку і в кінці (відповідно) малюнка, так що жоден з $.або .^або $.^буде працювати. (?!)я вважаю, що це Perl / PCRE.
філс

13

Максимальна відповідність

a++a

Щонайменше, aза яким слід будь-яке число as, без зворотного відстеження. Потім спробуйте відповідати ще одному a.

або Незалежне підрядне вираження

Це еквівалентно введенню a+самостійного підрозділу, за яким слідує інший a.

(?>a+)a

10

Perl 5.10 підтримує спеціальні контрольні слова під назвою "дієслова", які вкладаються в (*...)послідовність. (Порівняйте зі (?...)спеціальною послідовністю.) Серед них воно включає (*FAIL)дієслово, яке повертається з регулярного виразу негайно.

Зауважте, що дієслова також реалізовані в PCRE незабаром після цього, тому ви можете використовувати їх у PHP або інших мовах, використовуючи бібліотеку PCRE. (Ти не можеш в Python чи Ruby. Однак вони використовують власний двигун.)


Документи для цього на сайті perldoc.perl.org/perlre.html#%28%2AFAIL%29-%28%2AF%29 кажуть: "Цей шаблон нічого не відповідає і завжди виходить з ладу. Він еквівалентний (?!), Але простіше читати. Насправді, (?!) оптимізується внутрішньо (* FAIL). " Цікаво, що (?!) Є моєю улюбленою "чистою" відповіддю поки що (хоча вона не працює в Javascript). Дякую.
Пітер Хансен

10
\B\b

\bвідповідає межам слова - позиція між літерою та небуквою (або межею рядка).
\Bє його доповненням - воно відповідає положенню між двома літерами або між не літерами.

Разом вони не можуть відповідати жодній позиції.

Дивитися також:


Це здається чудовим рішенням, за умови, що він прикріплений до певної точки (початок тексту здасться розумним). Якщо ви цього не зробите, то це жахливе рішення, тому що кожна несловесна межа в тексті буде перевірена, щоб переконатися, чи не супроводжується межами слова! Тож розумна версія була б чимось на кшталт ^\B\b. У мовах, де "початок тексту" та "початок рядка" мають різний синтаксис, ви хочете використовувати синтаксис "початок тексту", інакше ви будете тестувати кожен рядок. (наприклад, в Emacs це було б \`\B\bабо "\\`\\B\\b".)
phils

З цього приводу я зараз зазначив, що заявленою метою цього питання є отримання регулярного вираження для використання в групі, і в цьому випадку ^проблематично в певному синтаксисі regexp (наприклад, POSIX BRE), де ^є лише якорем, коли це перший символ шаблону, інакше відповідає буквальному ^символу.
філс

@phils - Я думаю, що ти це переосмислюєш :)- це непрактичне питання, де метою було знайти цікаву відповідь - не ефективну відповідь. При цьому шаблон може бути відхилений за лінійний час (з розміром цільової рядка), тому це не погано для регулярного вираження - більшість шаблонів тут однакові і навіть ^можуть бути лінійними, якщо його не оптимізувати.
Кобі

Re: оптимізації, я готовий проігнорувати механізм regexp, який сподівається знайти "початок тексту" в будь-якій іншій позиції :)
phils

Крім того, це не такі непрактичні запитання і відповіді - єдиною причиною я опинився тут, щоб побачити, чи може хтось запропонувати більш ефективне моє рішення для практичної мети налаштування певної змінної Emacs, яка вимагала б значення regexp, але яку я хотіли ефективно відключити.
філс

8

Це, здається, працює:

$.

2
Це схоже на приклад Фердинанда Бейєра.
Gumbo

9
І він буде відповідати в режимі кращих матчів-нових рядків.
Тім Піцкер

У Perl це фактично відповідатиме поточному номеру рядка введення $.. У такому випадку вам доведеться вдатися $(.)чи більше рівнозначно $(?:.).
Бред Гілберт

У синтаксисі POSIX BRE $.буде відповідати літералу, $за яким слідує будь-який символ, оскільки він $є недійсним як якір у цьому шаблоні.
філс

8

Як щодо $^чи, може (?!),? 


3
Розрив рядка буде відповідати цьому виразу в режимі, де ^збігаються початок і $кінець рядка.
Gumbo

4
Можливо, він мав на увазі (?!)- негативний підказ для порожнього рядка. Але деякі аромати регулярного вираження трактують це також як синтаксичну помилку.
Алан Мур

1
Порожній рядок відповідає першому, принаймні в JavaScript.
Роланд Піхлакас

У синтаксисі POSIX BRE $^буде відповідати цим буквальним символам, тому що символи є недійсними як якоря (тобто сама причина, коли ви використовували шаблон, призводить до того, що він не робить те, що хотіли.)
phils

5

Найшвидшими будуть:

r = re.compile(r'a^')
r.match('whatever')

'a' може бути будь-яким неспеціальним символом ('x', 'y'). Реалізація Knio може бути трохи більш чистою, але ця буде швидшою для всіх рядків, не починаючи з того, який символ ви виберете замість "a", оскільки в цих випадках він буде відповідати не після першого символу, а не після другого.


Дійсно, (. ^) Буде приблизно на 10% повільніше, ніж (\ x00 ^) у моєму випадку.
Пітер Хансен

1
Я приймаю це, оскільки використання будь-якого значення, окрім \ n, як символ гарантовано ніколи не збігається, і я вважаю це трохи читабельнішим (враховуючи, що порівняно небагато людей є експертами з регулярних виразів), ніж варіант (?! X) x , хоча я теж проголосував за це. У моєму випадку для будь-якого варіанта мені знадобиться коментар для його пояснення, тому я думаю, що я просто налаштую свою первісну спробу на '\ x00NEVERMATCHES ^'. Я отримую гарантію невідповідності цієї відповіді з моїм оригінальним самодокументуванням. Дякую всім за відповіді!
Пітер Хансен

3
Це насправді працює, і якщо так, хто вирішив розірватися з Unix? У Unix regexps, ^особливий лише як перший символ і аналогічно з $. З будь-яким інструментом Unix цей regexp збирається відповідати будь-якому, що містить буквальний рядок a^.
JaakkoK

Хе, це гарна атака. Я ніколи не тестував проти цього буквального рядка.
Адам Нельсон

О, якщо це зламає юнікс-виразки, то вам сподобається >^.
CubicleSoft

4

Python не прийме його, але Perl:

perl -ne 'print if /(w\1w)/'

Цей теоретичний вираз повинен (теоретично) намагатися відповідати нескінченному (парному) числу ws, оскільки перша група ( ()и) повторюється в собі. Схоже, Perl не видає жодних попереджень, навіть під use strict; use warnings;, тому я припускаю, що принаймні справедливий, і моє (мінімальне) тестування не відповідає нічого, тому я подаю це на вашу критику.


1
Теорія завжди приємна, але на практиці я думаю, що я б переживав за регулярні вирази, описи яких включали слово "нескінченне"!
Пітер Хансен

perl -Mre=debug -e'"www wwww wwwww wwwwww" =~ /(w\1w)/'
Бред Гілберт

@BradGilbert - Якщо запустити, що тут (5.10, трохи застаріло) виробляється "невдалий вираз", як вимагала ОП. Чи відповідає це у вашій системі?
Кріс Луц


4

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

var noMatch = /^[]/;

Мені це подобається краще, ніж /$a/тому, що для мене він чітко передає свої наміри. А що стосується того, коли вам це коли-небудь знадобиться, він мені знадобився, тому що мені потрібен був резервний запас для динамічно складеного шаблону на основі введення користувача. Коли шаблон недійсний, мені потрібно замінити його на шаблон, який нічого не відповідає. Спрощено, це виглядає приблизно так:

try {
    var matchPattern = new RegExp(someUserInput);
}
catch (e) {
    matchPattern = noMatch;
}

4

Усі приклади, що стосуються граничного відповідника, слідують за тим самим рецептом. Рецепт:

  1. Візьміть будь-яке з граничних відповідників: ^, $, \ b, \ A, \ Z, \ z

  2. Зробіть протилежне тому, для чого вони призначені

Приклади:

^ і \ A призначені для початку, тому не використовуйте їх на початку

^ --> .^
\A --> .\A

\ b відповідає межі слова, тому використовуйте його між ними

\b --> .\b.

$, \ Z і \ z призначені для кінця, тому не використовуйте їх наприкінці

$ --> $.
\Z --> \Z.
\z --> \z.

Інші передбачають використання lookahead та lookbehind, які також працюють з тією ж аналогією: Якщо ви даєте позитивну чи негативну підказку з наступним чимось протилежним

(?=x)[^x]
(?!x)x

Якщо ви ставите позитивний чи негативний погляд, слідуючи за чимось протилежним

[^x](?<=x)
x(?<!x)

Їх може бути більше такого зразка і більше таких аналогій.


3

Стільки хороших відповідей!

Подібно до відповіді @ nivk, я хотів би поділитися порівнянням продуктивності Perl для різних варіантів ніколи не узгоджуваних регулярних виразів.

  1. Вхідні дані: псевдовипадкові рядки ascii (25 000 різних рядків, довжина 8-16):

Швидкість регексу:

Total for   \A(?!x)x: 69.675450 s, 1435225 lines/s
Total for       a\bc: 71.164469 s, 1405195 lines/s
Total for    (?>a+)a: 71.218324 s, 1404133 lines/s
Total for       a++a: 71.331362 s, 1401907 lines/s
Total for         $a: 72.567302 s, 1378031 lines/s
Total for     (?=a)b: 72.842308 s, 1372828 lines/s
Total for     (?!x)x: 72.948911 s, 1370822 lines/s
Total for       ^\b$: 79.417197 s, 1259173 lines/s
Total for         $.: 88.727839 s, 1127041 lines/s
Total for       (?!): 111.272815 s, 898692 lines/s
Total for         .^: 115.298849 s, 867311 lines/s
Total for    (*FAIL): 350.409864 s, 285380 lines/s
  1. Введення: / usr / share / dict / words (100 000 англійських слів).

Швидкість регексу:

Total for   \A(?!x)x: 128.336729 s, 1564805 lines/s
Total for     (?!x)x: 132.138544 s, 1519783 lines/s
Total for       a++a: 133.144501 s, 1508301 lines/s
Total for    (?>a+)a: 133.394062 s, 1505479 lines/s
Total for       a\bc: 134.643127 s, 1491513 lines/s
Total for     (?=a)b: 137.877110 s, 1456528 lines/s
Total for         $a: 152.215523 s, 1319326 lines/s
Total for       ^\b$: 153.727954 s, 1306346 lines/s
Total for         $.: 170.780654 s, 1175906 lines/s
Total for       (?!): 209.800379 s, 957205 lines/s
Total for         .^: 217.943800 s, 921439 lines/s
Total for    (*FAIL): 661.598302 s, 303540 lines/s

(Ubuntu на Intel i5-3320M, Linux ядро ​​4.13, Perl 5.26)


Ось порівняння JavaScript деяких методів, висвітлених тут: jsperf.com/regex-that-never-matches
thdoan

2

Я вірю, що

\Z RE FAILS! \A

охоплює навіть випадки, коли регулярний вираз включає прапори типу MULTILINE, DOTALL тощо.

>>> import re
>>> x=re.compile(r"\Z RE FAILS! \A")
>>> x.match('')
>>> x.match(' RE FAILS! ')
>>>

Я вважаю (але я не оцінював це), що незалежно від довжини (> 0) рядка між \Zі \A, час до відмови повинен бути постійним.


2
(*FAIL)

або

(*F)

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


2

Побачивши деякі з цих чудових відповідей, коментар @ arantius (щодо термінів $xпроти x^vs (?!x)x) щодо прийнятої в даний час відповіді змусив мене захотіти вчасно знайти деякі рішення, надані до цього часу.

Використовуючи стандартний рядок 275k @ arantius, я провів наступні тести в Python (v3.5.2, IPython 6.2.1).

TL; DR: 'x^'і 'x\by'найшвидші за коефіцієнтом принаймні ~ 16, і всупереч знаходженню @ arantius, (?!x)xбув серед найповільніших (~ 37 разів повільніше). Тож питання швидкості, безумовно, залежить від впровадження. Випробуйте його самостійно на передбачуваній системі перед тим, як здійснити важливість швидкості для вас.

ОНОВЛЕННЯ: Мабуть, існує велика невідповідність між термінами 'x^'та 'a^'. Будь ласка, перегляньте це запитання для отримання додаткової інформації та попереднє редагування для повільних термінів, aа не x.

In [1]: import re

In [2]: with open('/tmp/longfile.txt') as f:
   ...:     longfile = f.read()
   ...:     

In [3]: len(re.findall('\n',longfile))
Out[3]: 275000

In [4]: len(longfile)
Out[4]: 24733175

In [5]: for regex in ('x^','.^','$x','$.','$x^','$.^','$^','(?!x)x','(?!)','(?=x)y','(?=x)(?!x)',r'x\by',r'x\bx',r'^\b$'
    ...: ,r'\B\b',r'\ZNEVERMATCH\A',r'\Z\A'):
    ...:     print('-'*72)
    ...:     print(regex)
    ...:     %timeit re.search(regex,longfile)
    ...:     
------------------------------------------------------------------------
x^
6.98 ms ± 58.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
.^
155 ms ± 960 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$x
111 ms ± 2.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$.
111 ms ± 1.76 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$x^
112 ms ± 1.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$.^
113 ms ± 1.44 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
$^
111 ms ± 839 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
(?!x)x
257 ms ± 5.03 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
(?!)
203 ms ± 1.56 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
(?=x)y
204 ms ± 4.84 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
(?=x)(?!x)
210 ms ± 1.66 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
x\by
7.41 ms ± 122 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
x\bx
7.42 ms ± 110 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
------------------------------------------------------------------------
^\b$
108 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
\B\b
387 ms ± 5.77 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
------------------------------------------------------------------------
\ZNEVERMATCH\A
112 ms ± 1.52 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
------------------------------------------------------------------------
\Z\A
112 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Перший раз, коли я запустив це, я забув rрозчулити останні три вирази, тому '\b'його інтерпретували як '\x08'символ зворотної області. Однак, на мій подив, 'a\x08c'був швидшим за попередній найшвидший результат! Якщо чесно, він все одно буде відповідати цьому тексту, але я подумав, що все-таки варто відзначити, бо не знаю, чому це швидше.

In [6]: for regex in ('x\by','x\bx','^\b$','\B\b'):
    ...:     print('-'*72)
    ...:     print(regex, repr(regex))
    ...:     %timeit re.search(regex,longfile)
    ...:     print(re.search(regex,longfile))
    ...:     
------------------------------------------------------------------------
y 'x\x08y'
5.32 ms ± 46.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
None
------------------------------------------------------------------------
x 'x\x08x'
5.34 ms ± 66.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
None
------------------------------------------------------------------------
$ '^\x08$'
122 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
None
------------------------------------------------------------------------
\ '\\B\x08'
300 ms ± 4.11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
None

Мій тестовий файл був створений за допомогою формули для "... читабельного вмісту та жодних повторюваних ліній" (на Ubuntu 16.04):

$ ruby -e 'a=STDIN.readlines;275000.times do;b=[];rand(20).times do; b << a[rand(a.size)].chomp end; puts b.join(" "); end' < /usr/share/dict/words > /tmp/longfile.txt

$ head -n5 /tmp/longfile.txt 
unavailable speedometer's garbling Zambia subcontracted fullbacks Belmont mantra's
pizzicatos carotids bitch Hernandez renovate leopard Knuth coarsen
Ramada flu occupies drippings peaces siroccos Bartók upside twiggier configurable perpetuates tapering pint paralyzed
vibraphone stoppered weirdest dispute clergy's getup perusal fork
nighties resurgence chafe

\B\bє жахливо хибним для продуктивності (як і кожен візерунок, який не закріплений на позиції, але ця модель є особливо поганою). Спробуйте ^\B\bзамість цього тестування .
phils

2

Порожній вираз

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

Неможливий регулярний вираз

Інше рішення - створити неможливий регулярний вираз. Я виявив, що $-^для обчислення потрібно лише два кроки незалежно від розміру тексту ( https://regex101.com/r/yjcs1Z/1 ).

Довідково:

  • $^і $.зробіть 36 кроків для обчислення -> O (1)
  • \b\B робить 1507 кроків на моєму зразку і збільшується з кількістю символів у вашому рядку -> O (n)

Більш популярна тема щодо цього питання:


1

Може, це?

/$.+^/

У Python такий підхід працює лише в тому випадку, якщо ви керуєте прапорами : re.compile('$.+^', re.MULTILINE|re.DOTALL).search('a\nb\nc\n')повертає об'єкт відповідності, що відповідає b і c (і всі сусідні та між ними нові рядки). Я рекомендую підходи до негативного підходу, який я рекомендую (тобто не відповідає нічого) для будь-якої комбінації прапорів, з якою вона могла б бути складена.
Алекс Мартеллі

Моє погано - переплутав $і ^.
Кріс Лутц

1
Це може бути спроба шукати кінець рядка до початку, але я виявив, що $ не означає "кінець рядка", якщо це не останній символ регулярного виразу, і я очікую, що застосовується подібна поведінка до ^, тож це може збігатися з підрядкою, що починається з буквального $, і закінчується буквальним ^
pavium

@pavium, він точно не поводиться так у Python або Javascript. Якщо ви не уникнете їх з \ або не включите їх у набір символів з [], спеціальні символи, такі як $ та ^, не повинні розглядатися як літерали. Якою мовою ви це спостерігали?
Пітер Хансен

Принаймні, в Perl це має бути написано /\z.+\A/(див. Perldoc perlre ), що не дозволяє use re '/ms'впливати на багаторядковий та однорядний режим ( ).
Бред Гілберт

0
'[^0-9a-zA-Z...]*'

і замініть ... усіма символами для друку;). Це для текстового файлу.


Я думаю, що для цього повинен бути коротший шлях, але це теж була моя перша думка ^^
FP

4
Це буде відповідати порожній рядку. Щоб зловити всіх можливих символів, використовуйте [^\x00-\xFF]+(для байтових реалізацій).
Фердинанд Бейєр

6
Кращим виразом було б [^\s\S]. Але, як уже сказав Фердинанд Бейер, це буде відповідати порожній рядку.
Gumbo

3
Регекс Дракоші може відповідати порожньому рядку через *; залиште це або замініть його +, і воно має відповідати принаймні одному символу. Якщо клас виключає всі можливі символи, він не може нічого відповідати.
Алан Мур

0

А як же замість регулярного вираження, просто використовуйте завжди хибне твердження if? У JavaScript:

var willAlwaysFalse=false;
if(willAlwaysFalse)
{
}
else
{
}

Я додав коментар у відповідь на питання Чарлі, пояснюючи, чому такий підхід не бажаний. Коротше кажучи, мені потрібна група всередині регулярного вираження, яка завжди буде використовуватися, але в деяких випадках група повинна бути створена для того, щоб вона ніколи не могла відповідати.
Пітер Хансен

-2

Портативне рішення, яке не залежатиме від впровадження регулярного виклику, - це просто використовувати постійний рядок, який ви впевнені, що ніколи не з’являться в повідомленнях журналу. Наприклад, зробіть рядок на основі наступного:

cat /dev/urandom | hexdump | head -20
0000000 5d5d 3607 40d8 d7ab ce72 aae1 4eb3 ae47
0000010 c5e2 b9e8 910d a2d9 2eb3 fdff 6301 c85f
0000020 35d4 c282 e439 33d8 1c73 ca78 1e4d a569
0000030 8aca eb3c cbe4 aff7 d079 ca38 8831 15a5
0000040 818b 323f 0b02 caec f17f 387b 3995 88da
0000050 7b02 c80b 2d42 8087 9758 f56f b71f 0053
0000060 1501 35c9 0965 2c6e 03fe 7c6d f0ca e547
0000070 aba0 d5b6 c1d9 9bb2 fcd1 5ec7 ee9d 9963
0000080 6f0a 2c91 39c2 3587 c060 faa7 4ea4 1efd
0000090 6738 1a4c 3037 ed28 f62f 20fa 3d57 3cc0
00000a0 34f0 4bc2 3067 a1f7 9a87 086b 2876 1072
00000b0 d9e1 6b8f 5432 a60e f0f5 00b5 d9ef ed6f
00000c0 4a85 70ee 5ec4 a378 7786 927f f126 2ec2
00000d0 18c5 46fe b167 1ae6 c87c 1497 48c9 3c09
00000e0 8d09 e945 13ce 7da2 08af 1a96 c24c c022
00000f0 b051 98b3 2bf5 4d7d 5ec4 e016 a50d 355b
0000100 0e89 d9dd b153 9f0e 9a42 a51f 2d46 2435
0000110 ef35 17c2 d2aa 3cc7 e2c3 e711 d229 f108
0000120 324e 5d6a 650a d151 bc55 963f 41d3 66ee
0000130 1d8c 1fb1 1137 29b2 abf7 3af7 51fe 3cf4

Звичайно, це не інтелектуальний виклик, а більше схоже на програмування канальних стрічок .


-6
new Regex(Guid.NewGuid().ToString())

Створює візерунок, що містить лише буквено-цифрові символи та " -" (жоден з них не є спеціальними символами регулярного вирівнювання), але статистично неможливо, щоб той самий рядок не з'являвся де-небудь раніше (тому що це вся суть GUID.)


2
"Статистично неможливо"? Так? Залежно від того, як обчислюється GUID, можна і часто досить просто передбачити наступні GUID (оскільки вони залежать від обчислювальної машини та часу). Ви маєте на увазі "малоймовірно", "з дуже малою ймовірністю", але ви не можете сказати "неможливо" навіть для ідеально випадкових рядків. Ваш Regex буде відповідати нескінченній кількості рядків - це питання шукає питання, яке нічого не відповідатиме. Колись.
Фердинанд Бейер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.