grex es una biblioteca y una utilidad de línea de comandos destinada a simplificar la tarea, a menudo complicada y tediosa, de crear expresiones regulares. Lo hace generando automáticamente una única expresión regular a partir de casos de prueba proporcionados por el usuario. Se garantiza que la expresión resultante coincidirá con los casos de prueba a partir de los cuales se generó.
Este proyecto comenzó como una adaptación de Rust de la herramienta JavaScript regexgen escrita por Devon Govett. Aunque se le podrían añadir muchas funciones útiles, su desarrollo aparentemente se detuvo hace varios años. El plan ahora es agregar estas nuevas funciones a grex, ya que Rust realmente brilla cuando se trata de herramientas de línea de comandos. grex ofrece todas las funciones que proporciona regexgen y más.
La filosofía de este proyecto es generar la expresión regular más específica posible de forma predeterminada que coincida exactamente con la entrada dada y nada más. Con el uso de indicadores de línea de comandos (en la herramienta CLI) o métodos de preprocesamiento (en la biblioteca), se pueden crear expresiones más generalizadas.
Las expresiones producidas son expresiones regulares compatibles con Perl que también son compatibles con el analizador de expresiones regulares en la caja de expresiones regulares de Rust. Hasta el momento no se han probado otros analizadores de expresiones regulares o bibliotecas respectivas de otros lenguajes de programación, pero también deberían ser en su mayoría compatibles.
¡Definitivamente sí! Usando la configuración estándar, grex produce una expresión regular que garantiza que coincidirá solo con los casos de prueba proporcionados como entrada y nada más. Esto ha sido verificado mediante pruebas de propiedad. Sin embargo, si se habilita la conversión a clases de caracteres abreviados como w
, la expresión regular resultante coincide con un alcance mucho más amplio de casos de prueba. El conocimiento de las consecuencias de esta conversión es esencial para encontrar una expresión regular correcta para su dominio empresarial.
grex utiliza un algoritmo que intenta encontrar la expresión regular más corta posible para los casos de prueba dados. Sin embargo, muy a menudo la expresión resultante es aún más larga o más compleja de lo necesario. En tales casos, una expresión regular más compacta o elegante sólo se puede crear a mano. Además, cada motor de expresiones regulares tiene diferentes optimizaciones integradas. grex no sabe nada sobre ellos y por lo tanto no puede optimizar sus expresiones regulares para un motor específico.
Entonces, ¡aprenda a escribir expresiones regulares! El mejor caso de uso actual para grex es encontrar una expresión regular inicial correcta que debe inspeccionarse manualmente si es posible realizar más optimizaciones.
{min,max}
|
operador?
cuantificador^
y $
Puede descargar el ejecutable independiente para su plataforma arriba y colocarlo en el lugar que elija. Alternativamente, los archivos binarios precompilados de 64 bits están disponibles en los administradores de paquetes Scoop (para Windows), Homebrew (para macOS y Linux), MacPorts (para macOS) y Huber (para macOS, Linux y Windows). Raúl Piracés ha contribuido con un paquete Chocolatey Windows.
grex también está alojado en crates.io, el registro oficial de paquetes de Rust. Si es un desarrollador de Rust y ya tiene instalada la cadena de herramientas de Rust, puede instalarla compilando desde el código fuente usando cargo , el administrador de paquetes de Rust. Entonces el resumen de sus opciones de instalación es:
( brew | cargo | choco | huber | port | scoop ) install grex
Para usar grex como biblioteca, simplemente agréguelo como una dependencia a su archivo Cargo.toml
:
[ dependencies ]
grex = { version = " 1.4.5 " , default-features = false }
El aplauso de dependencia solo es necesario para la herramienta de línea de comandos. Al deshabilitar las funciones predeterminadas, se evita la descarga y compilación de clap para la biblioteca.
Se proporcionan explicaciones detalladas de las configuraciones disponibles en la sección de biblioteca. Todos los ajustes se pueden combinar libremente entre sí.
Los casos de prueba se pasan directamente ( grex abc
) o desde un archivo ( grex -f test_cases.txt
). grex también puede recibir información de canales Unix, por ejemplo, cat test_cases.txt | grex -
.
La siguiente tabla muestra todas las banderas y opciones disponibles:
$ 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
Los casos de prueba se pasan desde una colección mediante RegExpBuilder::from()
o desde un archivo mediante RegExpBuilder::from_file()
. Si se lee desde un archivo, cada caso de prueba debe estar en una línea separada. Las líneas pueden terminar con una nueva línea n
o un retorno de carro con un salto de línea 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})$" ) ;
De forma predeterminada, grex convierte cada subcadena de esta manera, que tiene al menos un carácter de longitud y que posteriormente se repite al menos una vez. Puede personalizar estos dos parámetros si lo desea.
En el siguiente ejemplo, el caso de prueba aa
no se convierte en a{2}
porque la subcadena repetida a
tiene una longitud de 1, pero la longitud mínima de la subcadena se ha establecido en 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})$" ) ;
Estableciendo un número mínimo de 2 repeticiones en el siguiente ejemplo, solo se convertirá el caso de prueba defdefdef
porque es el único que se repite dos veces.
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} \ .$" ) ;
Las versiones antiguas de JavaScript no admiten secuencias de escape Unicode para los planos del código astral (rango U+010000
a U+10FFFF
). Para admitir estos símbolos en expresiones regulares de JavaScript, es necesaria la conversión a pares sustitutos. Puede encontrar más información al respecto aquí.
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} \ .$" ) ;
Las expresiones regulares que genera grex distinguen entre mayúsculas y minúsculas de forma predeterminada. La coincidencia que no distingue entre mayúsculas y minúsculas se puede habilitar de esta manera:
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "big" , "BIGGER" ] )
. with_case_insensitive_matching ( )
. build ( ) ;
assert_eq ! ( regexp , "(?i)^big(?:ger)?$" ) ;
Los grupos que no capturan se utilizan de forma predeterminada. Ampliando el ejemplo anterior, puede cambiar a capturar grupos.
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "big" , "BIGGER" ] )
. with_case_insensitive_matching ( )
. with_capturing_groups ( )
. build ( ) ;
assert_eq ! ( regexp , "(?i)^big(ger)?$" ) ;
Si encuentra difícil leer la expresión regular generada, puede habilitar el modo detallado. Luego, la expresión se coloca en varias líneas y se sangra para que sea más agradable a la vista.
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
)
$"#
) ) ;
De forma predeterminada, los anclajes ^
y $
se colocan alrededor de cada expresión regular generada para garantizar que coincida solo con los casos de prueba proporcionados como entrada. Sin embargo, con bastante frecuencia se desea utilizar el patrón generado como parte de uno más grande. Para ello se pueden desactivar los anclajes, ya sea por separado o ambos.
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "a" , "aa" , "aaa" ] )
. without_anchors ( )
. build ( ) ;
assert_eq ! ( regexp , "a(?:aa?)?" ) ;
Los siguientes ejemplos muestran las diversas funciones de sintaxis de expresiones regulares admitidas:
$ 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.
La cadena "I ♥♥♥ 36 and ٣ and ??."
sirve como entrada para los siguientes ejemplos usando la notación de línea de comandos:
$ 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 crear el código fuente usted mismo, necesita la cadena de herramientas estable de Rust instalada en su máquina para que cargo , el administrador de paquetes de Rust, esté disponible. Tenga en cuenta : se requiere Rust >= 1.70.0 para construir la CLI. Para la parte de la biblioteca, Rust < 1.70.0 es suficiente.
git clone https://github.com/pemistahl/grex.git
cd grex
cargo build
El código fuente va acompañado de un extenso conjunto de pruebas que consta de pruebas unitarias, pruebas de integración y pruebas de propiedades. Para ejecutarlos, simplemente diga:
cargo test
Los puntos de referencia que miden el rendimiento de varias configuraciones se pueden ejecutar con:
cargo bench
Con la ayuda de PyO3 y Maturin, la biblioteca se compiló en un módulo de extensión de Python para que también pueda usarse en cualquier software de Python. Está disponible en el índice de paquetes de Python y se puede instalar con:
pip install grex
Para crear usted mismo el módulo de extensión de Python, cree un entorno virtual e instale Maturin.
python -m venv /path/to/virtual/environment
source /path/to/virtual/environment/bin/activate
pip install maturin
maturin build
La biblioteca de Python contiene una única clase llamada RegExpBuilder
que se puede importar así:
from grex import RegExpBuilder
Esta biblioteca se puede compilar en WebAssembly (WASM), lo que permite usar grex en cualquier proyecto basado en JavaScript, ya sea en el navegador o en el back-end que se ejecuta en Node.js.
La forma más sencilla de compilar es utilizar wasm-pack
. Después de la instalación, puede, por ejemplo, crear la biblioteca con el destino web para que pueda usarse directamente en el navegador:
wasm-pack build --target web
Esto crea un directorio llamado pkg
en el nivel superior de este repositorio, que contiene los archivos wasm compilados y los enlaces de JavaScript y TypeScript. En un archivo HTML, puedes llamar a grex de la siguiente manera, por ejemplo:
< script type =" module " >
import init , { RegExpBuilder } from "./pkg/grex.js" ;
init ( ) . then ( _ => {
alert ( RegExpBuilder . from ( [ "hello" , "world" ] ) . build ( ) ) ;
} ) ;
script >
También hay algunas pruebas de integración disponibles tanto para Node.js como para los navegadores Chrome, Firefox y Safari. Para ejecutarlos, simplemente diga:
wasm-pack test --node --headless --chrome --firefox --safari
Si las pruebas no se inician en Safari, primero debe habilitar el controlador web de Safari ejecutando:
sudo safaridriver --enable
La salida de wasm-pack
se alojará en un repositorio separado que permitirá agregar más configuraciones, pruebas y documentación relacionadas con JavaScript. Luego, grex también se agregará al registro npm, lo que permitirá una fácil descarga e instalación dentro de cada proyecto JavaScript o TypeScript.
Hay un sitio web de demostración disponible donde puedes probar grex.
Se crea un autómata finito determinista (DFA) a partir de las cadenas de entrada.
El número de estados y transiciones entre estados en el DFA se reduce aplicando el algoritmo de minimización de DFA de Hopcroft.
El DFA minimizado se expresa como un sistema de ecuaciones lineales que se resuelven con el método algebraico de Brzozowski, dando como resultado la expresión regular final.
Eche un vistazo a las emisiones previstas.
En caso de que quieras aportar algo a grex , te animo a que lo hagas. ¿Tienes ideas para funciones interesantes? ¿O has encontrado algún error hasta ahora? No dudes en abrir una incidencia o enviar una solicitud de extracción. Es muy apreciado. :-)