Las expresiones regulares (regex) son secuencias de caracteres que especifican un patrón de búsqueda en un texto.
Aprender la sintaxis de las expresiones regulares está fuera del alcance de este tema.
Nos centraremos en las expresiones que jq proporciona para utilizar regex.
Diferentes herramientas implementan diferentes versiones de las expresiones regulares.
jq incorpora la biblioteca de regex Oniguruma, que es en gran medida compatible con las regex de Perl v5.8.
La sintaxis específica que usa jq se puede encontrar en el repositorio de GitHub de Oniguruma.
jq no tiene ninguna sintaxis especial para las expresiones regulares.
Simplemente se expresan como strings.
Eso significa que cualquier barra invertida en la expresión regular debe escaparse en el string.
Por ejemplo, la clase de carácter de dígito (\d) debe escribirse como "\\d".
Las expresiones regulares en jq se limitan a un conjunto de filtros.
Cuando necesitas 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 produce un resultado Boolean.
"Hello World!" | test("W") # => true
"Goodbye Mars" | test("W") # => false
Cuando necesitas extraer la subcadena que realmente coincidió con el patrón, usa el filtro match.
STRING | match(REGEX)
STRING | match(REGEX; FLAGS)
STRING | match([REGEX, FLAGS])
Este filtro produce:
Este ejemplo busca dos vocales idénticas consecutivas usando la sintaxis de referencia inversa, \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 la bandera "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 un mapeo 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 la bandera "g".
STRING | scan(REGEX)
STRING | scan(REGEX; FLAGS)
# note, there is no scan([REGEX, FLAGS]) version, unlike other filters
scan producirá un flujo de subcadenas.
"Goodbye Mars" | scan("[aeiou]")
# => "o"
# "o"
# "e"
# "a"
Usa el constructor de array [...] 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 regex con split, debes proporcionar el segundo argumento; está bien usar un string vacío.
Un ejemplo que divide un string en espacios en blanco arbitrarios.
"first second third fourth" | split("\\s+"; "")
# => ["first", "second", "third", "fourth"]
Esto es lo que pasa si olvidamos el argumento de banderas.
"first second third fourth" | split("\\s+")
# => ["first second third fourth"]
Solo un resultado: el string fijo \s+ no se encontró en el string.
El split de aridad 1 no puede manejar espacios en blanco arbitrarios.
Dividir por un espacio da este resultado.
"first second third fourth" | split(" ")
# => ["first", "", "", "second", "", "", "", "",
# "", "", "", "", "", "", "third", "fourth" ]
Los filtros sub y gsub pueden transformar el string original, reemplazando las porciones coincidentes del string con un string de reemplazo.
Para reemplazar solo la primera coincidencia, usa sub.
Para reemplazar 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 que consta de cero o más de las banderas admitidas.
g - Búsqueda global (encuentra todas las coincidencias, no solo la primera)i - Búsqueda que no distingue mayúsculas y minúsculasm - Modo multilínea ('.' coincidirá con saltos de línea)n - Ignorar coincidencias vacíasp - Los modos s y m están habilitadoss - Modo de una sola línea ('^' -> '\A', '$' -> '\Z')l - Encontrar las coincidencias más largas posiblesx - Formato de regex extendido (ignora espacios en blanco y 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")