El paquete regexp ofrece soporte para expresiones regulares en Go.
La sintaxis de las expresiones regulares aceptadas es la misma sintaxis general que utilizan 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 los tabuladores \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 esto, es recomendable usar comillas invertidas para crear expresiones regulares, porque así no necesitamos 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.
Aquí, compilar significa tomar el patrón de string de la expresión regular y convertirlo en una representación interna con la que sea más fácil trabajar.
Solo necesitamos compilar cada patrón una vez; después, 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 falla:
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 cómoda a Compile:
re = regexp.MustCompile(`[a-z]+\d*`)
Con esta función, no es necesario gestionar un error.
MustCompile solo se debe usar cuando sabemos con seguridad que el patrón se compila; de lo contrario, el programa entrará en pánico.
Hay 16 métodos de Regexp que coinciden 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 encuentra coincidencias sucesivas no superpuestas de toda la expresión.String está presente, el argumento es un string; en caso contrario, es un slice de bytes; los valores devueltos se ajustan según corresponda.Submatch está presente, el valor devuelto 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 que contiene 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 que contiene 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 devuelto de 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 por 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 subcadenas separadas por la expresión y devuelve un slice de las subcadenas entre esas coincidencias de la expresión.
El recuento n determina el número máximo de subcadenas que se devuelven.
Si n<0, el método devuelve todas las subcadenas.
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 registro.
Tras una revisión de seguridad reciente, se te ha pedido que limpies los archivos de registro archivados de la organización.
Se garantiza 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 registro de tu archivo no cumplen los estándares actuales. Crees que una prueba sencilla revela si una línea de registro es válida. Para considerarse válida, una línea debe empezar por uno de los siguientes strings:
Implementa la función IsValidLine para que devuelva false si el 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 ha incorporado a la organización y descubres que sus archivos de registro 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 que tenga «<» como primer carácter y «>» como último carácter, y cualquier combinación de los caracteres «~», «*», «=» y «-» en medio.
Implementa la función SplitLogLine, que toma 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 saber qué referencias a contraseñas aparecen entre comillas para poder examinarlas manualmente.
Implementa la función CountQuotedPasswords para darte una idea de la probable magnitud del trabajo manual.
Identifica las líneas de registro en las que 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 del mismo modo, tanto si son válidas como si 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 cierto procesamiento previo de los registros ha ido dispersando por ellos el texto «end-of-line» seguido de un número de línea (sin un espacio intermedio).
Implementa la función RemoveEndOfLineText, que toma un string, elimina el texto «end-of-line» y devuelve un string «limpio».
Las líneas que no contengan el texto «end-of-line» deben devolverse sin modificar.
Limítate a eliminar 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 líneas de registro incluyen frases que se refieren a usuarios.
Estas frases siempre contienen el string "User", seguido de uno o más espacios y, a continuación, un nombre de usuario.
Decides etiquetar esas líneas.
Implementa una función TagWithUserName que procese líneas de registro:
"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 dar por sentado 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.