Регулярное выражение, которое никогда не будет соответствовать ни

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

Итак, что ваша мысль - что выглядит Regex, никогда не будет соответствовать какой-либо строке?

Изменить. Почему я хочу этого? Ну, во-первых, потому что мне интересно думать о таком выражении, а во-вторых, потому что мне нужно это для script.

В этом script я определяю словарь как Dictionary<string, Regex>. Это содержит, как вы видите, строку и выражение.

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

Если выражение сопоставляется, другому Dictionary<string, long> добавляется значение, возвращаемое выражением. Таким образом, чтобы поймать любые сообщения журнала, которые не соответствуют выражению в словаре, я создал новую группу под названием "unknown".

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

Таким образом, у вас есть причина для этого "не вопрос"...

Ответ 1

Это на самом деле довольно просто, , хотя это зависит от реализации /flags *:

$a

Будет соответствовать символу a после окончания строки. Удачи.

Внимание:
Это выражение дорогое - оно будет сканировать всю строку, найти привязку конца строки и только тогда не найти a и вернуть отрицательное соответствие. (Подробнее см. Комментарий ниже.)


* Первоначально я не много думал о многострочном регулярном выражении, где $ также совпадает с концом строки. Фактически, он будет соответствовать пустой строке прямо перед новой строкой, поэтому обычный символ типа a никогда не появится после $.

Ответ 2

Кредитное плечо negative lookahead:

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

этот RE является противоречием в терминах и поэтому никогда не будет соответствовать чему-либо.

Примечание:
В Python функция re.match() неявно добавляет привязку начала строки (\A) к началу регулярного выражения. Этот якорь важен для производительности: без него вся строка будет отсканирована. Те, кто не использует Python, захотят добавить якорь явно:

\A(?!x)x

Ответ 3

посмотреть вокруг:

(?=a)b

Для новичков регулярных выражений: положительный прогноз (?=a) гарантирует, что следующий символ a, но не меняет местоположение поиска (или включает "a" в согласованной строке). Теперь, когда следующий символ подтвержден как a, оставшаяся часть регулярного выражения (b) соответствует только следующему символу b. Таким образом, это регулярное выражение совпадает только в том случае, если символ одновременно a и b.

Ответ 4

Тот, который был пропущен:

^\b$

Он не может соответствовать, потому что пустая строка не содержит границы слова. Протестировано в Python 2.5.

Ответ 5

a\bc, где \b - это выражение с нулевой шириной, которое соответствует границе слова.

Он не может появляться посредине слова, которое мы вынуждаем.

Ответ 6

$.

.^

$.^

(?!)

Ответ 7

Максимальное соответствие

a++a

По крайней мере один a, за которым следует любое число a, без возврата. Затем попробуйте сопоставить еще один a.

или независимое вспомогательное выражение

Это эквивалентно помещению a+ в независимое подполе, за которым следует еще один a.

(?>a+)a

Ответ 8

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

Обратите внимание, что глаголы также реализованы в PCRE вскоре после этого, поэтому вы можете использовать их на PHP или других языках, используя библиотеку PCRE. (Однако вы не можете использовать Python или Ruby. Они используют свой собственный движок.)

Ответ 9

\B\b

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

Вместе они не могут соответствовать какой-либо позиции.

См. также:

Ответ 10

Как насчет $^ или, может быть, (?!)?  

Ответ 11

Это работает:

$.

Ответ 12

Python не примет его, но Perl будет:

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

Это регулярное выражение должно (теоретически) пытаться сопоставить бесконечное (четное) число w s, потому что первая группа (() s) возвращается в себя. Кажется, что Perl не выдавал никаких предупреждений даже под use strict; use warnings;, поэтому я предполагаю, что он по крайней мере действителен, и мое (минимальное) тестирование не соответствует чему-либо, поэтому я отправляю его для вашей критики.

Ответ 13

Самый быстрый будет:

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

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

Ответ 14

[^\d\D] или (?=a)b или a$a или a^a

Ответ 15

Это не будет работать для Python и многих других языков, но в регулярном выражении Javascript [] - допустимый класс символов, который нельзя сопоставить. Таким образом, следующее должно немедленно сбой, независимо от того, что вводит:

var noMatch = /^[]/;

Мне нравится это лучше, чем /$a/, потому что для меня он четко передает свое намерение. А когда вам это понадобится, мне это нужно, потому что мне нужен резерв для динамически скомпилированного шаблона, основанного на пользовательском вводе. Когда шаблон недействителен, мне нужно заменить его шаблоном, который ничего не соответствует. Упрощенный, он выглядит следующим образом:

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

Ответ 16

Я считаю, что

\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 время от времени должно быть постоянным.

Ответ 17

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

Используя стандартный стандарт @arantius 275k, я запускал следующие тесты в 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 aw последние 3 выражения, поэтому '\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

Мой тестовый файл был создан с использованием формулы для "... Readable Contents And No Duplicate Lines" (на 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 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 getup perusal fork
nighties resurgence chafe

Ответ 18

Так много хороших ответов!

Как и в случае ответа @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)

Ответ 19

Может быть, это?

/$.+^/

Ответ 20

(*FAIL)

или

(*F)

С помощью PCRE и PERL вы можете использовать этот контрольный глагол, который заставляет шаблон немедленно сбой.

Ответ 21

Пустое регулярное выражение

Лучшее регулярное выражение, чтобы никогда ничего не совпадать - пустое регулярное выражение. Но я не уверен, что все движки регулярных выражений примут это.

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

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

Для справки:

  • $^ и $. сделать 36 шагов для вычисления → O (1)
  • \b\B делает 1507 шагов на моем примере и увеличивается с числом символов в вашей строке → O (n)

Более популярная тема об этом вопросе:

Ответ 22

Все примеры, включающие сопоставление границ, следуют одному и тому же рецепту. Рецепт:

  1. Возьмите любой из сопоставителей границ: ^, $,\b,\A,\Z,\z

  2. Делать напротив того, для чего они предназначены

Примеры:

^ и \A предназначены для начала, поэтому не используйте их в начале

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

\b соответствует границе слова, поэтому используйте его между

\b --> .\b.

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

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

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

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

Если вы даете положительный или отрицательный взгляд, следуя чему-то противоположному

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

Их могло быть больше по такой схеме и больше подобных аналогий.

Ответ 23

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

и замените... всеми печатными символами;). Это для текстового файла.

Ответ 24

А что, вместо регулярного выражения, просто используйте инструкцию always if? В javascript:

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

Ответ 25

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

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

Конечно, это не интеллектуальный вызов, а больше похож на программирование ленточных каналов.

Ответ 26

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

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