grex é uma biblioteca e também um utilitário de linha de comando que visa simplificar a tarefa muitas vezes complicada e tediosa de criar expressões regulares. Isso é feito gerando automaticamente uma única expressão regular a partir de casos de teste fornecidos pelo usuário. É garantido que a expressão resultante corresponda aos casos de teste a partir dos quais foi gerada.
Este projeto começou como uma versão Rust da ferramenta JavaScript regexgen escrita por Devon Govett. Embora muitos outros recursos úteis pudessem ser adicionados a ele, seu desenvolvimento aparentemente foi interrompido há vários anos. O plano agora é adicionar esses novos recursos ao grex, já que o Rust realmente brilha quando se trata de ferramentas de linha de comando. grex oferece todos os recursos que o regexgen oferece e muito mais.
A filosofia deste projeto é gerar a expressão regular mais específica possível por padrão, que corresponda exatamente apenas à entrada fornecida e nada mais. Com o uso de sinalizadores de linha de comando (na ferramenta CLI) ou métodos de pré-processamento (na biblioteca), expressões mais generalizadas podem ser criadas.
As expressões produzidas são expressões regulares compatíveis com Perl que também são compatíveis com o analisador de expressões regulares na caixa regex do Rust. Outros analisadores de expressões regulares ou respectivas bibliotecas de outras linguagens de programação não foram testados até agora, mas também devem ser compatíveis.
Definitivamente, sim! Usando as configurações padrão, grex produz uma expressão regular que garante corresponder apenas aos casos de teste fornecidos como entrada e nada mais. Isto foi verificado por testes de propriedade. No entanto, se a conversão para classes de caracteres abreviados como w
estiver habilitada, a regex resultante corresponderá a um escopo muito mais amplo de casos de teste. O conhecimento sobre as consequências dessa conversão é essencial para encontrar uma expressão regular correta para o domínio do seu negócio.
grex usa um algoritmo que tenta encontrar o regex mais curto possível para os casos de teste fornecidos. Muitas vezes, porém, a expressão resultante ainda é mais longa ou mais complexa do que precisa ser. Nesses casos, uma regex mais compacta ou elegante só pode ser criada manualmente. Além disso, cada mecanismo de expressão regular possui diferentes otimizações integradas. grex não sabe nada sobre isso e, portanto, não pode otimizar suas expressões regulares para um mecanismo específico.
Então, aprenda a escrever expressões regulares! O melhor caso de uso atualmente para grex é encontrar um regex inicial correto que deve ser inspecionado manualmente se otimizações adicionais forem possíveis.
{min,max}
|
operador?
quantificador^
e $
Você pode baixar o executável independente para sua plataforma acima e colocá-lo em um local de sua escolha. Alternativamente, binários pré-compilados de 64 bits estão disponíveis nos gerenciadores de pacotes Scoop (para Windows), Homebrew (para macOS e Linux), MacPorts (para macOS) e Huber (para macOS, Linux e Windows). Raúl Piracés contribuiu com um pacote Chocolatey Windows.
grex também está hospedado em crates.io, o registro oficial de pacotes Rust. Se você é um desenvolvedor Rust e já tem o conjunto de ferramentas Rust instalado, você pode instalar compilando a partir do código-fonte usando cargo , o gerenciador de pacotes Rust. Portanto, o resumo de suas opções de instalação é:
( brew | cargo | choco | huber | port | scoop ) install grex
Para usar o grex como biblioteca, basta adicioná-lo como uma dependência ao seu arquivo Cargo.toml
:
[ dependencies ]
grex = { version = " 1.4.5 " , default-features = false }
O aplauso de dependência só é necessário para a ferramenta de linha de comando. Ao desabilitar os recursos padrão, o download e a compilação de clap são evitados para a biblioteca.
Explicações detalhadas das configurações disponíveis são fornecidas na seção da biblioteca. Todas as configurações podem ser combinadas livremente entre si.
Os casos de teste são passados diretamente ( grex abc
) ou de um arquivo ( grex -f test_cases.txt
). grex também é capaz de receber sua entrada de pipelines Unix, por exemplo, cat test_cases.txt | grex -
.
A tabela a seguir mostra todos os sinalizadores e opções disponíveis:
$ grex -h
grex 1.4.5
© 2019-today Peter M. Stahl
Licensed under the Apache License, Version 2.0
Downloadable from https://crates.io/crates/grex
Source code at https://github.com/pemistahl/grex
grex generates regular expressions from user-provided test cases.
Usage: grex [OPTIONS] {INPUT...|--file }
Input:
[INPUT]... One or more test cases separated by blank space
-f, --file Reads test cases on separate lines from a file
Digit Options:
-d, --digits Converts any Unicode decimal digit to d
-D, --non-digits Converts any character which is not a Unicode decimal digit to D
Whitespace Options:
-s, --spaces Converts any Unicode whitespace character to s
-S, --non-spaces Converts any character which is not a Unicode whitespace character to S
Word Options:
-w, --words Converts any Unicode word character to w
-W, --non-words Converts any character which is not a Unicode word character to W
Escaping Options:
-e, --escape Replaces all non-ASCII characters with unicode escape sequences
--with-surrogates Converts astral code points to surrogate pairs if --escape is set
Repetition Options:
-r, --repetitions
Detects repeated non-overlapping substrings and converts them to {min,max} quantifier
notation
--min-repetitions
Specifies the minimum quantity of substring repetitions to be converted if --repetitions
is set [default: 1]
--min-substring-length
Specifies the minimum length a repeated substring must have in order to be converted if
--repetitions is set [default: 1]
Anchor Options:
--no-start-anchor Removes the caret anchor `^` from the resulting regular expression
--no-end-anchor Removes the dollar sign anchor `$` from the resulting regular expression
--no-anchors Removes the caret and dollar sign anchors from the resulting regular
expression
Display Options:
-x, --verbose Produces a nicer-looking regular expression in verbose mode
-c, --colorize Provides syntax highlighting for the resulting regular expression
Miscellaneous Options:
-i, --ignore-case Performs case-insensitive matching, letters match both upper and lower case
-g, --capture-groups Replaces non-capturing groups with capturing ones
-h, --help Prints help information
-v, --version Prints version information
Os casos de teste são passados de uma coleção via RegExpBuilder::from()
ou de um arquivo via RegExpBuilder::from_file()
. Se for lido de um arquivo, cada caso de teste deverá estar em uma linha separada. As linhas podem ser finalizadas com uma nova linha n
ou um retorno de carro com um avanço de linha rn
.
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "a" , "aa" , "aaa" ] ) . build ( ) ;
assert_eq ! ( regexp , "^a(?:aa?)?$" ) ;
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "a" , "aa" , "123" ] )
. with_conversion_of_digits ( )
. with_conversion_of_words ( )
. build ( ) ;
assert_eq ! ( regexp , "^( \ d \ d \ d| \ w(?: \ w)?)$" ) ;
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "aa" , "bcbc" , "defdefdef" ] )
. with_conversion_of_repetitions ( )
. build ( ) ;
assert_eq ! ( regexp , "^(?:a{2}|(?:bc){2}|(?:def){3})$" ) ;
Por padrão, grex converte cada substring desta forma, que tem pelo menos um único caractere e que é subsequentemente repetida pelo menos uma vez. Você pode personalizar esses dois parâmetros, se desejar.
No exemplo a seguir, o caso de teste aa
não é convertido em a{2}
porque a substring repetida a
tem comprimento 1, mas o comprimento mínimo da substring foi definido como 2.
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "aa" , "bcbc" , "defdefdef" ] )
. with_conversion_of_repetitions ( )
. with_minimum_substring_length ( 2 )
. build ( ) ;
assert_eq ! ( regexp , "^(?:aa|(?:bc){2}|(?:def){3})$" ) ;
Definindo um número mínimo de 2 repetições no próximo exemplo, apenas o caso de teste defdefdef
será convertido por ser o único que se repete duas vezes.
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "aa" , "bcbc" , "defdefdef" ] )
. with_conversion_of_repetitions ( )
. with_minimum_repetitions ( 2 )
. build ( ) ;
assert_eq ! ( regexp , "^(?:bcbc|aa|(?:def){3})$" ) ;
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "You smell like ?." ] )
. with_escaping_of_non_ascii_chars ( false )
. build ( ) ;
assert_eq ! ( regexp , "^You smell like \ u{1f4a9} \ .$" ) ;
Versões antigas de JavaScript não suportam sequências de escape unicode para os planos de código astral (intervalo U+010000
a U+10FFFF
). Para suportar esses símbolos em expressões regulares JavaScript, é necessária a conversão para pares substitutos. Mais informações sobre esse assunto podem ser encontradas aqui.
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "You smell like ?." ] )
. with_escaped_non_ascii_chars ( true )
. build ( ) ;
assert_eq ! ( regexp , "^You smell like \ u{d83d} \ u{dca9} \ .$" ) ;
As expressões regulares que o grex gera diferenciam maiúsculas de minúsculas por padrão. A correspondência sem distinção entre maiúsculas e minúsculas pode ser habilitada da seguinte forma:
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "big" , "BIGGER" ] )
. with_case_insensitive_matching ( )
. build ( ) ;
assert_eq ! ( regexp , "(?i)^big(?:ger)?$" ) ;
Grupos sem captura são usados por padrão. Estendendo o exemplo anterior, você pode mudar para a captura de grupos.
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "big" , "BIGGER" ] )
. with_case_insensitive_matching ( )
. with_capturing_groups ( )
. build ( ) ;
assert_eq ! ( regexp , "(?i)^big(ger)?$" ) ;
Se você achar difícil ler a expressão regular gerada, poderá ativar o modo detalhado. A expressão é então colocada em múltiplas linhas e recuada para torná-la mais agradável aos olhos.
use grex :: RegExpBuilder ;
use indoc :: indoc ;
let regexp = RegExpBuilder :: from ( & [ "a" , "b" , "bcd" ] )
. with_verbose_mode ( )
. build ( ) ;
assert_eq ! ( regexp , indoc! (
r#"
(?x)
^
(?:
b
(?:
cd
)?
|
a
)
$"#
) ) ;
Por padrão, as âncoras ^
e $
são colocadas em torno de cada expressão regular gerada para garantir que correspondam apenas aos casos de teste fornecidos como entrada. Muitas vezes, contudo, deseja-se utilizar o padrão gerado como parte de um padrão maior. Para isso, as âncoras podem ser desativadas, separadamente ou ambas.
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "a" , "aa" , "aaa" ] )
. without_anchors ( )
. build ( ) ;
assert_eq ! ( regexp , "a(?:aa?)?" ) ;
Os exemplos a seguir mostram os vários recursos de sintaxe regex suportados:
$ grex a b c
^[a-c]$
$ grex a c d e f
^[ac-f]$
$ grex a b x de
^( ? :de | [abx])$
$ grex abc bc
^a ? bc$
$ grex a b bc
^( ? :bc ? | a)$
$ grex [a-z]
^ [ a - z ] $
$ grex -r b ba baa baaa
^b( ? :a{1,3}) ? $
$ grex -r b ba baa baaaa
^b( ? :a{1,2} | a{4}) ? $
$ grex y̆ a z
^( ? :y̆ | [az])$
Note:
Grapheme y̆ consists of two Unicode symbols:
U+0079 (Latin Small Letter Y)
U+0306 (Combining Breve)
$ grex " I ♥ cake " " I ♥ cookies "
^I ♥ c( ? :ookies | ake)$
Note:
Input containing blank space must be
surrounded by quotation marks.
A string "I ♥♥♥ 36 and ٣ and ??."
serve como entrada para os seguintes exemplos usando a notação de linha de comando:
$ grex < INPUT >
^I ♥♥♥ 36 and ٣ and ?? . $
$ grex -e < INPUT >
^I u {2665} u {2665} u {2665} 36 and u {663} and u {1f4a9} u {1f4a9} . $
$ grex -e --with-surrogates < INPUT >
^I u {2665} u {2665} u {2665} 36 and u {663} and u {d83d} u {dca9} u {d83d} u {dca9} . $
$ grex -d < INPUT >
^I ♥♥♥ dd and d and ?? . $
$ grex -s < INPUT >
^I s ♥♥♥ s 36 s and s ٣ s and s ?? . $
$ grex -w < INPUT >
^ w ♥♥♥ ww www w www ?? . $
$ grex -D < INPUT >
^ DDDDDD 36 DDDDD ٣ DDDDDDDD $
$ grex -S < INPUT >
^ S SSS SS SSS S SSS SSS $
$ grex -dsw < INPUT >
^ ws ♥♥♥ sddswwwsdswwws ?? . $
$ grex -dswW < INPUT >
^ wsWWWsddswwwsdswwwsWWW $
$ grex -r < INPUT >
^I ♥{3} 36 and ٣ and ?{2} . $
$ grex -er < INPUT >
^I u {2665}{3} 36 and u {663} and u {1f4a9}{2} . $
$ grex -er --with-surrogates < INPUT >
^I u {2665}{3} 36 and u {663} and ( ? : u {d83d} u {dca9}){2} . $
$ grex -dgr < INPUT >
^I ♥{3} d ( d and ){2}?{2} . $
$ grex -rs < INPUT >
^I s ♥{3} s 36 s and s ٣ s and s ?{2} . $
$ grex -rw < INPUT >
^ w ♥{3} w ( ? : w w {3} ){2}?{2} . $
$ grex -Dr < INPUT >
^ D {6}36 D {5}٣ D {8}$
$ grex -rS < INPUT >
^ S S ( ? : S {2} ){2} S {3} S S {3} S {3}$
$ grex -rW < INPUT >
^I W {5}36 W and W ٣ W and W {4}$
$ grex -drsw < INPUT >
^ ws ♥{3} sd ( ? : dsw {3} s ){2}?{2} . $
$ grex -drswW < INPUT >
^ wsW {3} sd ( ? : dsw {3} s ){2} W {3}$
Para construir o código-fonte você mesmo, você precisa do conjunto de ferramentas Rust estável instalado em sua máquina para que cargo , o gerenciador de pacotes Rust, esteja disponível. Observação : Rust >= 1.70.0 é necessário para construir a CLI. Para a parte da biblioteca, Rust <1.70.0 é suficiente.
git clone https://github.com/pemistahl/grex.git
cd grex
cargo build
O código-fonte é acompanhado por um extenso conjunto de testes que consiste em testes unitários, testes de integração e testes de propriedades. Para executá-los, basta dizer:
cargo test
Os benchmarks que medem o desempenho de diversas configurações podem ser executados com:
cargo bench
Com a ajuda de PyO3 e Maturin, a biblioteca foi compilada em um módulo de extensão Python para que também possa ser usada em qualquer software Python. Ele está disponível no Python Package Index e pode ser instalado com:
pip install grex
Para construir você mesmo o módulo de extensão Python, crie um ambiente virtual e instale o Maturin.
python -m venv /path/to/virtual/environment
source /path/to/virtual/environment/bin/activate
pip install maturin
maturin build
A biblioteca Python contém uma única classe chamada RegExpBuilder
que pode ser importada da seguinte forma:
from grex import RegExpBuilder
Esta biblioteca pode ser compilada para WebAssembly (WASM) que permite usar grex em qualquer projeto baseado em JavaScript, seja no navegador ou no back end rodando em Node.js.
A maneira mais fácil de compilar é usar wasm-pack
. Após a instalação, você pode, por exemplo, construir a biblioteca com o web target para que ela possa ser usada diretamente no navegador:
wasm-pack build --target web
Isso cria um diretório chamado pkg
no nível superior deste repositório, contendo os arquivos wasm compilados e ligações JavaScript e TypeScript. Em um arquivo HTML, você pode chamar grex da seguinte maneira, por exemplo:
< script type =" module " >
import init , { RegExpBuilder } from "./pkg/grex.js" ;
init ( ) . then ( _ => {
alert ( RegExpBuilder . from ( [ "hello" , "world" ] ) . build ( ) ) ;
} ) ;
script >
Existem também alguns testes de integração disponíveis tanto para Node.js quanto para os navegadores Chrome, Firefox e Safari. Para executá-los, basta dizer:
wasm-pack test --node --headless --chrome --firefox --safari
Se os testes não iniciarem no Safari, você precisará primeiro ativar o driver web do Safari executando:
sudo safaridriver --enable
A saída do wasm-pack
será hospedada em um repositório separado que permite adicionar mais configurações, testes e documentação relacionados ao JavaScript. grex também será adicionado ao registro npm, permitindo um download e instalação fáceis em cada projeto JavaScript ou TypeScript.
Existe um site de demonstração disponível onde você pode experimentar o grex.
Um autômato finito determinístico (DFA) é criado a partir das strings de entrada.
O número de estados e transições entre estados no DFA é reduzido aplicando o algoritmo de minimização DFA de Hopcroft.
O AFD minimizado é expresso como um sistema de equações lineares que são resolvidas com o método algébrico de Brzozowski, resultando na expressão regular final.
Dê uma olhada nas questões planejadas.
Caso você queira contribuir com algo para o grex , encorajo-o a fazê-lo. Você tem ideias para recursos interessantes? Ou você encontrou algum bug até agora? Sinta-se à vontade para abrir um problema ou enviar uma solicitação pull. É muito apreciado. :-)