Percursos
/
jq
jq
/
Programa
/
Expressões regulares
Ex

Expressões regulares em jq

1 exercício

Sobre Expressões regulares

As expressões regulares (regex) são sequências de carateres que especificam um padrão de pesquisa num texto.

Aprender a sintaxe das expressões regulares está fora do âmbito deste tópico. Vamos focar-nos nas expressões que o jq disponibiliza para usar expressões regulares.

Variante das expressões regulares

Ferramentas diferentes implementam versões diferentes das expressões regulares. O jq incorpora a biblioteca de expressões regulares Oniguruma, que é em grande parte compatível com as expressões regulares do Perl v5.8.

A sintaxe específica usada pelo jq pode ser consultada no repositório GitHub da Oniguruma.

Caution

O jq não tem nenhuma sintaxe especial para expressões regulares. São simplesmente expressas como strings. Isso significa que as barras invertidas nas expressões regulares têm de ser escapadas na string.

Por exemplo, a classe de carateres de algarismos (\d) tem de ser escrita como "\\d".

Funções de expressões regulares

As expressões regulares no jq limitam-se a um conjunto de filtros.

Correspondência simples

Quando precisas de saber se uma string corresponde a um padrão, usa o filtro test.

STRING | test(REGEX)
STRING | test(REGEX; FLAGS)
STRING | test([REGEX, FLAGS])

Este filtro produz um resultado boolean.

"Hello World!" | test("W")    # => true
"Goodbye Mars" | test("W")    # => false

Informação sobre a correspondência

Quando precisas de extrair a substring que correspondeu de facto ao padrão, usa o filtro match.

STRING | match(REGEX)
STRING | match(REGEX; FLAGS)
STRING | match([REGEX, FLAGS])

Este filtro produz:

  • nada, se não houver correspondência, ou
  • um objeto com várias propriedades, se houver correspondência.

Este exemplo procura duas vogais consecutivas iguais, usando a sintaxe de retroreferência, \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
#        }
#      ]
#    }

O filtro match devolve um objeto por cada correspondência. Este exemplo mostra a flag "g" em ação para encontrar todas as vogais.

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

Substrings capturadas

Tal como o filtro match, o filtro capture devolve um objeto se houver correspondência.

STRING | capture(REGEX)
STRING | capture(REGEX; FLAGS)
STRING | capture([REGEX, FLAGS])

O objeto devolvido é um mapeamento das capturas nomeadas.

"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")
# => {
#      "project": "JIRAISSUE",
#      "issue_num": "1234"
#    }

Apenas as substrings

O filtro scan é semelhante ao match com a flag "g".

STRING | scan(REGEX)
STRING | scan(REGEX; FLAGS)

# note, there is no scan([REGEX, FLAGS]) version, unlike other filters

O scan produz um fluxo de substrings.

"Goodbye Mars" | scan("[aeiou]")
# => "o"
#    "o"
#    "e"
#    "a"

Usa o construtor de array [...] para capturar as substrings.

"Goodbye Mars" | [ scan("[aeiou]") ]
# => ["o", "o", "e", "a"]

Dividir uma string

Se souberes que partes da string queres manter, usa match ou scan. Se souberes que partes queres descartar, usa split.

STRING | split(REGEX; FLAGS)
Caution

O filtro split de aridade 1 trata o seu argumento como uma string fixa.

Para usar uma expressão regular com o split, tens de indicar o segundo argumento; podes usar uma string vazia.

Um exemplo que divide uma string em espaços em branco arbitrários.

"first   second           third fourth" | split("\\s+"; "")
# => ["first", "second", "third", "fourth"]
Note

Isto é o que acontece se nos esquecermos do argumento das flags.

"first   second           third fourth" | split("\\s+")
# => ["first   second           third fourth"]

Só um resultado: a string fixa \s+ não apareceu no texto de entrada.

O split de aridade 1 não consegue lidar com espaços em branco arbitrários. Dividir por um espaço dá este resultado.

"first   second           third fourth" | split(" ")
# => ["first", "", "", "second", "", "", "", "",
#     "", "", "", "", "", "", "third", "fourth" ]

Substituições

Os filtros sub e gsub podem transformar a string de entrada, substituindo as partes correspondentes por uma string de substituição.

Para substituir apenas a primeira correspondência, usa sub. Para substituir todas as correspondências, 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."

O texto de substituição pode referir-se às substrings correspondentes; usa capturas nomeadas e interpolação 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

Em todos os filtros acima, FLAGS é uma string composta por zero ou mais das flags suportadas.

  • g - Procura global (encontra todas as correspondências, não apenas a primeira)
  • i - Procura que não distingue maiúsculas de minúsculas
  • m - Modo multilinha (o '.' corresponde a mudanças de linha)
  • n - Ignora correspondências vazias
  • p - Ativa os modos s e m em simultâneo
  • s - Modo de linha única ('^' -> '\A', '$' -> '\Z')
  • l - Encontra as correspondências mais longas possíveis
  • x - Formato de expressão regular estendido (ignora espaços em branco e comentários)

Por exemplo

"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 via GitHub A ligação abre numa nova janela ou separador

Aprende Expressões regulares

A prática está bloqueada

Desbloqueia mais 1 exercício para praticares Expressões regulares