Um Regex que nunca será correspondido por nada

131

Pode parecer uma pergunta estúpida, mas tive uma longa conversa com alguns de meus colegas desenvolvedores e pareceu uma coisa divertida de se pensar.

Assim; Qual é o seu pensamento - como é um Regex, que nunca será correspondido por nenhuma string!

Edit : Por que eu quero isso? Bem, primeiro porque acho interessante pensar em uma expressão assim e, em segundo lugar, porque preciso dela para um script.

Nesse script eu defino um dicionário como Dictionary<string, Regex>. Isso contém, como você vê, uma string e uma expressão.

Com base nesse dicionário, crio métodos que todos usam esse dicionário apenas como referência sobre como devem fazer seu trabalho, um deles corresponde às expressões regulares em um arquivo de log analisado.

Se uma expressão for correspondida, outra Dictionary<string, long>será adicionada um valor retornado pela expressão. Portanto, para capturar quaisquer mensagens de log que não correspondam a uma expressão no dicionário, criei um novo grupo chamado "desconhecido".

A este grupo, tudo o que não corresponde a nada é adicionado. Mas, para evitar que a expressão "desconhecida" não corresponda (por acidente) a uma mensagem de log, eu tive que criar uma expressão que certamente nunca é correspondida, independentemente da string que eu fornecer.

Portanto, aí está minha razão para esta "não ser uma pergunta real" ...

Florian Peschka
fonte
1
Observe que é muito difícil provar um negativo.
Lasse V. Karlsen
5
Interessante. Onde você usaria esse regex?
Charlie Salts
1
Anotarei aqui para registrar que muitos dos comentários acima e respostas a esta pergunta foram originalmente de stackoverflow.com/questions/1845078/…, que pedi. Marc Gravell os fundiu, o que acho que torna muitas dessas respostas meio estranhas sem o contexto original preciso, a ponto de alguns comentários não parecerem fazer sentido. (Provavelmente também rouba possíveis pontos de referência futuros.) Eu sugeriria que perguntas com antecedentes tão detalhados nunca pudessem ser "duplicatas exatas". Seja qual for ...
Peter Hansen
2
Esta pergunta foi adicionada à FAQ de expressões regulares de estouro de pilha , em "Regex-Fu avançado".
Alreralmind
3
"Note que é muito difícil provar um negativo" - isso é amplamente aceito, ainda que totalmente e obviamente falso ... como sabemos pelo menos desde que Euclides provou que não há o melhor primo. E qualquer prova de P é uma prova da negação de (não de P). O que é verdade é que é difícil provar um universal empírico, positivo ou negativo, por exemplo, "todos os corvos são pretos" ou "nenhum corvo é branco". Os algoritmos são analíticos, não empíricos, portanto, essa é uma má aplicação particularmente ruim da regra falsa. por exemplo, uma prova de que o padrão 'a' não corresponde a nenhuma sequência que começa com 'b' não é "muito difícil".
Jim Balter

Respostas:

66

Na verdade, isso é bastante simples, embora dependa da implementação / flags *:

$a

Combina um caractere aapós o final da string. Boa sorte.

AVISO:
Essa expressão é cara - ela varrerá a linha inteira, localizará a âncora de fim de linha e só então não encontrará a ae retornará uma correspondência negativa. (Veja o comentário abaixo para mais detalhes.)


* Originalmente, não pensei muito no regexp no modo multilinha, onde $também corresponde ao final de uma linha. Na verdade, ele corresponderia à string vazia logo antes da nova linha , para que um caractere comum como anunca possa aparecer depois $.

Ferdinand Beyer
fonte
50
Essa expressão é cara - ela varrerá a linha inteira, encontrará a âncora de fim de linha e só então não encontrará o "a" e retornará uma correspondência negativa. Vejo que demora ~ 480ms para digitalizar um arquivo de linha de ~ 275k. O inverso "a ^" leva aproximadamente o mesmo tempo, mesmo que pareça mais eficiente. Por outro lado, um observador negativo não precisa escanear nada: "(?! X) x" (qualquer coisa que não seja seguida por um x também seguida por um x, ou seja, nada) leva cerca de 30ms, ou menos de 7% do tempo. (Medido com o tempo gnu e egrep.)
Arantius
1
No Perl, isso corresponderá ao valor atual de $a. É equivalente a Perl $(?:a)também é muito lento perl -Mre=debug -e'$_=a x 50; /$(?:a)/'.
amigos estão dizendo sobre brad gilbert
@arantius, veja minha resposta em relação ao tempo , pois achei exatamente o oposto medido com timeite python3.
Nivk
Não é chocante que seis anos e uma versão principal do Python possam mudar as coisas.
Arantius
1
Na sintaxe POSIX BRE, $acorresponderá ao texto literal $a, porque $é inválido como uma âncora nesse padrão.
phils
76

Alavancagem negative lookahead:

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

este ER é uma contradição em termos e, portanto, nunca corresponderá a nada.

NOTA:
No Python, re.match () adiciona implicitamente uma âncora no início da string ( \A) ao início da expressão regular. Essa âncora é importante para o desempenho: sem ela, toda a cadeia será varrida. Aqueles que não usam Python vão querer adicionar a âncora explicitamente:

\A(?!x)x
Alex Martelli
fonte
@ Chris, sim - também, (?=x)(?!x)e assim por diante (concatenações de visões contraditórias e o mesmo para olhar para trás), e muitos deles também trabalham para valores arbitrários de x(as necessidades de lookbehinds xs que correspondem a cadeias de comprimento fixo).
Alex Martelli
1
Parece funcionar bem. Mas e quanto (?!)? Como () sempre corresponderá, (?!) Não será garantido que nunca corresponda?
5117 Peter Hansen
2
@ Peter, sim, se o Python aceitar essa sintaxe (e os lançamentos recentes parecem), isso também seria contraditório. Outra idéia (não tão elegante, mas quanto mais idéias você obtiver, mais provável será encontrar uma que funcione em todos os mecanismos de interesse do ER):, r'a\bc'procurando um limite de palavras imediatamente cercado por letras dos dois lados (variante: caracteres não-palavras em ambos os lados).
Alex Martelli
1
Curiosamente, meu original com um literal simples que eu "sei" não aparecerá na minha entrada acaba sendo mais rápido, em Python. Com uma sequência de entrada de 5 MB e usando-a em uma operação sub (), (?! X) x leva 21% mais tempo, (?! ()) É 16% e ($ ^) 6% mais. Pode ser significativo em alguns casos, embora não no meu.
31520 Peter Hansen
2
Isso pode ser bem lento perl -Mre=debug -e'$_=x x 8; /(?!x)x/'. Você pode torná-lo mais rápido ancorando-o no início \A(?!x)xou no final (?!x)x\z. perl -Mre=debug -e'$_=x x 8; /(?!x)x\z/; /\A(?!x)x/'
Brad Gilbert
43

Um que foi esquecido:

^\b$

Não pode corresponder porque a sequência vazia não contém um limite de palavras. Testado em Python 2.5.

Mark Byers
fonte
7
Esta é a melhor resposta. Ele não usa lookaheads, não quebra em algumas implementações de regex, não usa um caractere específico (por exemplo, 'a') e falha em um máximo de três etapas de processamento (de acordo com regex101.com) sem verificar o conjunto sequência de entrada. Isso também é fácil de entender de relance.
CubicleSoft
1
Isso realmente falha no Emacs em determinadas condições (se houver uma linha em branco no início ou no final do buffer), no entanto \`\b\'funciona, que substitui a sintaxe do Emacs por "início / fim de texto" (em oposição a "início / fim" da linha").
phils
35

olhar em volta:

(?=a)b

Para iniciantes em regex: o olhar positivo à frente (?=a)garante que o próximo caractere seja a, mas não altere o local da pesquisa (ou inclua o 'a' na sequência correspondente). Agora que o próximo caractere está confirmado a, a parte restante do regex ( b) corresponde apenas se o próximo caractere for b. Portanto, esse regex corresponde apenas se um caractere for ao mesmo tempo ae bao mesmo tempo.

Amarghosh
fonte
30

a\bc, onde \bé uma expressão de largura zero que corresponde ao limite da palavra.

Não pode aparecer no meio de uma palavra, o que forçamos.

P Shved
fonte
Se o seu caso de uso permitir ancorar o padrão no início da cadeia, esse aprimoramento impedirá que o mecanismo regexp procure e teste todas as instâncias de um ano texto.
precisa saber é
20

$.

.^

$.^

(?!)

Knio
fonte
1
Fofa! Meu subconsciente me afastou de idéias como as três primeiras, pois são "ilegais" ... conceitualmente, mas obviamente não para o regex. Não reconheço o (!) ... terá que procurar esse.
5119 Peter Hansen
1
Ok, então, eu gosto da resposta (?!) ... efetivamente o que Alex sugeriu. Observe que em stackoverflow.com/questions/1723182 (apontado por Amarghosh acima) alguém afirma que "alguns sabores" do regex considerariam um erro de sintaxe. Python gosta muito bem. Observe que todas as suas outras sugestões falhariam nos modos re.DOTALL | re.MULTILINE no Python.
5119 Peter Hansen
1
Isso foi testado? Eu teria assumido que ^só tem significado especial como o primeiro caractere de uma regexp e $só tem significado especial no final de uma regexp, a menos que a expressão regular seja uma expressão de várias linhas.
PP.
Na verdade, em Perl /$./significa algo totalmente diferente. Significa corresponder ao valor atual de $.(número da linha de entrada) . Mesmo /$(.)/poderia corresponder a algo se você escreveu use re '/s';antes. ( perl -E'say "\n" =~ /$(.)/s || 0')
Brad Gilbert
Na sintaxe POSIX BRE, ^e $são especiais apenas no início e no final (respectivamente) do padrão, portanto, nenhum $.ou .^ou $.^funcionaria. (?!)é um recurso Perl / PCRE, acredito.
26418 phils
13

Correspondência máxima

a++a

Pelo menos um aseguido por qualquer número de a's, sem retroceder. Em seguida, tente combinar mais um a.

ou subexpressão independente

Isso é equivalente a colocar a+uma subexpressão independente, seguida por outra a.

(?>a+)a
Brad Gilbert
fonte
10

O Perl 5.10 suporta palavras de controle especiais chamadas "verbos", que são colocadas em (*...)seqüência. (Compare com a (?...)sequência especial.) Entre eles, inclui o (*FAIL)verbo que retorna da expressão regular imediatamente.

Observe que os verbos também são implementados no PCRE logo depois, para que você possa usá-los em PHP ou outras linguagens usando a biblioteca PCRE também. (No entanto, você não pode em Python ou Ruby. Eles usam seu próprio mecanismo.)

Kang Seonghoon
fonte
Os documentos para isso em perldoc.perl.org/perlre.html#%28%2AFAIL%29-%28%2AF%29 dizem "Esse padrão não corresponde a nada e sempre falha. É equivalente a (?!), Mas é mais fácil de leia. De fato, (?!) é otimizado para (* FAIL) internamente. " Interessante, já que (?!) É a minha resposta "pura" favorita até o momento (mesmo que não funcione em Javascript). Obrigado.
6269 Peter Hansen
10
\B\b

\bcorresponde aos limites da palavra - a posição entre uma letra e uma não-letra (ou o limite da string).
\Bé seu complemento - ele corresponde à posição entre duas letras ou entre não letras.

Juntos, eles não podem corresponder a nenhuma posição.

Veja também:

Kobi
fonte
Essa parece ser uma excelente solução, desde que ancorada em um ponto específico (o início do texto pareceria sensato). Se você não fizer isso, é uma solução terrível , porque todos os limites que não sejam palavras no texto serão testados para ver se são seguidos por um limite de palavras! Portanto, a versão sensata seria algo parecido ^\B\b. Nos idiomas em que "início de texto" e "início de linha" têm sintaxe diferente, convém usar a sintaxe "início de texto"; caso contrário, você estará testando todas as linhas. (por exemplo, em Emacs isso seria \`\B\bou "\\`\\B\\b".)
phils
Dito isso, observei agora que o objetivo declarado dessa pergunta é obter um regexp para uso em um grupo, caso em que ^é problemático em certa sintaxe do regexp (por exemplo, POSIX BRE), onde ^é apenas uma âncora quando é o primeiro caractere do padrão e corresponde a um ^caractere literal .
phils
@phils - Eu acho que você está pensando demais :)- essa é uma pergunta não prática, onde o objetivo era encontrar uma resposta interessante - e não uma resposta eficiente. Dito isso, o padrão pode ser rejeitado no tempo de liner (com o tamanho da cadeia de destino), portanto, não é ruim para uma regex - a maioria dos padrões aqui é a mesma e ^pode ser linear se não for otimizada.
Kobi
Re: otimizações, estou disposto a ignorar um motor regexp que espera encontrar "o início do texto" em qualquer outra posição :)
phils
Além disso, não é uma pergunta e tanto impraticável - a única razão pela qual acabei aqui foi ver se alguém poderia sugerir uma solução mais eficiente para mim, com o objetivo prático de configurar uma variável Emacs específica que exigisse um valor de regexp, mas que eu queria efetivamente desativar.
phils
8

Isso parece funcionar:

$.
Jerry Fernholz
fonte
2
Isso é semelhante ao exemplo de Ferdinand Beyer.
Gumbo #
9
E corresponderá no modo dot-match-newlines.
Tim Pietzcker 12/11/2009
No Perl, isso realmente corresponderá ao número da linha de entrada atual $.. Nesse caso, você deve recorrer $(.)ou mais equivalente $(?:.).
amigos estão dizendo sobre brad gilbert
Na sintaxe POSIX BRE, $.corresponderá a um literal $seguido por qualquer caractere, porque $é inválido como uma âncora nesse padrão.
phils 26/08
8

Que tal $^ou talvez (?!)

Bob
fonte
3
Uma quebra de linha será correspondida por essa expressão no modo em que ^corresponde ao início e $ao final de uma linha.
Gumbo #
4
Talvez ele quis dizer (?!)- um olhar negativo para uma corda vazia. Mas alguns tipos de expressões regulares também tratam isso como um erro de sintaxe.
1213 Alan Moore
1
Uma sequência vazia corresponde à primeira, pelo menos em JavaScript.
Roland Pihlakas
Em POSIX sintaxe BRE, $^irá corresponder esses caracteres literais, porque os personagens são inválidos como âncoras (ou seja, a razão que você usou o padrão faz com que ele não fazer o que você queria.)
phils
5

O mais rápido será:

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

'a' pode ser qualquer caractere não especial ('x', 'y'). A implementação do Knio pode ser um pouco mais pura, mas essa será mais rápida para todas as strings que não começarem com o caractere que você escolher, em vez de 'a', porque não corresponderá ao primeiro caractere, e sim ao segundo nesses casos.

Adam Nelson
fonte
De fato, (. ^) Seria aproximadamente 10% mais lento que (\ x00 ^) no meu caso.
31520 Peter Hansen
1
Estou aceitando isso, já que usar qualquer outro valor que não seja \ n, pois é garantido que o caractere nunca corresponda, e eu o vejo como um pouco mais legível (considerando que relativamente poucas pessoas são especialistas em regex) do que a opção (?! X) x , embora eu tenha votado nessa também. No meu caso, para qualquer uma das opções, eu precisaria de um comentário para explicá-lo, então acho que ajustarei minha tentativa original para '\ x00NEVERMATCHES ^'. Eu recebo a garantia inigualável desta resposta, com minha auto-documentação original. Obrigado a todos por respostas!
6269 Peter Hansen
3
Isso realmente funciona? Em caso afirmativo, quem decidiu romper com o Unix? Nas regexps do Unix, ^é especial apenas como o primeiro caractere e da mesma forma com $. Com qualquer ferramenta Unix, esse regexp corresponde a qualquer coisa que contenha a string literal a^.
JaakkoK
Heh, isso é um bom ataque. Eu nunca testei contra essa string literal.
Adam Nelson
Ah, se isso quebrar os regexps do Unix, você vai adorar >^.
CubicleSoft
4

O Python não aceita, mas o Perl:

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

Essa regex deve (teoricamente) tentar corresponder a um número infinito (par) de ws, porque o primeiro grupo ( ()s) se repete em si mesmo. O Perl parece não emitir nenhum aviso, mesmo use strict; use warnings;assim, portanto, suponho que seja pelo menos válido, e meu (mínimo) teste não corresponde a nada, então o envio para sua crítica.

Chris Lutz
fonte
1
A teoria é sempre boa, mas na prática acho que ficaria preocupado com expressões regulares cujas descrições incluíam a palavra "infinito"!
5119 Peter Hansen
perl -Mre=debug -e'"www wwww wwwww wwwwww" =~ /(w\1w)/'
precisa saber é o seguinte
@ BradGilbert - Executar isso aqui (5.10, um pouco desatualizado) produz "falha na regex", conforme solicitado pelo OP. Isso corresponde ao seu sistema?
Chris Lutz
4

[^\d\D]ou (?=a)bou a$aoua^a

Bart Kiers
fonte
Obrigado. Observe que (?! X) x foi a primeira resposta dada, listada acima.
31520 Peter Hansen
Sim, parecia que eu examinei os outros atendentes muito rapidamente.
22730 Bart Kiers
4

Isso não funcionará no Python, e em muitos outros idiomas, mas em um regex Javascript, []é uma classe de caractere válida que não pode ser correspondida. Portanto, o seguinte deve falhar imediatamente, independentemente da entrada:

var noMatch = /^[]/;

Gosto mais do que /$a/porque, para mim, comunica claramente sua intenção. E quanto a quando você precisaria, eu precisava disso porque precisava de um fallback para um padrão compilado dinamicamente com base na entrada do usuário. Quando o padrão é inválido, preciso substituí-lo por um padrão que não corresponda a nada. Simplificado, fica assim:

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

Todos os exemplos que envolvem um correspondente de limites seguem a mesma receita. Receita:

  1. Escolha qualquer um dos correspondentes de limite: ^, $, \ b, \ A, \ Z, \ z

  2. Faça o oposto do que eles significam

Exemplos:

^ e \ A são destinados ao início, portanto, não os use no início

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

\ b corresponde a um limite de palavras, portanto, use-o entre

\b --> .\b.

$, \ Z e \ z são destinados ao fim, portanto, não os use no final

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

Outros envolvem o uso de lookahead e lookbehind, que também funcionam com a mesma analogia: se você der lookahead positivo ou negativo seguido de algo oposto

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

Se você der uma olhada positiva ou negativa atrás de algo oposto

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

O seu poderia ser mais esse padrão e mais analogias.

Arun
fonte
3

Tantas boas respostas!

Semelhante à resposta do @ nivk, eu gostaria de compartilhar a comparação de desempenho do Perl para diferentes variantes do regex que nunca combina.

  1. Entrada: seqüências pseudo-aleatórias ascii (25.000 linhas diferentes, comprimento 8-16):

Velocidade Regex:

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. Entrada: / usr / share / dict / words (100.000 palavras em inglês).

Velocidade Regex:

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 no Intel i5-3320M, kernel do Linux 4.13, Perl 5.26)

filiprem
fonte
Aqui está uma comparação JavaScript de alguns métodos abordados aqui: jsperf.com/regex-that-never-matches
thdoan
2

eu acredito

\Z RE FAILS! \A

abrange até os casos em que a expressão regular inclui sinalizadores como MULTILINE, DOTALL etc.

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

Acredito (mas ainda não a comparei) que, independentemente do comprimento (> 0) da cadeia entre \Ze \A, o tempo até a falha deve ser constante.

tzot
fonte
2
(*FAIL)

ou

(*F)

Com PCRE e PERL, você pode usar esse verbo de controle de retorno que força o padrão a falhar imediatamente.

Casimir et Hippolyte
fonte
2

Depois de ver algumas dessas ótimas respostas, o comentário de @ arantius (sobre timing $xvs x^vs(?!x)x ) sobre a resposta atualmente aceita me fez querer cronometrar algumas das soluções fornecidas até agora.

Usando o padrão de linha de 275k do @ arantius, executei os seguintes testes no Python (v3.5.2, IPython 6.2.1).

TL; DR: 'x^'e 'x\by'são os mais rápidos por um fator de pelo menos ~ 16, e ao contrário da descoberta de @ arantius, (?!x)xestava entre os mais lentos (~ 37 vezes mais lento). Portanto, a questão da velocidade certamente depende da implementação. Teste você mesmo no sistema pretendido antes de confirmar se a velocidade é importante para você.

ATUALIZAÇÃO: Aparentemente, há uma grande discrepância entre tempo 'x^'e tempo 'a^'. Consulte esta pergunta para obter mais informações e a edição anterior para tempos mais lentos com em avez de 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)

A primeira vez que executei isso, esqueci de rexibir as três últimas expressões, então '\b'fui interpretada como '\x08'o caractere de backspace. No entanto, para minha surpresa, 'a\x08c'foi mais rápido que o resultado mais rápido anterior! Para ser justo, ele ainda corresponderá a esse texto, mas achei que ainda valia a pena notar, porque não sei por que é mais rápido.

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

Meu arquivo de teste foi criado usando uma fórmula para "... Conteúdo legível e sem linhas duplicadas" (no 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
nivk
fonte
\B\bé terrivelmente falho em termos de desempenho (como todo padrão que não está ancorado em uma posição, mas esse padrão é particularmente ruim). Tente comparações ^\B\b.
phils
2

Regex vazio

A melhor regex para nunca corresponder a nada é uma regex vazia. Mas não tenho certeza de que todos os mecanismos de regex aceitem isso.

Regex impossível

A outra solução é criar uma regex impossível. Descobri que são $-^necessárias apenas duas etapas para calcular, independentemente do tamanho do seu texto ( https://regex101.com/r/yjcs1Z/1 ).

Para referência:

  • $^e $.execute 36 etapas para calcular -> O (1)
  • \b\B toma 1507 etapas na minha amostra e aumenta com o número de caracteres na sua string -> O (n)

Tópico mais popular sobre esta questão:

aeon
fonte
1

Talvez isto?

/$.+^/
Dan Breen
fonte
No Python, essa abordagem funciona apenas se você controlar os sinalizadores : re.compile('$.+^', re.MULTILINE|re.DOTALL).search('a\nb\nc\n')retorna um objeto de correspondência correspondente aos bec (e todas as novas linhas adjacentes e intermediárias). A abordagem negativa, que recomendo, funciona (ou seja, falha em corresponder a qualquer coisa) para qualquer combinação de sinalizadores com as quais possa ser compilada.
Alex Martelli
Meu mal - misturou o $e ^.
5309 Chris Lutz
1
Isso pode ser uma tentativa de procurar o final de uma sequência antes do início, mas descobri que $ não significa 'final de sequência', a menos que seja o último caractere da expressão regular e espero que se aplique um comportamento semelhante a ^, então isso pode corresponder a um substring começando com um $ literal, e terminando com uma literal ^
pavium
@pavium, certamente não se comporta dessa maneira em Python ou Javascript. A menos que você os escape com \ ou inclua-os em um conjunto de caracteres com [], caracteres especiais como $ e ^ não devem ser tratados como literais. Em que idioma você observou isso?
5119 Peter Hansen
Em Perl, pelo menos, isso deve ser escrito /\z.+\A/(veja perldoc perlre ). Isso impede que o modo de linha múltipla e linha única ( use re '/ms') o afete.
perfil completo de Brad Gilbert
0
'[^0-9a-zA-Z...]*'

e substitua ... por todos os símbolos imprimíveis;). Isso é para um arquivo de texto.

Drakosha
fonte
Eu acho que tem que haver uma maneira mais curta para isso, mas esse foi o meu primeiro pensamento também ^^
FP
4
Isso corresponderá à string vazia. Para capturar todos os caracteres possíveis, use [^\x00-\xFF]+(para implementações baseadas em bytes).
28830 Ferdinand Beyer
6
Uma expressão melhor seria [^\s\S]. Mas, como Ferdinand Beyer já disse, corresponderia a uma string vazia.
Gumbo #
3
A regex de Drakosha pode corresponder a uma cadeia vazia por causa do *; deixe isso de lado ou substitua-o por +, e ele deve corresponder a pelo menos um caractere. Se a classe excluir todos os caracteres possíveis, não poderá corresponder a nada.
1213 Alan Moore Alan
0

E em vez de regex, basta usar uma declaração if sempre falsa? Em javascript:

var willAlwaysFalse=false;
if(willAlwaysFalse)
{
}
else
{
}
Graviton
fonte
Adicionei um comentário em resposta à pergunta de Charlie, explicando por que esse tipo de abordagem não é desejável. Em resumo, preciso de um grupo dentro de uma regex que sempre será usada, mas em alguns casos o grupo deve ser criado para garantir que nunca possa corresponder.
31512 Peter Hansen
-2

Uma solução portátil que não dependerá da implementação do regexp é usar apenas uma cadeia constante que você tem certeza de que nunca aparecerá nas mensagens de log. Por exemplo, faça uma string com base no seguinte:

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

Claro, isso não é um desafio intelectual, mas mais como a programação de fita adesiva .

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

Cria um padrão que contém apenas alfanuméricos e ' -' (nenhum dos quais são caracteres especiais de expressão regular), mas é estatisticamente impossível que a mesma sequência tenha aparecido em qualquer lugar antes (porque esse é o objetivo de um GUID).

finnw
fonte
2
"Estatisticamente impossível"? Hã? Dependendo de como o GUID é calculado, é possível e geralmente bastante simples prever os próximos GUIDs (pois eles dependem da máquina que os computa e do tempo). Você quer dizer "improvável", "com uma probabilidade muito pequena", mas não pode dizer "impossível", mesmo para seqüências perfeitamente aleatórias. Seu Regex corresponderá a um número infinito de strings - esta questão está procurando por um que não corresponda a nada. Sempre.
Ferdinand Beyer