Las expresiones regulares (regexes) son secuencias de caracteres que especifican un patrón de búsqueda en un texto.
Aprender la sintaxis de las expresiones regulares queda fuera del alcance de este tema.
Nos centraremos en las expresiones que ofrece jq para trabajar con expresiones regulares.
Distintas herramientas implementan distintas versiones de las expresiones regulares.
jq incorpora la biblioteca de expresiones regulares Oniguruma, que es en gran medida compatible con las expresiones regulares de Perl v5.8.
La sintaxis específica que utiliza jq se puede consultar en el repositorio de Oniguruma en GitHub.
jq no tiene ninguna sintaxis especial para las expresiones regulares.
Simplemente se expresan como strings.
Eso significa que las barras invertidas que contenga la expresión regular hay que escaparlas en el string.
Por ejemplo, la clase de caracteres de dígitos (\d) debe escribirse como "\\d".
Las expresiones regulares en jq se limitan a un conjunto de filtros.
Cuando necesites saber si un string coincide con un patrón, usa el filtro test.
STRING | test(REGEX)
STRING | test(REGEX; FLAGS)
STRING | test([REGEX, FLAGS])
Este filtro devuelve un resultado Boolean.
"Hello World!" | test("W") # => true
"Goodbye Mars" | test("W") # => false
Cuando necesites extraer la subcadena que realmente ha coincidido con el patrón, usa el filtro match.
STRING | match(REGEX)
STRING | match(REGEX; FLAGS)
STRING | match([REGEX, FLAGS])
Este filtro devuelve:
Este ejemplo busca dos vocales idénticas consecutivas usando la sintaxis de referencia hacia atrás, \1.
"Hello World!" | match("([aeiou])\\1")
# => empty
"Goodbye Mars" | match("([aeiou])\\1")
# => {
# "offset": 1,
# "length": 2,
# "string": "oo",
# "captures": [
# {
# "offset": 1,
# "length": 1,
# "string": "o",
# "name": null
# }
# ]
# }
El filtro match devuelve un objeto por cada coincidencia.
Este ejemplo muestra el flag "g" en acción para encontrar todas las vocales.
"Goodbye Mars" | match("[aeiou]"; "g")
# => { "offset": 1, "length": 1, "string": "o", "captures": [] }
# { "offset": 2, "length": 1, "string": "o", "captures": [] }
# { "offset": 6, "length": 1, "string": "e", "captures": [] }
# { "offset": 9, "length": 1, "string": "a", "captures": [] }
De forma similar al filtro match, el filtro capture devuelve un objeto si hubo una coincidencia.
STRING | capture(REGEX)
STRING | capture(REGEX; FLAGS)
STRING | capture([REGEX, FLAGS])
El objeto devuelto es una correspondencia de las capturas con nombre.
"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")
# => {
# "project": "JIRAISSUE",
# "issue_num": "1234"
# }
El filtro scan es similar a match con el flag "g".
STRING | scan(REGEX)
STRING | scan(REGEX; FLAGS)
# note, there is no scan([REGEX, FLAGS]) version, unlike other filters
scan generará un flujo de subcadenas.
"Goodbye Mars" | scan("[aeiou]")
# => "o"
# "o"
# "e"
# "a"
Usa el constructor de arrays [...] para capturar las subcadenas.
"Goodbye Mars" | [ scan("[aeiou]") ]
# => ["o", "o", "e", "a"]
Si conoces las partes del string que quieres conservar, usa match o scan.
Si conoces las partes que quieres descartar, usa split.
STRING | split(REGEX; FLAGS)
El filtro split de aridad 1 trata su argumento como un string fijo.
Para usar una expresión regular con split, debes proporcionar el segundo argumento; no pasa nada por usar un string vacío.
Un ejemplo que divide un string por espacios en blanco arbitrarios.
"first second third fourth" | split("\\s+"; "")
# => ["first", "second", "third", "fourth"]
Esto es lo que ocurre si nos olvidamos del argumento de los flags.
"first second third fourth" | split("\\s+")
# => ["first second third fourth"]
Un solo resultado: el string fijo \s+ no aparecía en la entrada.
El split de aridad 1 no puede manejar espacios en blanco arbitrarios.
Si dividimos por un espacio, obtenemos este resultado.
"first second third fourth" | split(" ")
# => ["first", "", "", "second", "", "", "", "",
# "", "", "", "", "", "", "third", "fourth" ]
Los filtros sub y gsub pueden transformar el string de entrada, sustituyendo las partes coincidentes de la entrada por un string de reemplazo.
Para sustituir solo la primera coincidencia, usa sub.
Para sustituir todas las coincidencias, usa gsub.
STRING | sub(REGEX; REPLACEMENT)
STRING | sub(REGEX; REPLACEMENT; FLAGS)
STRING | gsub(REGEX; REPLACEMENT)
STRING | gsub(REGEX; REPLACEMENT; FLAGS)
"Goodnight kittens. Goodnight mittens." | sub("night"; " morning")
# => "Good morning kittens. Goodnight mittens."
"Goodnight kittens. Goodnight mittens." | gsub("night"; " morning")
# => "Good morning kittens. Good morning mittens."
El texto de reemplazo puede hacer referencia a las subcadenas coincidentes; usa capturas con nombre e interpolación de strings.
"Some 3-letter acronyms: gnu, csv, png"
| gsub( "\\b(?<tla>[[:alpha:]]{3})\\b"; # find words 3 letters long
"\(.tla | ascii_upcase)" ) # upper-case the match
# => "Some 3-letter acronyms: GNU, CSV, PNG"
En todos los filtros anteriores, FLAGS es un string formado por cero o más de los flags admitidos.
g - Búsqueda global (encuentra todas las coincidencias, no solo la primera)i - Búsqueda que no distingue mayúsculas de minúsculasm - Modo multilínea ('.' coincidirá con los saltos de línea)n - Ignora las coincidencias vacíasp - Activa los modos s y m a la vezs - Modo de una sola línea ('^' -> '\A', '$' -> '\Z')l - Encuentra las coincidencias más largas posiblesx - Formato extendido de expresiones regulares (ignora los espacios en blanco y los comentarios)Por ejemplo
"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")
# or with Extended formatting
"JIRAISSUE-1234" | capture("
(?<project> \\w+ ) # the Jira project
- # followed by a hyphen
(?<issue_num> \\d+ ) # followed by digits
"; "x")