Las expresiones regulares son una forma muy versátil de hacer coincidir patrones en strings, usando un lenguaje de dominio específico (DSL) diseñado para ese propósito.
Como varios otros lenguajes de programación, Julia no intenta implementar su propia biblioteca de Regex. En su lugar, envuelve la popular biblioteca PCRE2, ofreciendo así una sintaxis de Regex idéntica a la de (por ejemplo) Gleam, y muy similar a la de JavaScript.
Este temario de Julia asume que ya conoces la sintaxis básica de Regex. Nos concentraremos únicamente en las características específicas de Julia.
Abajo encontrarás 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 es simplemente un string al que se le antepone una r antes de la " de apertura.
Toda la funcionalidad básica es parte de la biblioteca estándar.
De hecho, muchas de las funciones que ya se trataron en el concepto Strings están diseñadas para hacer 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
Puedes poner caracteres modificadores después de la comilla de cierre, como i para una coincidencia que no distingue mayúsculas y minúsculas.
julia> occursin(r"test", "Testing")
false
julia> occursin(r"test"i, "Testing")
true
Con frecuencia queremos saber qué coincide. Esto se logra incluyendo grupos de captura entre paréntesis dentro de la regex, y luego usando 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.
El resultado será entonces el valor especial Nothing en lugar de un RegexMatch, así que prepárate para verificarlo.
# failed match
m = match(r"(not here)", "dissolve 25g sugar in 200ml water")
julia> typeof(m)
Nothing
julia> isnothing(m)
true
Aunque match comienza por defecto al inicio 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 objetivo: no hay 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 necesites 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"
Una razón común para usar una Regex es reemplazar la coincidencia con un string diferente.
La función replace() se trató en el concepto Strings, usando literales de string sobre los que buscar.
La misma función puede aprovechar toda la potencia de las coincidencias con 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 constantemente obliga 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 son posibles otras alternativas (¡y hasta pueden ser más eficientes!)
Además de ser inteligente, el chatbot también es un asistente leal.
Para pedirle 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 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 las personas usan 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 los emojis a lo largo del mensaje.
Las líneas que no contengan el texto de emojis deben devolverse sin modificar.
Solo elimina el string 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"
Dado que las funcionalidades del chatbot se descargan en una app 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 le informa al usuario 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 software muy curioso. Aunque puede buscar en internet sobre un tema en particular, le gusta preguntar a los usuarios por sitios web interesantes o URL para encontrar información relevante.
Ejemplo de conversación:
Implementa la función getURL() que puede devolver un array con solo el enlace de cada sitio web.
julia> getURL("I learned a lot from exercism.org")
["exercism.org"]
Para guardar los datos de todas las personas que han conversado con él, el chatbot puede obtener el nombre completo del perfil del usuario con este estilo: «smith, john».
De esta forma, queremos que nuestro chatbot sea realmente 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.