Sugiero tratar de resolver 10 pruebas de expresiones regulares de Callum Macrae. A diferencia de mi análisis anterior del desafío , no hay tareas francamente simples e incluso promedio. Como dicen, solo expresiones regulares, solo hardcore.
Dado que el desafío es bastante complicado, no es necesario seguir todas las reglas como yo, pasar cualquier examen es 100%, lo que significa que eres un súper profesional. Bienvenido!
Sí, lo sé, este desafío ya se ha publicado una vez. Pero el autor de la publicación no presentó soluciones de trabajo, y en los comentarios, las personas no pudieron resolver otros 4 problemas, y con mayor frecuencia ni siquiera entendieron el significado de la tarea y lo que querían de ellos.
Por lo tanto, lo publico nuevamente, con una traducción detallada, una explicación y todos los bollos de confianza.
Tarea 1: resaltar palabras duplicadas
http://callumacrae.imtqy.com/regex-tuesday/challenge1.html
Hay un conjunto de oraciones, en esta oración puede haber palabras duplicadas. Es necesario resaltar las palabras que se repiten.
Un ejemplo:
This is is a test
En este caso, la palabra "es" se repite dos veces, resaltada en negrita:
This is <strong>is</strong> a test
PistaEs necesario encontrar repeticiones de palabras, y las palabras están separadas por un espacio, por lo tanto, se requiere un carácter de espacio en blanco. En expresiones regulares, es técnicamente posible encontrar repeticiones solo a través del enlace de retroceso.
SoluciónExpresión:
/\b([\w']+)\s(\1)\b/gi
Reemplazo:
$1 <strong>$2</strong>
Solución de análisis- "\ b" - debe comenzar desde el límite de la palabra
- "([\ w '] +)": cualquier número de letras, números y apóstrofo (también puede resolverlo con cualquier otro que no sea un espacio ) y asegúrese de capturarlo en un grupo, porque A continuación, debe encontrar repeticiones de este grupo.
- "\ s (\ 1)" - porque sabemos que la repetición viene después del espacio, ponemos un espacio "\ s" y luego escribimos que después de eso debe seguir la repetición del primer grupo capturado previamente "(\ 1)".
- "\ b": la repetición debe terminar con el límite de la palabra; de lo contrario, corremos el riesgo de capturar solo una parte de la palabra.
Tarea 2 - Escala de grises
http://callumacrae.imtqy.com/regex-tuesday/challenge2.html
Hay códigos de colores en diferentes formatos, la tarea es encontrar todos los tonos de gris.
Ejemplos de códigos válidos:
#eEe #6F6F6F rgb(2.5, 2.5,2.5) hsl(0, 10%, 100%)
Ejemplos de códigos inválidos:
#eEf #11111e rgb(1.5%, 1.5%, 1.6%) hsl(20, 20%, 20%)
Explicaciones de códigoLa pregunta más importante en esta tarea es qué se considera gris.
Según Wikipedia, el gris es:
Muchos de los colores obtenidos mediante la combinación de los tres colores primarios del modelo de color RGB: rojo, verde y azul en concentraciones iguales .
Los códigos que comienzan con # son el formato hexadecimal, viene en dos formas. Abreviado, tres caracteres (#rgb) y completo, seis caracteres $ rrggbb. Donde r, g, b son los tres colores primarios.
Los códigos rgb (r, g, b) son exactamente iguales, solo se escriben en números del 0 al 255.
El formato hsl es un poco más complicado, los números aquí significan tono, saturación y ligereza. Para comprender en qué condiciones se obtienen tres colores primarios en proporciones iguales, por ejemplo, puede jugar con este editor visual.
PistaPara el hexágono abreviado, la aparición correcta será la repetición de los tres caracteres, por ejemplo, #aaa. Para hexadecimal completo, repita dos caracteres, por ejemplo #efefef. Para rgb digital, repita los dígitos, por ejemplo rgb (2, 2, 2). Comprender el formato hsl es un poco más complicado, pero aún sabiendo lo anterior, puede comprender que aquí el color gris es el color en el que el tono es 0 o la saturación es 0 o 100.
En consecuencia, como en la tarea anterior, debe usar el vínculo de retroceso. La expresión regular resultante será grande (esto es normal), ya que debe tener en cuenta muchas opciones diferentes, incluidas las escritas incorrectamente.
Solución /^(?:#(\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
Solución de análisisSe escribe un rugular separado para cada color, los analizaremos por separado:
#(\w)\1\1
- "(\ w)" toma un solo carácter en el grupo.
- "\ 1 \ 1" - e indica que debe repetirse 2 veces.
Para dos personajes lo mismo, no repetiré.
rgb\(((?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])%?(?:\.\d+)?),[ ]?[0]*\3,[ ]?[0]*\3\)
Me gustaría escribir "rgba?", Pero es posible un caso cuando el cuarto parámetro se especifica en rgb (), por lo que rgb y rgba deben describirse por separado:
- "\ d {1,2} | 1 \ d {2} | 2 [0-4] \ d | 25 [0-5]" - el rango es de 0 a 255. No lo analizaré en detalle, puede ver la tarea 5 aquí .
- "(?: \. \ d +)?" - un grupo opcional cuyo número no está asignado. Un punto y un número después de un punto son posibles (esto es para números no enteros).
- ", []? [0] * \ 3": una coma obligatoria, seguida de 0 o 1 espacio, 0 o muchos ceros, después de lo cual se debe repetir el valor del grupo capturado previamente.
En rgba (): lo mismo, pero se requieren 4 parámetros.
hsla?\([\d.]+,[ ]*(0%[^)]+|[\d.]+%,[ ]*(0|100)%[^\)]*)\)
Aquí, en el buen sentido, también debe separar hsl y hsla, pero no existe tal caso en los casos de prueba, por lo que escribiremos un pequeño "hsla?".
- "[\ d.] +, [] *" - primero viene el número requerido "[\ d.] +" (incluyendo no un número entero) con una coma obligatoria y un espacio opcional "[] *".
- "(0% [^)] + | [\ d.] +%, [] * (0 | 100)% [^)] *" - y luego son posibles dos opciones: 1) donde el 0% viene primero y luego cualquier carácter distinto del carácter de cierre del corchete [^)] +; 2) hay cualquier número con un signo de porcentaje obligatorio y una coma "[\ d.] +%," Y luego 0% o 100% "(0 | 100)%".
Tarea 3: buscar fechas
http://callumacrae.imtqy.com/regex-tuesday/challenge3.html
Hay una lista de fechas, a partir de estas fechas, encuentre las fechas de 1000 a 2012 inclusive en el formato AAAA / MM / DD HH: MM (: SS). Donde cada letra es un número requerido, y entre paréntesis no es un requisito previo.
Ejemplo
2001/09/30 23:59:11
Pista"[0-9]" no es un rango de números, es una expresión que significa que un solo carácter de 0-9 es válido. En las expresiones regulares no hay rango para números grandes, pero a partir de piezas tan pequeñas puede hacer una expresión regular que cubra el rango deseado. Ejemplo: "1 [0-9]" - un rango de 10 a 19.
Solución /^(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]))?$/
Solución de análisis- El año válido es "(1 [\ d] {3} | 200 \ d | 201 [0-2])", donde en orden de 1000 a 1999, de 2000 a 2009, de 2010 a 2012.
- Mes "(0 [1-9] | 1 [0-2])". Del 01 al 09 y del 10 al 12.
- Día "(0 [1-9] | 1 [0-9] | 2 [0-9] | 3 [0-2])". Del 01 al 09 y del 10 al 19, del 20 al 29 y del 30 al 32.
- Hora "(0 [0-9] | 1 [0-9] | 2 [0-3])". De 00 a 09 y de 10 a 19, de 20 a 23.
- Minuto "([0-5] [\ d])". 00 a 59
- (: ([0-5] [\ d]))? - segundos opcionales, de 00 a 59.
Tarea 4: cursiva
http://callumacrae.imtqy.com/regex-tuesday/challenge4.html
Hay un texto con marcado MarkDown (al igual que en el Habré). Debe escribir una expresión regular que reemplace las palabras entre los asteriscos con la etiqueta <em>.
Ejemplo
*This text is italic.* -> <em>This text is italic.</em>
PistaNecesita encontrar un asterisco antes y después del cual no hay otro asterisco. Solo se mira hacia adelante y hacia adelante y hacia atrás (el más simple, pero no entre navegadores).
SoluciónExpresión:
/(^|[^*])\*([^*].*?[^*]|[^*])\*((?!\*)|$)/g
Reemplazo:
$1<em>$2</em>
Solución de análisis- "(^ | [^ *])": comenzaremos desde el principio de la línea o desde cualquier carácter, excepto un asterisco. El grupo necesita capturar este símbolo y ponerlo antes de la etiqueta <em>.
- (?
- "([^ *]. *? [^ *] | [^ *])" - en el medio tenemos "[^ *]. *? [^ *]" Cualquier texto que no debe comenzar y terminar con un asterisco y una expresión o "| [^ *]" solo para tener en cuenta un solo carácter dentro de la etiqueta (no es necesario pasar la prueba).
http://callumacrae.imtqy.com/regex-tuesday/challenge5.html
De la lista de números, seleccione solo números con el formato correcto. En general, se acepta escribir números de derecha a izquierda, divididos en grupos de tres dígitos en cada uno.
Ejemplos de números registrados correctamente:
1,024 8,205,500.4672 10.444444444444 30 000,7302
PistaEs importante tener en cuenta que los números se escriben exactamente de derecha a izquierda y no al revés. Esto significa que un número puede comenzar con 1-3 dígitos, y luego solo puede haber tres dígitos en un grupo. En la parte no entera puede haber tantos números como desee (o ninguno). Tenga en cuenta que el separador de grupos puede ser una coma o un espacio, y el separador de la parte entera y no entera puede ser una coma o un punto.
SoluciónExpresión:
/^\d{1,3}([ ,]\d{3})*([.,]\d+)?$/
Solución de análisis- "^ \ d {1,3}" - al comienzo de 1 a 3 dígitos.
- "([,] \ d {3}) *" - además de un separador y un grupo de 3 números, un asterisco indica que nuestro formato puede ocurrir 0 o muchas veces.
- "([.,] \ d +)? $": al final hay un grupo con un separador y un número, el signo de interrogación es un cuantificador que dice que la presencia de la parte no entera no es un requisito previo.
Tarea 6 - direcciones ip
http://callumacrae.imtqy.com/regex-tuesday/challenge6.html
De la lista de direcciones IP en una variedad de formatos, encuentre direcciones IP válidas. Quizás la tarea más triste de todas. No tanto súper complicado, cuánto triste.
Ejemplos de entradas válidas de direcciones IP y explicación:
- 192.0.2.235 - decimal con puntos.
- 0300.0000.0002.0353 - octal con puntos.
- 0xC0.0x00.0x02.0xEB - hexadecimal con puntos.
- 0xC00002EC - hexadecimal.
- 287454020 - decimal.
- 030000001353 - octal.
Mezclar diferentes formatos es malo. Especialmente los números. La situación se complica aún más por el hecho de que los formatos de direcciones IP con puntos se pueden mezclar, por ejemplo, 0xFF.255.0377.0x12. Personalmente, mi opinión es que esta es una mala práctica, pero sin embargo, de acuerdo con la prueba, tales opciones son posibles y, por lo tanto, esto debe tenerse en cuenta.
Pista- 192.0.2.235 - decimal con puntos. Una notación común se puede expresar de 1 a 3 dígitos entre puntos (valores de 0 a 255).
- 0300.0000.0002.0353 - octal con puntos. 4 dígitos entre puntos con valores de 0 a 7.
- 0xC0.0x00.0x02.0xEB - hexadecimal con puntos. Cuatro personajes entre puntos. Liderando "0x", luego dos caracteres (por dígitos o de "a" a "f").
- 0xC00002EC - hexadecimal. Liderando "0x", luego 8 caracteres (valores de dígitos o de "a" a "f").
- 287454020 - decimal. Cualquier número en el rango de 0 a 4294967295.
- 030000001353 - octal. Los primeros 0. Los números son de 0 a 7. El rango es de 0 a 07777777777777.
La expresión regular será genial.
Solución /^((((\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
Solución de análisisPara direcciones IP con puntos, la mezcla es posible, por lo que escribimos opciones a través de "|" por dicho patrón: ((decimal | hexadecimal | octal).) {3} (decimal | hexadecimal | octal).
- "(\ d | [1-9] \ d | 1 \ d \ d | 2 [0-4] \ d | 25 [0-5])" - para decimal con punto de registro.
- "(0x [\ da-f] {2})" - para hexadecimal con un punto de registro.
- "([0-7] {4})" - para octal con un punto de registro.
Y otros formatos de grabación:
- "(0x [\ da-f] {8})" - para notación 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 notación decimal. Y aquí, debo admitir, para una expresión más corta, hice trampa al incluir solo direcciones IP decimales en el rango de prueba. Por el bien, aquí debe considerar cualquier número del 0 al 4294967295. Escribir esto manualmente no es una tarea de agradecimiento, por lo que lo usamos .
- (0 ([0-7] {1,11})) - para notación octal.
Tarea 7 - URL
http://callumacrae.imtqy.com/regex-tuesday/challenge7.html
De la lista de URL, encuentra válido.
Ejemplos de direcciones válidas:
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
PistaLa dirección debe comenzar necesariamente en http: // o https: //, y terminar con una barra diagonal, una letra (si es un dominio) o un número si es una dirección IP. Cada dominio puede tener un subdominio. Según el estándar, la longitud de cada dominio no puede exceder los 63 caracteres. con una longitud total de 255 caracteres . Un dominio que anida en un subdominio limitado a 127 dominios . Desafortunadamente, el motor Regex JavaScript no habilitará completamente estas restricciones, pero puede escribir una expresión que cumpla con las reglas y pasar la prueba. Tachado lo que se puede evitar ajustando otros parámetros.
Solución /^https?:\/\/(((\b[az\d-]{1,63}\b)\.){1,40}(\b[az\d-]{1,63}\b))\/?$/i
Solución de análisis- "^ https ?: \ / \ /" - http: // o https: //
Analicemos por separado ((\ b [az \ d -] {1,63} \ b).) {1,40}
- "\ b" al final y al principio del dominio para asegurarse de que el dominio no se inicie y no termine con nada inválido.
- "[az \ d -] {1,63}" - dentro del nombre de dominio se permiten letras, números y guiones
- "{1.63}": todo esto no tiene más de 63 caracteres.
- "((nombre-dominio).) {1,40}" - Me gustaría poner 127 aquí, pero en expresiones regulares el cuantificador {,} significa el intervalo de repetición. En el caso de usar [] {} - este es el número de caracteres, pero en el caso sin [] - este es exactamente el número de repeticiones de la plantilla (nombre de dominio).). Por lo tanto, limitamos la repetición a 40 para no exceder el límite de longitud general, que nosotros, por esta razón, tampoco podemos establecer estrictamente.
Tarea 8 - Elementos repetidos
http://callumacrae.imtqy.com/regex-tuesday/challenge8.html
La tarea es muy similar a la tarea 1 en muchos aspectos, pero aquí debe encontrar y resaltar los elementos repetidos de la lista MarkDown con dos estrellas.
Tal lista:
* Repeated list item * Repeated list item
Debe convertirse a esto:
* Repeated list item * **Repeated list item**
PistaUsamos un enlace de retroceso, un carácter de avance de línea, teclas globales, multilínea e insensibles.
SoluciónExpresión:
/^(\*\s+([^\n]+)\n\*\s+)(\2)$/gmi
Reemplazo:
$1**$3**
Tarea 9: enlaces MarkDown
http://callumacrae.imtqy.com/regex-tuesday/challenge9.html
Reemplace los enlaces válidos de MarkDown con enlaces html.
Ejemplo de conversión:
[Another](http://example.com/) -> <a href="http://example.com/">Another</a>
PistaSe puede hacer sin espiar, o simplemente mirando hacia el futuro. En lugar de mirar hacia atrás, es un reemplazo.
SoluciónExpresión:
/(^|\s+)\[([^\]\[]+)\]\s*\((https?:\/\/\b[az\d-]+\b(\.[az-]+)*\.\w+\/*)\)(?=$|\s+)/i
Reemplazo:
$1<a href="$3">$2</a>
Solución de análisis- "(^ | \ s +)": antes del enlace MarkDown, se permite el comienzo de una línea o un espacio. Tomamos esto en el grupo para sustituir el espacio capturado en el reemplazo de $ 1.
- "[([^] [] +)] \ s *": cualquier carácter que no sea comillas cuadradas está permitido en el encabezado.
- "(https ?: \ / \ / \ b [az \ d -] + \ b (. [az -] +) . \ w + \ / )" - comprobamos que la dirección URL es válida.
- "(? = $ | \ s +)": al final de un espacio o al final de una línea.
Tarea 10 - Palabras clave
http://callumacrae.imtqy.com/regex-tuesday/challenge10.html
El desafío más duro de todos. Usando expresiones regulares con reemplazos, convierta el texto existente en palabras clave separadas por comas.
Reglas
- Las comillas son una palabra clave.
- Los nombres con guiones son una palabra clave.
- La palabra puede contener un apóstrofe.
- Los símbolos (; - '") deben eliminarse.
Un ejemplo es este:
no le digas a Suzie Smith-Hopper que rompí el caballo de juguete de Daniel
Debería convertirse a esto:
no, dile, Suzie, Smith-Hopper, que, yo, rompí, Daniel's, juguete, caballo
A primera vista no parece complicado, pero no lo es. El hecho es que tal problema no se resuelve y no se lleva a la forma final con solo una expresión regular con un reemplazo. Pero los casos de prueba están diseñados de tal manera que de todos modos haría posible la solución al problema.
PistaEs necesario decidir dónde poner una coma, qué sustituir al lado de esta coma y de qué lado. Hay una suposición en el problema: la primera palabra en cada caso de prueba no requiere ningún cambio. Esto significa que debe poner una coma a la izquierda de la palabra reemplazada, excepto la primera palabra.
SoluciónExpresión:
/\s(['"])([^'"]+)\1|(;? |['"]? | ['"]|-{2,})(\w+)/g
Reemplazo:
,$2$4
Solución de análisisComo ya hemos decidido el lugar donde colocar la coma, decidiremos con qué reemplazaremos esta coma y qué eliminar.
- "\ s (['"]) ([^' "] +)" - reemplace la plantilla {espacio "de la palabra con un espacio entre comillas"} por {, palabras con un espacio} . "\ s" aquí no es solo así, sino para excluir ocurrencias falsas con comillas colocadas incorrectamente.
- "(;? | ['"]? | [' "] | - {2,}) (\ w +)" - luego hay palabras simples precedidas por caracteres que deben eliminarse y una coma antes de estas palabras.