Testando com “A Força”

Markdown foi um dos linguagens de marcação humana que avaliamos e adotamos para o Stack Overflow. No geral, estou muito satisfeito com ela. Tanto que quis implementar um subconjunto pequeno e leve do Markdown também para os comentários.

Optei por estes três elementos comumente usados:

*italic* or _italic_
**bold** or __bold__
`code`

I me ama algumas expressões regulares e é exatamente para isso que o regex nasceu! Ele não veja muito resistente. Então, tirei a poeira do minha cópia do RegexBuddy e comecei.

Digitei alguns dados de teste na janela de teste e criei um pequeno regex em pouco tempo. Essa não é minha primeira vez na discoteca.

regexbuddy-naive-regex.png

Bam! Sim! Feito e Feito! Por chiclete, Eu devo ser um programador genial!

Apesar da minha óbvia genialidade, comecei a ter algumas pequenas dúvidas incômodas. A frase do teste é…

I would like this to be *italic* please.

realmente testes suficientes?

Com certeza é! Posso sentir em meus ossos que essa coisa funciona! É quase como se eu estivesse sendo puxado para enviar esse código por alguma força inexorável, sombria e testadora… É tão sedutoramente fácil!

come-to-the-dark-side-vader.jpg

Mas espere. Eu tenho todo esse banco de dados de comentários do mundo real que as pessoas inseriram no Stack Overflow. Será que eu não deveria experimentar minha incrível expressão regular nesse corpus de dados para ver o que acontece? Ah, tudo bem. Se for preciso. Só para fazer humor com o senhor, sua dúvida persistente. Vamos executar uma consulta e ver.

select Text from PostComments
where dbo.RegexIsMatch(Text, '*(.*?)*') = 1

que produziu esta lista de correspondências, entre outras:

Fato interessante sobre matemática: x * 7 == x + (x * 2) + (x * 4), ou x + x >> 1 + x >> 2. A adição de números inteiros geralmente é bem barata.

Obrigado. O que eu precisava era ativar o modo Singleline também e usar o .*? em vez de .*.

Sim, veja minha edição – alterar seleção * para selecionar RESULT.* uma linha – o senhor tem certeza de que tem mais de um item de linha com o mesmo InstanceGUID?

Não é o seu problema principal, mas o senhor está misturando e combinando wchar_t e TCHAR. mbstowcs() converte de char * para wchar_t *.

aawwwwwww…. Cérebro**k não é válido. :/

Graças a Deus, dei ouvidos aos meus midichlorians e deixei o o lado leve da força de teste prevaleça aqui!

come-to-the-light-side-skywalker.jpg

Então, como corrigimos essa regex? Usamos o lado leve da força: força bruta, ou seja, contra uma tonelada de casos de teste! Meu trabalho aqui é relativamente fácil porque tenho mais de 20.000 casos de teste em um banco de dados. Talvez o senhor não tenha esse luxo. Talvez o senhor precise sair e encontrar um monte de dados de teste em algum lugar na Internet. Ou escrever uma função que gere strings aleatórias para alimentar a rotina, também conhecida como teste de fuzz.

Eu queria deixar o restante dessa expressão regular como um exercício para o leitor, pois sou um cara doente que acha esse tipo de coisa divertida. Se o senhor não achar – bem, que diabos há de errado com o o senhor, senhor? Mas estou divagando. Já fui criticado por não fornecer, o senhor sabe, “a resposta” em minhas publicações no blog. Vamos examinar algumas melhorias em nosso padrão regex itálico.

Primeiro, vamos nos certificar de que temos pelo menos um caractere que não seja espaço em branco dentro dos asteriscos. E mais de um caractere no total para que não coincidamos com o caso **. Usaremos lookahead e lookbehind positivos para fazer isso.

*(?=S)(.+?)(?<=S)*

Isso ajuda muito, mas podemos fazer testes com nossos dados para descobrir outros problemas. Temos problemas quando há caracteres inesperados na frente ou atrás dos asteriscos, como, por exemplo, p*q*r. Portanto, vamos especificar que queremos apenas determinados caracteres fora dos asteriscos.

(?<=[s^,(])*(?=S)(.+?)(?<=S)*(?=[s$,.?!])

Execute essa terceira versão em relação ao corpus de dados e, uau, isso está começando a parecer muito bom! Sem dúvida, há algumas condições de borda, principalmente porque temos o azar de falar sobre código em muitos de nossos comentários, que usam asteriscos de forma estranha.

Esse regex não precisa ser (e provavelmente não pode ser, dado o enorme número possível de entradas humanas) perfeito, mas executá-lo em relação a um grande conjunto de dados de teste de entrada me dá uma confiança razoável de que não estou estragando tudo.

Portanto, o senhor pode testar seu código com a força – força bruta! É uma coisa boa! Apenas cuidado para não se descuidar e deixar o lado negro da força de teste prevalecer. Se o senhor acha que um ou dois casos de teste simples dão conta do recado, está optando pela saída mais fácil (e, provavelmente, com bugs e incorreta).