Tracks
/
jq
jq
/
Temario
/
Expresiones regulares
Ex

Expresiones regulares en jq

1 ejercicio

Acerca de Expresiones regulares

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.

Dialecto de las 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.

Caution

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

Funciones de expresiones regulares

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

Coincidencia simple

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

Información sobre la coincidencia

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:

  • nada si no hubo ninguna coincidencia, o
  • un objeto con diversas propiedades si hubo una coincidencia.

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

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

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

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

Sustituciones

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"

Flags

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

Aprende Expresiones regulares

La práctica está bloqueada

Desbloquea 1 ejercicio más para practicar Expresiones regulares