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çãoExpressã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ódigoA 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ãoPara 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áliseUm 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ãoVocê 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çãoExpressã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).
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çãoExpressã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álisePara 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ãoO 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ãoUtilizamos um link de retorno, um caractere de avanço de linha, chaves globais, multilinhas e sem sensibilidade.
SoluçãoExpressã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ãoIsso pode ser feito sem espiar, ou apenas olhando para o futuro. Em vez de olhar para trás, é um substituto.
SoluçãoExpressã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çãoExpressão:
/\s(['"])([^'"]+)\1|(;? |['"]? | ['"]|-{2,})(\w+)/g
Substituição:
,$2$4
Solução de análiseComo 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.