regex - probar - expresiones regulares java
¿Cómo obtener la funcionalidad de grupo de captura en las expresiones regulares de Golang? (4)
Estoy portando una biblioteca de Ruby to Go, y acabo de descubrir que las expresiones regulares en Ruby no son compatibles con Go (google RE2). Me llamó la atención que Ruby y Java (además de otros lenguajes usan expresiones regulares PCRE (perl compatible, que admite grupos de captura)), por lo que necesito volver a escribir mis expresiones para que se compilen en Go
Por ejemplo, tengo el siguiente regex:
`(?<Year>/d{4})-(?<Month>/d{2})-(?<Day>/d{2})`
Esto debería aceptar entradas tales como:
2001-01-20
Los grupos de captura permiten que el año, el mes y el día se capturen en variables. Para obtener el valor de cada grupo, es muy fácil; simplemente indexa los datos coincidentes devueltos con el nombre del grupo y recupera el valor. Así, por ejemplo, para obtener el año, algo así como este pseudo código:
m=expression.Match("2001-01-20")
year = m["Year"]
Este es un patrón que uso mucho en mis expresiones, así que tengo que reescribir muchas cosas.
Entonces, ¿hay una manera de obtener este tipo de funcionalidad en Go regexp; ¿Cómo debo reescribir estas expresiones?
¿Cómo debo reescribir estas expresiones?
Agregue algunas Ps, como se define here :
(?P<Year>/d{4})-(?P<Month>/d{2})-(?P<Day>/d{2})
Referencia cruzada de nombres de grupos de captura con re.SubexpNames()
.
Y usar de la siguiente manera :
package main
import (
"fmt"
"regexp"
)
func main() {
r := regexp.MustCompile(`(?P<Year>/d{4})-(?P<Month>/d{2})-(?P<Day>/d{2})`)
fmt.Printf("%#v/n", r.FindStringSubmatch(`2015-05-27`))
fmt.Printf("%#v/n", r.SubexpNames())
}
Había creado una función para manejar expresiones de URL, pero también se adapta a sus necesidades. Puedes revisar this fragmento, pero simplemente funciona así:
/**
* Parses url with the given regular expression and returns the
* group values defined in the expression.
*
*/
func getParams(regEx, url string) (paramsMap map[string]string) {
var compRegEx = regexp.MustCompile(regEx)
match := compRegEx.FindStringSubmatch(url)
paramsMap = make(map[string]string)
for i, name := range compRegEx.SubexpNames() {
if i > 0 && i <= len(match) {
paramsMap[name] = match[i]
}
}
return
}
Puedes usar esta función como:
params := getParams(`(?P<Year>/d{4})-(?P<Month>/d{2})-(?P<Day>/d{2})`, `2015-05-27`)
fmt.Println(params)
y la salida será:
map[Year:2015 Month:05 Day:27]
Para mejorar el uso de la RAM y la CPU sin llamar a funciones anónimas dentro del bucle y sin copiar arreglos en la memoria dentro del bucle con la función "agregar", vea el siguiente ejemplo:
Puede almacenar más de un subgrupo con texto multilínea, sin agregar la cadena con ''+'' y sin usar el bucle interno para el bucle (como otros ejemplos publicados aquí).
txt := `2001-01-20
2009-03-22
2018-02-25
2018-06-07`
regex := *regexp.MustCompile(`(?s)(/d{4})-(/d{2})-(/d{2})`)
res := regex.FindAllStringSubmatch(txt, -1)
for i := range res {
//like Java: match.group(1), match.gropu(2), etc
fmt.Printf("year: %s, month: %s, day: %s/n", res[i][1], res[i][2], res[i][3])
}
Salida:
year: 2001, month: 01, day: 20
year: 2009, month: 03, day: 22
year: 2018, month: 02, day: 25
year: 2018, month: 06, day: 07
Nota: res [i] [0] = ~ match.group (0) Java
Si desea almacenar esta información use un tipo de estructura:
type date struct {
y,m,d int
}
...
func main() {
...
dates := make([]date, 0, len(res))
for ... {
dates[index] = date{y: res[index][1], m: res[index][2], d: res[index][3]}
}
}
Es mejor usar grupos anónimos (mejora del rendimiento)
Usar "ReplaceAllGroupFunc" publicado en Github es una mala idea porque:
- está usando bucle dentro de bucle
- está usando una función anónima llamada dentro del bucle
- tiene mucho código
- está usando la función "agregar" dentro del bucle y eso es malo. Cada vez que se realiza una llamada a la función "añadir", se está copiando la matriz a la nueva posición de memoria
Si necesita reemplazar en función de una función mientras captura grupos, puede usar esto:
import "regexp"
func ReplaceAllGroupFunc(re *regexp.Regexp, str string, repl func([]string) string) string {
result := ""
lastIndex := 0
for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) {
groups := []string{}
for i := 0; i < len(v); i += 2 {
groups = append(groups, str[v[i]:v[i+1]])
}
result += str[lastIndex:v[0]] + repl(groups)
lastIndex = v[1]
}
return result + str[lastIndex:]
}
Ejemplo:
str := "abc foo:bar def baz:qux ghi"
re := regexp.MustCompile("([a-z]+):([a-z]+)")
result := ReplaceAllGroupFunc(re, str, func(groups []string) string {
return groups[1] + "." + groups[2]
})
fmt.Printf("''%s''/n", result)