Passamos o desafio de Callum Macrae 100%

Sugiro tentar resolver 10 testes regex de Callum Macrae. Ao contrário da minha análise anterior do desafio , não há tarefas francamente simples e até médias. Como se costuma dizer - apenas regex, apenas hardcore.


Como o desafio é bastante complicado, não é necessário seguir todas as regras como eu, qualquer aprovação no teste é 100% - significa que você é um super profissional. Bem vindo!


Sim, eu sei, esse desafio já foi publicado uma vez. Mas o autor do post não apresentou soluções de trabalho e, nos comentários, as pessoas não conseguiam resolver mais quatro problemas e, na maioria das vezes, nem entendiam o significado da tarefa e o que queriam deles.


Portanto, eu o publico novamente, com uma tradução detalhada, explicação e todos os pães confiantes.


Tarefa 1 - destacar palavras duplicadas


http://callumacrae.imtqy.com/regex-tuesday/challenge1.html


Há um conjunto de frases; nessa frase, pode haver palavras duplicadas. É necessário destacar palavras repetidas.


Um exemplo:


This is is a test 

Nesse caso, a palavra "é" é repetida duas vezes, destacada em negrito:


 This is <strong>is</strong> a test 

Sugestão

É necessário encontrar repetições de palavras, e as palavras são separadas por um espaço; portanto, é necessário um caractere de espaço em branco. Em expressões regulares, é tecnicamente possível encontrar repetições apenas através do link de retorno.


Solução

Expressão:


 /\b([\w']+)\s(\1)\b/gi 

Substituição:


 $1 <strong>$2</strong> 

Solução de análise
  • "\ b" - deve começar a partir do limite da palavra
  • "([\ w '] +)" - qualquer número de letras, números e apóstrofo (você também pode resolvê-lo com outro espaço que não seja um espaço ) e certifique-se de capturá-lo em um grupo, porque Em seguida, você precisa encontrar repetições deste grupo.
  • "\ s (\ 1)" - porque sabemos que a repetição ocorre depois do espaço, colocamos um espaço "\ s" e depois escrevemos que depois disso deve seguir a repetição do primeiro grupo "(\ 1)" anteriormente capturado.
  • "\ b" - a repetição deve terminar com o limite da palavra, caso contrário corremos o risco de capturar apenas parte da palavra.

Tarefa 2 - Escala de cinza


http://callumacrae.imtqy.com/regex-tuesday/challenge2.html


Existem códigos de cores em diferentes formatos, a tarefa é encontrar todos os tons de cinza.


Exemplos de códigos válidos:


 #eEe #6F6F6F rgb(2.5, 2.5,2.5) hsl(0, 10%, 100%) 

Exemplos de códigos inválidos:


 #eEf #11111e rgb(1.5%, 1.5%, 1.6%) hsl(20, 20%, 20%) 

Explicações de código

A questão mais importante nesta tarefa é o que é considerado cinza.


Segundo a Wikipedia, o cinza é:


Muitas das cores obtidas pela combinação das três cores primárias do modelo de cores RGB - vermelho, verde e azul em concentrações iguais .

Os códigos que começam com # são do formato hexadecimal, vêm em duas formas. Abreviado, três caracteres (#rgb) e completo, seis caracteres $ rrggbb. Onde r, g, b são as três cores primárias.
Os códigos rgb (r, g, b) são exatamente os mesmos, eles são escritos apenas em números de 0 a 255.
O formato hsl é um pouco mais complicado, os números aqui significam tom, saturação e luminosidade. Para entender em que condições três cores primárias são obtidas em proporções iguais, por exemplo, você pode brincar com este editor visual.


Sugestão

Para o hexadecimal abreviado, a ocorrência correta será a repetição dos três caracteres, por exemplo #aaa. Para hexadecimal completo, repita dois caracteres, por exemplo #efefef. Para rgb digital, repita os dígitos, por exemplo rgb (2, 2, 2). Compreender o formato hsl é um pouco mais complicado, mas ainda sabendo o que foi dito acima, você pode entender que aqui a cor cinza é a cor na qual o tom é 0 ou a saturação é 0 ou 100.


Assim, como na tarefa anterior, você precisa usar o link de volta. A expressão regular resultante será grande (isso é normal), pois é necessário levar em consideração muitas opções diferentes, incluindo as escritas incorretamente.


Solução
 /^(?:#(\w)\1\1|#(\w{2})\2\2|rgb\(((?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])%?(?:\.\d+)?),[ ]?[0]*\3,[ ]?[0]*\3\)|rgba\(([\d.]+%?),[0 ]*\4,[0 ]*\4,[^)]+\)|hsla?\([\d.]+,[ ]*(0%[^)]+|[\d.]+%,[ ]*(0|100)%[^\)]*)\))$/i 

Solução de análise

Um rugular separado é escrito para cada cor; nós os analisaremos separadamente:


 #(\w)\1\1 

  • "(\ w)" recebe um único caractere no grupo.
  • "\ 1 \ 1" - e indique que deve ser repetido 2 vezes.

Para dois caracteres a mesma coisa - não vou repetir.


 rgb\(((?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])%?(?:\.\d+)?),[ ]?[0]*\3,[ ]?[0]*\3\) 

Gostaria de escrever "rgba?", Mas um caso é possível quando o quarto parâmetro é especificado em rgb (), portanto, rgb e rgba precisam ser descritos separadamente:


  • "\ d {1,2} | 1 \ d {2} | 2 [0-4] \ d | 25 [0-5]" - o intervalo é de 0 a 255. Não vou analisá-lo em detalhes, você pode ver a tarefa 5 aqui .
  • "(?: \. \ d +)?" - um grupo opcional cujo número não está atribuído. Um ponto e um número após um ponto são possíveis (isto é para números não inteiros).
  • ", []? [0] * \ 3" - uma vírgula obrigatória, seguida por 0 ou 1 espaço, 0 ou muitos zeros, após o qual o valor do grupo capturado anteriormente deve ser repetido.

Em rgba () - a mesma coisa, mas são necessários 4 parâmetros.


 hsla?\([\d.]+,[ ]*(0%[^)]+|[\d.]+%,[ ]*(0|100)%[^\)]*)\) 

Aqui, de uma maneira boa, você também precisa separar hsl e hsla, mas não existe esse caso nos casos de teste, portanto, escrevendo um pouco de "hsla?"


  • "[\ d.] +, [] *" - primeiro vem o número necessário "[\ d.] +" (incluindo um número não inteiro) com uma vírgula obrigatória e um espaço opcional "[] *".
  • "(0% [^)] + | [\ d.] +%, [] * (0 | 100)% [^)] *" - e, em seguida, duas opções são possíveis: 1) onde 0% vem primeiro e depois qualquer caractere que não seja o caractere de fechamento do colchete [^)] +; 2) existe qualquer número com um sinal de porcentagem obrigatório e uma vírgula "[\ d.] +%", E então 0% ou 100% "(0 | 100)%".

Tarefa 3 - encontrar datas


http://callumacrae.imtqy.com/regex-tuesday/challenge3.html


Há uma lista de datas, a partir dessas datas, encontre as datas de 1000 a 2012, escritas inclusive no formato AAAA / MM / DD HH: MM (: SS). Onde cada letra é um número necessário e entre parênteses não é um pré-requisito.


Exemplo


 2001/09/30 23:59:11 

Sugestão

"[0-9]" não é um intervalo de números, é uma expressão que significa que um único caractere de 0-9 é válido. Nas expressões regulares, não há intervalo para números grandes, mas, a partir de pequenos pedaços, é possível criar uma expressão regular que cubra o intervalo desejado. Exemplo: "1 [0-9]" - um intervalo de 10 a 19.


Solução
 /^(1[\d]{3}|200\d|201[0-2])\/(0[1-9]|1[0-2])\/(0[1-9]|1[0-9]|2[0-9]|3[0-2])\s(0[0-9]|1[0-9]|2[0-3]):([0-5][\d])(:([0-5][\d]))?$/ 

Solução de análise
  • O ano válido é "(1 [\ d] {3} | 200 \ d | 201 [0-2])", em que de 1000 a 1999, de 2000 a 2009, de 2010 a 2012.
  • Mês "(0 [1-9] | 1 [0-2])". De 01 a 09 e de 10 a 12.
  • Dia "(0 [1-9] | 1 [0-9] | 2 [0-9] | 3 [0-2])". De 01 a 09 e de 10 a 19, de 20 a 29 e de 30 a 32.
  • Hora "(0 [0-9] | 1 [0-9] | 2 [0-3])". De 00 a 09 e de 10 a 19, de 20 a 23.
  • Minuto "([0-5] [\ d])". 00 a 59
  • (: ([0-5] [\ d]))? - segundos opcionais, de 00 a 59.

Tarefa 4 - itálico


http://callumacrae.imtqy.com/regex-tuesday/challenge4.html


Há um texto com marcação MarkDown (assim como no Habré). Você deve escrever uma expressão regular que substitua as palavras entre os asteriscos pela tag <em>.


Exemplo


 *This text is italic.* -> <em>This text is italic.</em> 

Sugestão

Você precisa encontrar um asterisco antes e depois do qual não há outro asterisco. Está olhando apenas para a frente e olhando para frente e para trás (o mais simples, mas não entre navegadores).


Solução

Expressão:


 /(^|[^*])\*([^*].*?[^*]|[^*])\*((?!\*)|$)/g 

Substituição:


 $1<em>$2</em> 

Solução de análise
  • "(^ | [^ *])" - iniciaremos do início da linha ou de qualquer caractere, exceto um asterisco. O grupo precisa capturar esse símbolo e colocá-lo antes da tag <em>.
  • ((?! *) | $) - terminaremos com o final da linha ou com qualquer caractere, exceto um asterisco, já que aqui está espiando - o espaço não é capturado.
  • "([^ *]. *? [^ *] | [^ *])" - no meio temos "[^ *]. *? [^ *]" Qualquer texto que não deva começar e terminar com um asterisco e expressão ou "| [^ *]" apenas para levar em conta um único caractere dentro da tag (não é necessário passar no teste).

Tarefa 5 - Formato numérico


http://callumacrae.imtqy.com/regex-tuesday/challenge5.html


Na lista de números, selecione apenas números com o formato correto. É geralmente aceito escrever números da direita para a esquerda, divididos em grupos de três dígitos em cada um.


Exemplos de números gravados corretamente:


 1,024 8,205,500.4672 10.444444444444 30 000,7302 

Sugestão

É importante considerar que os números são escritos exatamente da direita para a esquerda, e não vice-versa. Isso significa que um número pode começar com 1-3 dígitos e, em seguida, só pode haver três dígitos em um grupo. Na parte não inteira, pode haver quantos números você quiser (ou nem um pouco). Leve em consideração que o separador de grupos pode ser uma vírgula ou um espaço e o separador de uma parte inteira e não inteira pode ser uma vírgula ou um ponto.


Solução

Expressão:


 /^\d{1,3}([ ,]\d{3})*([.,]\d+)?$/ 

Solução de análise
  • "^ \ d {1,3}" - no início de 1 a 3 dígitos.
  • "([,] \ d {3}) *" - além de um separador e um grupo de 3 números, um asterisco indica que nosso formato pode ocorrer 0 ou várias vezes.
  • "([.,] \ d +)? $" - no final é um grupo com um separador e um número, o ponto de interrogação é um quantificador que diz que a presença da parte não inteira não é um pré-requisito.

Tarefa 6 - endereços IP


http://callumacrae.imtqy.com/regex-tuesday/challenge6.html


Na lista de endereços IP em vários formatos, encontre endereços IP válidos. Talvez a tarefa mais triste de todas. Não é muito super complicado, é muito triste.


Exemplos de entradas de endereço IP válidas e explicação:


  • 192.0.2.235 - decimal com pontos.
  • 0300.0000.0002.0353 - octal com pontos.
  • 0xC0.0x00.0x02.0xEB - hexadecimal com pontos.
  • 0xC00002EC - hexadecimal.
  • 287454020 - decimal.
  • 030000001353 - octal.

Misturar formatos diferentes é ruim. Especialmente os números. A situação é ainda mais complicada pelo fato de que os formatos de endereços IP com pontos podem ser misturados, por exemplo - 0xFF.255.0377.0x12. Pessoalmente, minha opinião é que essa é uma prática ruim, mas, de acordo com o teste, essas opções são possíveis e, portanto, isso deve ser levado em consideração.


Sugestão
  • 192.0.2.235 - decimal com pontos. Uma notação comum pode ser expressa de 1 a 3 dígitos entre os pontos (valores de 0 a 255).
  • 0300.0000.0002.0353 - octal com pontos. 4 dígitos entre pontos com valores de 0 a 7.
  • 0xC0.0x00.0x02.0xEB - hexadecimal com pontos. Quatro caracteres entre pontos. À esquerda "0x", dois caracteres (por dígitos ou de "a" a "f").
  • 0xC00002EC - hexadecimal. À esquerda "0x" e 8 caracteres (valores de dígitos ou de "a" a "f").
  • 287454020 - decimal. Quaisquer números no intervalo de 0 a 4294967295.
  • 030000001353 - octal. À esquerda 0. Os números são de 0 a 7. O intervalo é de 0 a 0777777777777777.

A expressão regular será ótima.


Solução
 /^((((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])|(0x[\da-f]{2})|([0-7]{4}))\.){3}(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])|(0x[\da-f]{2})|([0-7]{4})))|(0x[\da-f]{8})|(0([0-7]{1,11}))|(2874540[2-8][0-9]|28745409[0-9]|287454[1-9][0-9]{2}|28745[5-9][0-9]{3}|2874[6-9][0-9]{4}|287[5-9][0-9]{5}|28[89][0-9]{6}|29[0-9]{7}|[3-9][0-9]{8}|[1-3][0-9]{9}|4[01][0-9]{8}|42[0-8][0-9]{7}|429[0-3][0-9]{6}|4294[0-8][0-9]{5}|42949[0-5][0-9]{4}|429496[0-6][0-9]{3}|4294967[01][0-9]{2}|42949672[0-8][0-9]|429496729[0-5]))$/i 

Solução de análise

Para endereços IP com pontos, a mistura é possível, por isso escrevemos opções através de "|" por esse padrão: ((decimal | hexadecimal | octal).) {3} (decimal | hexadecimal | octal).


  • "(\ d | [1-9] \ d | 1 \ d \ d | 2 [0-4] \ d | 25 [0-5])" - para decimal com ponto de registro.
  • "(0x [\ da-f] {2})" - para hexadecimal com um ponto de registro.
  • "([0-7] {4})" - para octal com um ponto de registro.

E outros formatos de gravação:


  • "(0x [\ da-f] {8})" - para notação hexadecimal.
  • "(2874540 [2-8] [0-9] | 28745409 [0-9] | 287454 [1-9] [0-9] {2} | 28745 [5-9] [0-9] {3} | 2874 [6-9] [0-9] {4} | 287 [5-9] [0-9] {5} | 28 [89] [0-9] {6} | 29 [0-9] {7} | [3-9] [0-9] {8} | [1-3] [0-9] {9} | 4 [01] [0-9] {8} | 42 [0-8 ] [0-9] {7} | 429 [0-3] [0-9] {6} | 4294 [0-8] [0-9] {5} | 42949 [0-5] [0-9 ] {4} | 429496 [0-6] [0-9] {3} | 4294967 [01] [0-9] {2} | 42949672 [0-8] [0-9] | 429496729 [0-5 ]) "- para notação decimal. E aqui, devo admitir, para uma expressão mais curta, trapacei incluindo apenas endereços IP decimais no intervalo de teste. Para o bem, aqui você precisa considerar qualquer número de 0 a 4294967295. Escrever isso manualmente não é uma tarefa agradável, por isso usamos .
  • (0 ([0-7] {1,11})) - para notação octal.

Tarefa 7 - URLs


http://callumacrae.imtqy.com/regex-tuesday/challenge7.html


Na lista de URLs, encontre válido.


Exemplos de endereços válidos:


 http://ab https://example.com/ http://test.this-test.com/ http://1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa 

Sugestão

O endereço deve necessariamente começar em http: // ou https: // e terminar com uma barra, uma letra (se um domínio) ou um número se um endereço IP. Cada domínio pode ter um subdomínio. De acordo com o padrão, o comprimento de cada domínio não pode exceder 63 caracteres com um comprimento total de 255 caracteres . Um domínio aninhado em um subdomínio limitado a 127 domínios . Infelizmente, o mecanismo JavaScript Regex não ativará totalmente essas restrições, mas você pode escrever uma expressão que atenda às regras e passe no teste. Riscar o que pode ser contornado ajustando outros parâmetros.


Solução
 /^https?:\/\/(((\b[az\d-]{1,63}\b)\.){1,40}(\b[az\d-]{1,63}\b))\/?$/i 

Solução de análise
  • "^ https ?: \ / \ /" - http: // ou https: //

Vamos analisá-lo separadamente ((\ b [az \ d -] {1,63} \ b).) {1,40}


  • "\ b" no final e no início do domínio para garantir que o domínio não seja iniciado e não termine com nada inválido.
  • "[az \ d -] {1,63}" - dentro do nome do domínio letras, números e hífens são permitidos dentro
  • "{1,63}" - tudo isso não passa de 63 caracteres.
  • "((nome do domínio).) {1,40}" - gostaria de colocar 127 aqui, mas em expressões regulares o quantificador {,} significa o intervalo de repetição. No caso de usar [] {} - este é o número de caracteres, mas no caso sem [] - esse é exatamente o número de repetições do modelo (nome do domínio).). Portanto, limitamos a repetição a 40 para não exceder o limite geral de comprimento, que também não podemos definir estritamente por esse motivo.

Tarefa 8 - Repetição de elementos


http://callumacrae.imtqy.com/regex-tuesday/challenge8.html


A tarefa é muito semelhante à tarefa 1 de várias maneiras, mas aqui você precisa encontrar e destacar os elementos repetidos da lista MarkDown com duas estrelas.


Essa lista:


 * Repeated list item * Repeated list item 

Deve ser convertido para isso:


 * Repeated list item * **Repeated list item** 

Sugestão

Utilizamos um link de retorno, um caractere de avanço de linha, chaves globais, multilinhas e sem sensibilidade.


Solução

Expressão:


 /^(\*\s+([^\n]+)\n\*\s+)(\2)$/gmi 

Substituição:


 $1**$3** 

Tarefa 9 - Links de MarkDown


http://callumacrae.imtqy.com/regex-tuesday/challenge9.html


Substitua links válidos do MarkDown por links html.


Exemplo de conversão:


 [Another](http://example.com/) -> <a href="http://example.com/">Another</a> 

Sugestão

Isso pode ser feito sem espiar, ou apenas olhando para o futuro. Em vez de olhar para trás, é um substituto.


Solução

Expressão:


 /(^|\s+)\[([^\]\[]+)\]\s*\((https?:\/\/\b[az\d-]+\b(\.[az-]+)*\.\w+\/*)\)(?=$|\s+)/i 

Substituição:


 $1<a href="$3">$2</a> 

Solução de análise
  • "(^ | \ s +)" - antes do link MarkDown, o início de uma linha ou de um espaço é permitido. Levamos isso ao grupo para substituir o espaço capturado na substituição de $ 1.
  • "[([^] [] +)] \ s *" - são permitidos caracteres diferentes de aspas no cabeçalho.
  • "(https ?: \ / \ / \ b [az \ d -] + \ b (. [az -] +) . \ w + \ / )") - verificamos se o endereço da URL é válido.
  • "(? = $ | \ s +)" - no final de um espaço ou no final de uma linha.

Tarefa 10 - Palavras-chave


http://callumacrae.imtqy.com/regex-tuesday/challenge10.html


O desafio mais grave de todos. Usando expressões regulares com substituições, transforme o texto existente em palavras-chave separadas por vírgulas.


Regras:


  • Aspas são uma palavra-chave.
  • Nomes hifenizados são uma palavra-chave.
  • A palavra pode conter um apóstrofo.
  • Os símbolos (; - '") devem ser removidos.

Um exemplo é este:


não diga a Suzie Smith-Hopper que eu quebrei o cavalo de brinquedo de Daniel


Deve ser convertido para isso:


não diga, Suzie, Smith-Hopper, que eu quebrei o brinquedo de Daniel, cavalo


Não parece complicado à primeira vista, mas não parece. O fato é que esse problema não é resolvido e não é trazido para a forma final com apenas uma expressão regular com uma substituição. Mas os casos de teste são projetados de tal maneira que todos tornariam possível a solução para o problema.


Sugestão

É necessário decidir onde colocar uma vírgula, o que substituir ao lado dessa vírgula e de que lado. Há uma suposição no problema - a primeira palavra em cada caso de teste não requer nenhuma alteração. Isso significa que você precisa colocar uma vírgula à esquerda da palavra substituída, exceto a primeira palavra.


Solução

Expressão:


 /\s(['"])([^'"]+)\1|(;? |['"]? | ['"]|-{2,})(\w+)/g 

Substituição:


 ,$2$4 

Solução de análise

Como já decidimos o local onde colocar a vírgula, decidiremos com o que substituiremos essa vírgula e o que excluir.


  • "\ s (['"]) ([^' "] +)" - substitua o modelo {espaço "da palavra por um espaço entre aspas"} por {, palavras com um espaço} . "\ s" aqui não é exatamente assim, mas para excluir ocorrências falsas com aspas inseridas incorretamente.
  • "(;? | ['"] | | [' "] | - {2,}) (\ w +)" - existem palavras únicas precedidas por caracteres que precisam ser excluídos e uma vírgula antes dessas palavras.

Source: https://habr.com/ru/post/pt474184/


All Articles