Las expresiones regulares son una forma muy versátil de hacer pattern matching sobre strings, usando un lenguaje de dominio específico (DSL) diseñado para ello.
Como otros tantos lenguajes de programación, Julia no intenta implementar su propia biblioteca de Regex. En su lugar, envuelve la popular biblioteca PCRE2, lo que le proporciona una sintaxis de Regex idéntica a la de (por ejemplo) Gleam y muy similar a la de JavaScript.
Este temario de Julia da por supuesto que ya conoces la sintaxis básica de las Regex. Nos centraremos únicamente en las características específicas de Julia.
A continuación se enumeran algunos recursos para refrescar tus conocimientos sobre expresiones regulares.
La interfaz de Julia con las expresiones regulares se describe en el manual.
Una expresión regular en Julia no es más que un string precedido por r antes de la comilla de apertura ".
Toda la funcionalidad básica forma parte de la biblioteca estándar.
De hecho, muchas de las funciones que ya se han tratado en el concepto Strings están diseñadas para búsquedas con Regex de forma estándar, como occursin().
julia> re = r"test$"
r"test$"
julia> typeof(re)
Regex
# Does a string end with "test"?
julia> occursin(re, "this is a test")
true
julia> occursin(re, "these are tests")
false
Tras la comilla de cierre pueden aparecer caracteres modificadores, como i para una coincidencia que no distingue entre mayúsculas y minúsculas.
julia> occursin(r"test", "Testing")
false
julia> occursin(r"test"i, "Testing")
true
A menudo queremos saber qué coincide.
Para ello se incluyen grupos de captura entre paréntesis dentro de la Regex y luego se usa la función match().
julia> m = match(r"(\d+g) .* (\d+ml)", "dissolve 25g sugar in 200ml water")
RegexMatch("25g sugar in 200ml", 1="25g", 2="200ml")
julia> m.captures
2-element Vector{Union{Nothing, SubString{String}}}:
"25g"
"200ml"
# how many matches?
julia> length(m.captures)
2
# what matched?
julia> m[1], m[2]
("25g", "200ml")
# Starting positions of the matches (character index)
julia> m.offsets
2-element Vector{Int64}:
10
23
Por supuesto, las coincidencias pueden fallar.
En ese caso, el resultado será el valor especial Nothing en lugar de un RegexMatch, así que prepárate para comprobarlo.
# failed match
m = match(r"(not here)", "dissolve 25g sugar in 200ml water")
julia> typeof(m)
Nothing
julia> isnothing(m)
true
Aunque match empieza por defecto al principio del string, también podemos especificar un desplazamiento n para ignorar los primeros n caracteres.
# capture first match
julia> m = match(r"(\wat)", "cat, sat, mat")
RegexMatch("cat", 1="cat")
# ignore first 5 characters, then match
julia> m = match(r"(\wat)", "cat, sat, mat", 5)
RegexMatch("sat", 1="sat")
En Julia, match() solo encuentra la primera coincidencia dentro del string de destino: no existe un modificador global como en otros lenguajes.
En su lugar, tenemos eachmatch(), que devuelve un iterador de coincidencias.
Se evalúa de forma perezosa, así que puede que tengas que convertirlo al formato que quieras.
julia> matches = eachmatch(r"(\wat)", "cat, sat, mat")
Base.RegexMatchIterator{String}(r"(\wat)", "cat, sat, mat", false)
# convert to vector
julia> collect(matches)
3-element Vector{RegexMatch}:
RegexMatch("cat", 1="cat")
RegexMatch("sat", 1="sat")
RegexMatch("mat", 1="mat")
# convert with comprehension
julia> [m.match for m in matches]
3-element Vector{SubString{String}}:
"cat"
"sat"
"mat"
# broadcast an anonymous function
julia> (m -> m.match).(matches)
3-element Vector{SubString{String}}:
"cat"
"sat"
"mat"
Un motivo habitual para usar una Regex es reemplazar la coincidencia por un string distinto.
La función replace() se trató en el concepto Strings, usando literales de string para buscar.
Esa misma función puede aprovechar toda la potencia de las coincidencias de Regex.
julia> replace("some string", r"[aeiou]" => "*")
"s*m* str*ng"
julia> replace("first second", r"(\w+) (?<agroup>\w+)" => s"\g<agroup> \1")
"second first"
El segundo ejemplo de arriba muestra cómo se pueden usar tanto grupos de captura numerados como con nombre en el reemplazo, dentro de un string s" ".
Consulta el manual para más detalles: ¡este es un tema que obliga constantemente a la mayoría de los programadores a volver a la documentación!
Te han contratado como especialista en expresiones regulares en una empresa que está desarrollando un chatbot.
Está en una fase de desarrollo muy básica, así que tu misión es usar expresiones regulares para mejorar la capacidad del chatbot de entender y generar lenguaje natural.
Con fines de aprendizaje, resuelve estas tareas usando expresiones regulares.
Sabemos que a veces existen alternativas (¡y puede que incluso sean más eficientes!)
Además de ser inteligente, el chatbot también es un asistente leal.
Para preguntarle algo al chatbot, el usuario debe decir la palabra «Chatbot» en la primera posición del comando.
No importa si la palabra clave está en mayúsculas o en minúsculas. Lo importante aquí es la posición de la palabra.
Implementa la función is_valid_command() que ayuda al chatbot a reconocer cuándo el usuario está dando un comando.
julia> is_valid_command("Chatbot, play a song from the 80's.")
True
julia> is_valid_command("Hey Chatbot, where is the closest pharmacy?")
False
julia> is_valid_command("CHATBOT, do you have a solution for this challenge?")
True
Al chatbot le cuesta entender cómo usan las personas los emojis para expresar sus emociones.
Cuando el chatbot recibe mensajes de los usuarios, cada emoji se representa como «emoji» seguido de su número id.
Implementa el método remove_emoji() para que tome un string y elimine todo el cifrado de emojis del mensaje.
Las líneas que no contengan el texto de un emoji deben devolverse sin modificar.
Elimina solo el texto del emoji. No intentes ajustar los espacios en blanco.
julia> remove_emoji("I love playing videogames emoji3465 it's one of my hobbies")
"I love playing videogames it's one of my hobbies"
Teniendo en cuenta la descarga de funcionalidades del chatbot en una aplicación móvil, se espera que el usuario escriba un número de teléfono durante la conversación.
El problema es que el chatbot solo puede leer y validar un número con un formato específico.
Si el número es válido (coincide con la secuencia de caracteres especificada por la expresión regular), el chatbot responde con un mensaje que agradece al usuario y confirma el número. Si el número no es válido, la función informa al usuario de que el número de teléfono no es válido.
El formato esperado es: (+##) ###-###-###
julia> check_phone_number("(+34) 659-771-594")
"Thanks! You can now download me to your phone."
julia> check_phone_number("659-771-594")
"Oops, it seems like I can't reach out to 659-771-594"
El chatbot es un programa muy curioso. Aunque puede buscar en internet información sobre un tema concreto, le gusta preguntar a los usuarios por sitios web o URL interesantes donde encontrar información relevante.
Ejemplo de conversación:
Implementa la función getURL() que es capaz de devolver un array solo con el enlace de cada sitio web.
julia> getURL("I learned a lot from exercism.org")
["exercism.org"]
Para almacenar los datos de todas las personas con las que ha conversado, el chatbot puede obtener el nombre completo del perfil del usuario con este estilo: «smith, john».
De esta forma, queremos que nuestro chatbot sea muy educado y cause una buena impresión.
Escribe la función nice_to_meet_you() que toma un string con el nombre completo del usuario y devuelve el string «Nice to meet you, John Smith»
julia> str = "Smith, John"
julia> nice_to_meet_you(str)
"Nice to meet you, John Smith"
Regístrate en Exercism para aprender y dominar Julia con 35 conceptos128 ejercicios y mentoría humana real, todo gratis.