El paquete regexp ofrece soporte para expresiones regulares en Go.
La sintaxis de las expresiones regulares aceptadas es la misma sintaxis general que usan Perl, Python y otros lenguajes.
Tanto los patrones de búsqueda como los textos de entrada se interpretan como UTF-8.
Cuando usas comillas invertidas (`) para crear strings, las barras invertidas (\) no tienen ningún significado especial y no marcan el inicio de caracteres especiales como las tabulaciones \t o los saltos de línea \n:
"\t\n" // regular string literal with 2 characters: a tab and a newline
`\t\n`// raw string literal with 4 characters: two backslashes, a 't', and an 'n'
Por eso, conviene usar comillas invertidas para crear expresiones regulares, porque así no necesitas escapar las barras invertidas:
"\\" // string with a single backslash
`\\` // string with 2 backslashes
RegExp
Para usar una expresión regular, primero debemos compilar el patrón de string.
Compilar aquí significa tomar el patrón de string de la expresión regular y convertirlo en una representación interna con la que es más fácil trabajar.
Solo necesitamos compilar cada patrón una vez; después de eso, podemos usar la versión compilada de la expresión regular muchas veces.
El tipo regexp.Regexp representa una expresión regular compilada.
Podemos compilar un patrón de string en un regexp.Regexp usando la función regexp.Compile.
Esta función devuelve nil y un error si la compilación falló:
re, err := regexp.Compile(`(a|b)+`)
fmt.Println(re, err) // => (a|b)+ <nil>
re, err = regexp.Compile(`a|b)+`)
fmt.Println(re, err) // => <nil> error parsing regexp: unexpected ): `a|b)+`
La función MustCompile es una alternativa conveniente a Compile:
re = regexp.MustCompile(`[a-z]+\d*`)
Con esta función, no necesitas manejar ningún error.
MustCompile solo debe usarse cuando sabemos con certeza que el patrón sí compila, porque de lo contrario el programa entrará en pánico.
Hay 16 métodos de Regexp que buscan coincidencias con una expresión regular e identifican el texto coincidente.
Sus nombres coinciden con esta expresión regular:
Find(All)?(String)?(Submatch)?(Index)?
All está presente, el método busca coincidencias sucesivas y no superpuestas de toda la expresión.String está presente, el argumento es un string; de lo contrario, es un slice de bytes; los valores de retorno se ajustan según corresponda.Submatch está presente, el valor de retorno es un slice que identifica las subcoincidencias sucesivas de la expresión.Index está presente, las coincidencias y subcoincidencias se identifican mediante pares de índices de bytes dentro del string de entrada.También hay métodos para:
En total, el paquete regexp define más de 40 funciones y métodos.
A continuación, mostraremos el uso de algunos métodos.
Consulta la documentación de la API para ver los detalles de estas y otras funciones.
MatchString
El método MatchString indica si un string contiene alguna coincidencia de una expresión regular.
re = regexp.MustCompile(`[a-z]+\d*`)
b = re.MatchString("[a12]") // => true
b = re.MatchString("12abc34(ef)") // => true
b = re.MatchString(" abc!") // => true
b = re.MatchString("123 456") // => false
FindString
El método FindString devuelve un string con el texto de la coincidencia más a la izquierda de la expresión regular.
re = regexp.MustCompile(`[a-z]+\d*`)
s = re.FindString("[a12]") // => "a12"
s = re.FindString("12abc34(ef)") // => "abc34"
s = re.FindString(" abc!") // => "abc"
s = re.FindString("123 456") // => ""
FindStringSubmatch
El método FindStringSubmatch devuelve un slice de strings con el texto de la coincidencia más a la izquierda de la expresión regular y las coincidencias, si las hay, de sus subexpresiones.
Esto se puede usar para identificar los strings que coinciden con grupos de captura.
Un valor de retorno nil indica que no hay coincidencia.
re = regexp.MustCompile(`[a-z]+(\d*)`)
sl = re.FindStringSubmatch("[a12]") // => []string{"a12","12"}
sl = re.FindStringSubmatch("12abc34(ef)") // => []string{"abc34","34"}
sl = re.FindStringSubmatch(" abc!") // => []string{"abc",""}
sl = re.FindStringSubmatch("123 456") // => <nil>
ReplaceAllString
El método re.ReplaceAllString(src,repl) devuelve una copia de src, reemplazando las coincidencias de la expresión regular re con el string de reemplazo repl.
re = regexp.MustCompile(`[a-z]+\d*`)
s = re.ReplaceAllString("[a12]", "X") // => "[X]"
s = re.ReplaceAllString("12abc34(ef)", "X") // => "12X(X)"
s = re.ReplaceAllString(" abc!", "X") // => " X!"
s = re.ReplaceAllString("123 456", "X") // => "123 456"
Split
El método re.Split(s,n) divide un texto s en substrings separados por la expresión y devuelve un slice con los substrings entre esas coincidencias de la expresión.
El recuento n determina el número máximo de substrings a devolver.
Si n<0, el método devuelve todos los substrings.
re = regexp.MustCompile(`[a-z]+\d*`)
sl = re.Split("[a12]", -1) // => []string{"[","]"}
sl = re.Split("12abc34(ef)", 2) // => []string{"12","(ef)"}
sl = re.Split(" abc!", -1) // => []string{" ","!"}
sl = re.Split("123 456", -1) // => []string{"123 456"}
Este ejercicio aborda el análisis de archivos de log.
Después de una revisión de seguridad reciente, te pidieron que limpiaras los archivos de log archivados de la organización.
Está garantizado que todos los strings que se pasan a las funciones no son nulos y no tienen espacios al principio ni al final.
Necesitas hacerte una idea de cuántas líneas de log de tu archivo no cumplen con los estándares actuales. Crees que una prueba simple revela si una línea de log es válida. Para considerarse válida, una línea debe comenzar con uno de los siguientes strings:
Implementa la función IsValidLine para que devuelva false si un string no es válido y true en caso contrario.
IsValidLine("[ERR] A good error here")
// => true
IsValidLine("Any old [ERR] text")
// => false
IsValidLine("[BOB] Any old text")
// => false
Un equipo nuevo se unió a la organización y descubres que sus archivos de log usan un separador extraño para los «campos». En lugar de algo sensato como dos puntos «:», usan un string como «<--->» o «<=>» (porque es más bonito); de hecho, cualquier string cuyo primer carácter sea «<» y cuyo último carácter sea «>» y que tenga en medio cualquier combinación de los siguientes caracteres: «~», «*», «=» y «-».
Implementa la función SplitLogLine, que recibe una línea y devuelve un array de strings, cada uno de los cuales contiene un campo.
SplitLogLine("section 1<*>section 2<~~~>section 3")
// => []string{"section 1", "section 2", "section 3"},
password en texto entre comillasEl equipo necesita conocer las referencias a contraseñas en texto entre comillas para poder examinarlas manualmente.
Implementa la función CountQuotedPasswords para darte una idea de la magnitud probable del trabajo manual.
Identifica las líneas de log donde el string «password», que puede estar en cualquier combinación de mayúsculas y minúsculas, está rodeado de comillas. Debes tener en cuenta la posibilidad de que haya contenido adicional entre las comillas, antes y después de «password». Cada línea contendrá como máximo dos comillas.
Las líneas que se pasan a la rutina pueden ser válidas o no según lo definido en la tarea 1. Las procesamos de la misma manera, sean válidas o no.
lines := []string{
`[INF] passWord`, // contains 'password' but not surrounded by quotation marks
`"passWord"`, // count this one
`[INF] User saw error message "Unexpected Error" on page load.`, // does not contain 'password'
`[INF] The message "Please reset your password" was ignored by the user`, // count this one
}
// => 2
Has descubierto que algún procesamiento anterior de los logs ha estado dispersando por todos los logs el texto «end-of-line» seguido de un número de línea (sin un espacio intermedio).
Implementa la función RemoveEndOfLineText para que reciba un string, elimine el texto end-of-line y devuelva un string «limpio».
Las líneas que no contengan el texto end-of-line deben devolverse sin modificaciones.
Solo elimina el string end-of-line. No intentes ajustar los espacios en blanco.
RemoveEndOfLineText("[INF] end-of-line23033 Network Failure end-of-line27")
// => "[INF] Network Failure "
Te has dado cuenta de que algunas de las líneas de log incluyen oraciones que se refieren a usuarios.
Estas oraciones siempre contienen el string "User", seguido de uno o más espacios y luego un nombre de usuario.
Decides etiquetar esas líneas.
Implementa una función TagWithUserName que procese líneas de log:
"User " permanecen sin cambios."User ", antepón a la línea [USR] seguido del nombre de usuario.Por ejemplo:
result := TagWithUserName([]string{
"[WRN] User James123 has exceeded storage space.",
"[WRN] Host down. User Michelle4 lost connection.",
"[INF] Users can login again after 23:00.",
"[DBG] We need to check that user names are at least 6 chars long.",
})
// => []string {
// "[USR] James123 [WRN] User James123 has exceeded storage space.",
// "[USR] Michelle4 [WRN] Host down. User Michelle4 lost connection.",
// "[INF] Users can login again after 23:00.",
// "[DBG] We need to check that user names are at least 6 chars long."
// }
Puedes asumir que:
"User " en cada línea.Regístrate en Exercism para aprender y dominar Go con 34 conceptos165 ejercicios y mentoría humana real, todo gratis.