Tracks
/
jq
jq
/
Temario
/
Expresiones regulares
Ex

Expresiones regulares en jq

1 ejercicio

Acerca de Expresiones regulares

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.

Variante de 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.

Caution

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".

Funciones de regex

Las expresiones regulares en jq se limitan a un conjunto de filtros.

Coincidencia simple

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

Información sobre la coincidencia

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:

  • nada si no hubo coincidencia, o
  • un objeto que contiene varias propiedades si hubo una coincidencia.

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": [] }

Subcadenas capturadas

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"
#    }

Solo las subcadenas

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"]

Dividir un string

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)
Caution

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"]
Note

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" ]

Sustituciones

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"

Banderas

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úsculas
  • m - Modo multilínea ('.' coincidirá con saltos de línea)
  • n - Ignorar coincidencias vacías
  • p - Los modos s y m están habilitados
  • s - Modo de una sola línea ('^' -> '\A', '$' -> '\Z')
  • l - Encontrar las coincidencias más largas posibles
  • x - 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")
Editar en GitHub El enlace se abre en una ventana o pestaña nueva

Aprende Expresiones regulares

La práctica está bloqueada

Desbloquea 1 ejercicio más para practicar Expresiones regulares