Expressões regulares (regexes) são sequências de caracteres que especificam um padrão de busca em um texto.
Aprender a sintaxe de expressões regulares está além do escopo deste tópico.
Vamos nos concentrar nas expressões que o jq oferece para usar regexes.
Ferramentas diferentes implementam versões diferentes de expressões regulares.
O jq incorpora a biblioteca de regex Oniguruma, que é amplamente compatível com as regexes do Perl v5.8.
A sintaxe específica usada pelo jq pode ser encontrada no repositório do Oniguruma no GitHub.
O jq não tem nenhuma sintaxe especial para expressões regulares.
Elas são simplesmente expressas como strings.
Isso significa que qualquer barra invertida na expressão regular precisa ser escapada na string.
Por exemplo, a classe de caractere de dígito (\d) deve ser escrita como "\\d".
As expressões regulares no jq se limitam a um conjunto de filtros.
Quando você precisa saber se uma string corresponde a um padrão, use o filtro test.
STRING | test(REGEX)
STRING | test(REGEX; FLAGS)
STRING | test([REGEX, FLAGS])
Esse filtro gera um resultado boolean.
"Hello World!" | test("W") # => true
"Goodbye Mars" | test("W") # => false
Quando você precisa extrair a substring que de fato correspondeu ao padrão, use o filtro match.
STRING | match(REGEX)
STRING | match(REGEX; FLAGS)
STRING | match([REGEX, FLAGS])
Esse filtro gera:
Este exemplo procura duas vogais consecutivas idênticas usando a sintaxe de retro-referê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 retorna um objeto para 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": [] }
Semelhante ao filtro match, o filtro capture retorna um objeto se houve correspondência.
STRING | capture(REGEX)
STRING | capture(REGEX; FLAGS)
STRING | capture([REGEX, FLAGS])
O objeto retornado é um mapeamento das capturas nomeadas.
"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")
# => {
# "project": "JIRAISSUE",
# "issue_num": "1234"
# }
O filtro scan é semelhante ao match com a flag "g".
STRING | scan(REGEX)
STRING | scan(REGEX; FLAGS)
O scan gera um fluxo de substrings.
"Goodbye Mars" | scan("[aeiou]")
# => "o"
# "o"
# "e"
# "a"
Use o construtor de array [...] para capturar as substrings.
"Goodbye Mars" | [ scan("[aeiou]") ]
# => ["o", "o", "e", "a"]
Se você sabe quais partes da string quer manter, use match ou scan.
Se você sabe quais partes quer descartar, use split.
STRING | split(REGEX; FLAGS)
O filtro split de aridade 1 trata seu argumento como uma string fixa.
Para usar uma regex com split, você precisa fornecer o 2º argumento; não tem problema 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"]
Os filtros sub e gsub podem transformar a string de entrada, substituindo as partes correspondentes da entrada por uma string de substituição.
Para substituir apenas a primeira correspondência, use sub.
Para substituir todas as correspondências, use 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 se referir às substrings correspondentes; use 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"
Em todos os filtros acima, FLAGS é uma string composta de zero ou mais das flags compatíveis.
g - Busca global (encontra todas as correspondências, não apenas a primeira)i - Busca sem diferenciar maiúsculas e minúsculasm - Modo multilinha ('.' corresponde a quebras de linha)n - Ignora correspondências vaziasp - Os modos s e m são ativadoss - Modo de linha única ('^' -> '\A', '$' -> '\Z')l - Encontra as correspondências mais longas possíveisx - Formato de regex 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")
Contrataram você como Especialista em Expressões Regulares em uma empresa que está desenvolvendo um Chatbot.
Ela está em uma fase muito básica de desenvolvimento. Sua missão é usar Expressões Regulares para melhorar a capacidade do Chatbot de entender e gerar linguagem natural.
Além de inteligente, o Chatbot também é um assistente leal. Para perguntar algo ao Chatbot, o usuário deve dizer a palavra "Chatbot" na primeira posição do comando. Não importa se a palavra-chave está em MAIÚSCULAS ou minúsculas. O importante é a posição da palavra.
Implemente a função is_valid_command que ajuda o Chatbot a reconhecer quando o usuário está dando um comando.
"Chatbot, play a song from the 80's." | is_valid_command
# => true
"Hey Chatbot, where is the closest pharmacy?" | is_valid_command
# => false
"CHATBOT, do you have a solution for this challenge?" | is_valid_command
# => true
O Chatbot tem dificuldade para entender como as pessoas usam emojis para expressar suas emoções. Quando o Chatbot recebe mensagens de usuários, cada emoji é representado pela string "emoji" seguida de um número de id.
Implemente o método remove_emoji, que recebe uma string e remove todos os emojis da mensagem.
Linhas que não contêm emojis devem ser retornadas sem modificações. Basta remover a string do emoji. Não ajuste os espaços em branco.
"I love playing videogames emoji3465 it's one of my hobbies" | remove_emoji
# => "I love playing videogames it's one of my hobbies"
Em algum momento da interação com o Chatbot, o usuário vai fornecer um número de telefone. O Chatbot só consegue ligar para um número com um formato específico.
Implemente a função check_phone_number.
Se o número for válido, o Chatbot responde com uma mensagem agradecendo ao usuário e confirmando o número. Se o número for inválido, o Chatbot informa ao usuário que o número de telefone não é válido.
O formato esperado é (+NN) NNN-NNN-NNN, em que N é um dígito.
"chatbot my phone number is (+34) 659-771-594" | check_phone_number
# => "Thanks! Your phone number is OK."
"chatbot, call me at 659-771-594" | check_phone_number
# => "Oops, it seems like I can't reach out to 659-771-594."
O Chatbot é um software muito curioso. Apesar de conseguir pesquisar na internet sobre um assunto específico, ele gosta de perguntar aos usuários sobre sites legais para visitar e encontrar informações relevantes.
Exemplo de conversa:
Chatbot: Ei, Usuário, eu gostaria de aprender a programar em JavaScript. Você conhece algum site legal onde eu poderia aprender?
Usuário: Eu aprendi muito no exercism.org, tem muita coisa boa lá.
Implemente a função get_domains, que retorna um array de domínios de sites.
"I learned a lot from exercism.org and google.com" | get_domains
# => ["exercism.org", "google.com"]
Um Chatbot educado fala com os usuários pelo nome. Quando um usuário se apresenta, nosso Chatbot detecta o nome e responde com uma saudação amigável.
Escreva a função nice_to_meet_you.
Se a string de entrada contiver "My name is Someone.", capture o nome e retorne a string "Nice to meet you, Someone.".
"My name is Jean-Luc" | nice_to_meet_you
# => "Nice to meet you, Jean-Luc"
Cedendo à mania de adicionar cada vez mais funcionalidades, vamos adicionar uma função de análise de CSV ao Chatbot.
Implemente a função parse_csv, que recebe uma string e retorna um array com os campos resultantes.
O separador de campos deve ser "vírgula mais espaço em branco opcional".
Não vamos nos preocupar com os casos limite do formato CSV (como campos que contêm vírgulas).
"first, second,third, fourth" | parse_csv
# => ["first", "second", "third", "fourth"]
Crie sua conta no Exercism para aprender e dominar jq com 12 conceitos75 exercícios e mentoria humana de verdade, tudo de graça.