grex เป็นไลบรารีรวมทั้งยูทิลิตีบรรทัดคำสั่งที่มีจุดมุ่งหมายเพื่อลดความซับซ้อนและน่าเบื่อของการสร้างนิพจน์ทั่วไป โดยสร้างนิพจน์ทั่วไปรายการเดียวโดยอัตโนมัติจากกรณีทดสอบที่ผู้ใช้จัดเตรียมไว้ รับประกันว่านิพจน์ผลลัพธ์จะตรงกับกรณีทดสอบที่สร้างขึ้น
โปรเจ็กต์นี้เริ่มต้นเป็นพอร์ต Rust ของ regexgen เครื่องมือ JavaScript ที่เขียนโดย Devon Govett แม้ว่าจะสามารถเพิ่มคุณสมบัติที่มีประโยชน์เพิ่มเติมได้มากมาย แต่การพัฒนาก็ดูเหมือนจะหยุดลงเมื่อหลายปีก่อน ขณะนี้มีแผนจะเพิ่มคุณสมบัติใหม่เหล่านี้ให้กับ grex เนื่องจาก Rust โดดเด่นมากเมื่อพูดถึงเครื่องมือบรรทัดคำสั่ง grex นำเสนอฟีเจอร์ทั้งหมดที่ regexgen มอบให้และอีกมากมาย
ปรัชญาของโปรเจ็กต์นี้คือการสร้างนิพจน์ทั่วไปที่เฉพาะเจาะจงมากที่สุดเท่าที่จะเป็นไปได้ตามค่าเริ่มต้น ซึ่งตรงกับอินพุตที่กำหนดเท่านั้น และไม่มีอะไรอื่นอีก ด้วยการใช้แฟล็กบรรทัดคำสั่ง (ในเครื่องมือ CLI) หรือวิธีการประมวลผลล่วงหน้า (ในไลบรารี) คุณสามารถสร้างนิพจน์ทั่วไปได้มากขึ้น
นิพจน์ที่สร้างขึ้นนั้นเป็นนิพจน์ทั่วไปที่เข้ากันได้กับ Perl ซึ่งเข้ากันได้กับตัวแยกวิเคราะห์นิพจน์ทั่วไปในลัง regex ของ Rust ตัวแยกวิเคราะห์นิพจน์ทั่วไปอื่น ๆ หรือไลบรารีที่เกี่ยวข้องจากภาษาการเขียนโปรแกรมอื่นยังไม่ได้รับการทดสอบ แต่ส่วนใหญ่ควรจะเข้ากันได้เช่นกัน
แน่นอน ใช่แล้ว! เมื่อใช้การตั้งค่ามาตรฐาน grex จะสร้างนิพจน์ทั่วไปที่รับประกันว่าจะจับคู่เฉพาะกรณีทดสอบที่กำหนดเป็นอินพุตเท่านั้น และไม่มีอะไรอื่นอีก สิ่งนี้ได้รับการตรวจสอบโดยการทดสอบคุณสมบัติ อย่างไรก็ตาม หากเปิดใช้งานการแปลงเป็นคลาสอักขระชวเลข เช่น w
ผลลัพธ์ regex จะตรงกับขอบเขตของกรณีทดสอบที่กว้างกว่ามาก ความรู้เกี่ยวกับผลที่ตามมาของการแปลงนี้เป็นสิ่งจำเป็นสำหรับการค้นหานิพจน์ทั่วไปที่ถูกต้องสำหรับโดเมนธุรกิจของคุณ
grex ใช้อัลกอริทึมที่พยายามค้นหา regex ที่สั้นที่สุดที่เป็นไปได้สำหรับกรณีทดสอบที่กำหนด บ่อยครั้งมากที่นิพจน์ผลลัพธ์ยังคงยาวหรือซับซ้อนเกินกว่าที่จำเป็น ในกรณีเช่นนี้ คุณจะสร้างนิพจน์ทั่วไปที่มีขนาดกะทัดรัดหรือสวยงามได้ด้วยมือเท่านั้น นอกจากนี้ เอ็นจิ้นนิพจน์ทั่วไปทุกตัวยังมีการปรับให้เหมาะสมในตัวที่แตกต่างกัน grex ไม่รู้อะไรเกี่ยวกับสิ่งเหล่านั้นดังนั้นจึงไม่สามารถเพิ่มประสิทธิภาพ regexes สำหรับเอ็นจิ้นเฉพาะได้
ดังนั้นโปรดเรียนรู้วิธีการเขียนนิพจน์ทั่วไป! กรณีการใช้งานที่ดีที่สุดในปัจจุบันสำหรับ grex คือการค้นหา regex ที่ถูกต้องเริ่มต้นซึ่งควรตรวจสอบด้วยตนเองหากสามารถปรับให้เหมาะสมเพิ่มเติมได้
{min,max}
|
ตัวดำเนินการ?
ปริมาณ^
และ $
คุณสามารถดาวน์โหลดไฟล์ปฏิบัติการที่มีอยู่ในตัวเองสำหรับแพลตฟอร์มของคุณด้านบนและวางไว้ในตำแหน่งที่คุณเลือก อีกทางหนึ่ง ไบนารี 64 บิตที่คอมไพล์ไว้ล่วงหน้ามีอยู่ในตัวจัดการแพ็คเกจ Scoop (สำหรับ Windows), Homebrew (สำหรับ macOS และ Linux), MacPorts (สำหรับ macOS) และ Huber (สำหรับ macOS, Linux และ Windows) Raúl Piracés ได้บริจาคแพ็คเกจ Chocolatey Windows
grex ยังโฮสต์อยู่บน crates.io ซึ่งเป็นรีจิสทรีแพ็คเกจ Rust อย่างเป็นทางการ หากคุณเป็นนักพัฒนา Rust และติดตั้ง Toolchain Rust ไว้แล้ว คุณสามารถติดตั้งโดยการคอมไพล์จากแหล่งที่มาโดยใช้ cargo ซึ่งเป็นตัวจัดการแพ็คเกจ Rust สรุปตัวเลือกการติดตั้งของคุณคือ:
( brew | cargo | choco | huber | port | scoop ) install grex
หากต้องการใช้ grex เป็นไลบรารี เพียงเพิ่มเป็นการพึ่งพาไฟล์ Cargo.toml
ของคุณ:
[ dependencies ]
grex = { version = " 1.4.5 " , default-features = false }
การตบมือ การพึ่งพาจำเป็นสำหรับเครื่องมือบรรทัดคำสั่งเท่านั้น ด้วยการปิดการใช้งานคุณสมบัติเริ่มต้น การดาวน์โหลดและการรวบรวม clap จะถูกป้องกันสำหรับไลบรารี
คำอธิบายโดยละเอียดของการตั้งค่าที่มีให้ไว้ในส่วนห้องสมุด การตั้งค่าทั้งหมดสามารถรวมเข้าด้วยกันได้อย่างอิสระ
กรณีทดสอบจะถูกส่งโดยตรง ( grex abc
) หรือจากไฟล์ ( grex -f test_cases.txt
) grex สามารถรับอินพุตจากไปป์ไลน์ Unix ได้เช่นกัน เช่น cat test_cases.txt | grex -
.
ตารางต่อไปนี้แสดงแฟล็กและตัวเลือกที่มีอยู่ทั้งหมด:
$ 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
กรณีทดสอบจะถูกส่งผ่านจากคอลเลกชันผ่าน RegExpBuilder::from()
หรือจากไฟล์ผ่าน RegExpBuilder::from_file()
หากอ่านจากไฟล์ แต่ละกรณีการทดสอบจะต้องอยู่ในบรรทัดแยกกัน บรรทัดอาจลงท้ายด้วยการขึ้นบรรทัดใหม่ n
หรือขึ้นบรรทัดใหม่ด้วยการขึ้นบรรทัดใหม่ 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})$" ) ;
ตามค่าเริ่มต้น grex จะแปลงแต่ละสตริงย่อยด้วยวิธีนี้ ซึ่งมีความยาวอย่างน้อยหนึ่งอักขระและทำซ้ำอย่างน้อยหนึ่งครั้งในภายหลัง คุณสามารถปรับแต่งพารามิเตอร์ทั้งสองนี้ได้หากต้องการ
ในตัวอย่างต่อไปนี้ กรณีทดสอบ aa
จะไม่ถูกแปลงเป็น a{2}
เนื่องจากสตริงย่อย a
ที่ซ้ำกันมีความยาว 1 แต่ความยาวสตริงย่อยต่ำสุดถูกกำหนดไว้ที่ 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})$" ) ;
การตั้งค่าจำนวนการทำซ้ำขั้นต่ำ 2 ครั้งในตัวอย่างถัดไป เฉพาะกรณีทดสอบ defdefdef
เท่านั้นที่จะถูกแปลง เนื่องจากเป็นเพียงรายการเดียวที่ทำซ้ำสองครั้ง
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} \ .$" ) ;
JavaScript เวอร์ชันเก่าไม่รองรับลำดับหลีกยูนิโค้ดสำหรับระนาบโค้ดดาว (ช่วง U+010000
ถึง U+10FFFF
) เพื่อที่จะสนับสนุนสัญลักษณ์เหล่านี้ในนิพจน์ทั่วไปของ JavaScript จำเป็นต้องแปลงเป็นคู่ตัวแทน ข้อมูลเพิ่มเติมเกี่ยวกับเรื่องดังกล่าวสามารถพบได้ที่นี่
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} \ .$" ) ;
นิพจน์ทั่วไปที่ grex สร้างขึ้นจะคำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่โดยค่าเริ่มต้น สามารถเปิดใช้งานการจับคู่ที่ไม่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ได้ดังนี้:
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "big" , "BIGGER" ] )
. with_case_insensitive_matching ( )
. build ( ) ;
assert_eq ! ( regexp , "(?i)^big(?:ger)?$" ) ;
กลุ่มที่ไม่ได้จับภาพจะถูกใช้ตามค่าเริ่มต้น จากตัวอย่างก่อนหน้านี้ คุณสามารถสลับไปใช้การจับกลุ่มแทนได้
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "big" , "BIGGER" ] )
. with_case_insensitive_matching ( )
. with_capturing_groups ( )
. build ( ) ;
assert_eq ! ( regexp , "(?i)^big(ger)?$" ) ;
หากคุณพบว่านิพจน์ทั่วไปที่สร้างขึ้นอ่านยาก คุณสามารถเปิดใช้งานโหมดรายละเอียดได้ จากนั้นจึงใส่นิพจน์หลายบรรทัดและเยื้องเพื่อให้ดูน่ามองยิ่งขึ้น
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
)
$"#
) ) ;
ตามค่าเริ่มต้น แองเคอร์ ^
และ $
จะถูกใส่รอบๆ ทุกนิพจน์ทั่วไปที่สร้างขึ้น เพื่อให้แน่ใจว่าจะตรงกับกรณีทดสอบที่กำหนดเป็นอินพุตเท่านั้น อย่างไรก็ตาม บ่อยครั้งที่ต้องการใช้รูปแบบที่สร้างขึ้นเป็นส่วนหนึ่งของรูปแบบที่ใหญ่กว่า เพื่อจุดประสงค์นี้ สามารถปิดใช้งานจุดยึดได้ ไม่ว่าจะแยกกันหรือทั้งสองอย่างก็ได้
use grex :: RegExpBuilder ;
let regexp = RegExpBuilder :: from ( & [ "a" , "aa" , "aaa" ] )
. without_anchors ( )
. build ( ) ;
assert_eq ! ( regexp , "a(?:aa?)?" ) ;
ตัวอย่างต่อไปนี้แสดงฟีเจอร์ไวยากรณ์ regex ที่รองรับต่างๆ:
$ 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.
สตริง "I ♥♥♥ 36 and ٣ and ??."
ทำหน้าที่เป็นอินพุตสำหรับตัวอย่างต่อไปนี้โดยใช้สัญลักษณ์บรรทัดคำสั่ง:
$ 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}$
ในการสร้างซอร์สโค้ดด้วยตัวเอง คุณต้องติดตั้ง Rust toolchain ที่เสถียรบนเครื่องของคุณ เพื่อให้ cargo , Rust package manager พร้อมใช้งาน โปรดทราบ : ต้องใช้ Rust >= 1.70.0 เพื่อสร้าง CLI สำหรับส่วนของไลบรารี Rust < 1.70.0 ก็เพียงพอแล้ว
git clone https://github.com/pemistahl/grex.git
cd grex
cargo build
ซอร์สโค้ดมาพร้อมกับชุดทดสอบที่ครอบคลุมซึ่งประกอบด้วยการทดสอบหน่วย การทดสอบการรวม และการทดสอบคุณสมบัติ หากต้องการเรียกใช้ เพียงพูดว่า:
cargo test
เกณฑ์มาตรฐานที่วัดประสิทธิภาพของการตั้งค่าต่างๆ สามารถทำได้ด้วย:
cargo bench
ด้วยความช่วยเหลือของ PyO3 และ Maturin ไลบรารี่ได้รับการคอมไพล์เป็นโมดูลส่วนขยายของ Python เพื่อให้สามารถใช้งานภายในซอฟต์แวร์ Python ใดก็ได้เช่นกัน มีอยู่ใน Python Package Index และสามารถติดตั้งได้กับ:
pip install grex
หากต้องการสร้างโมดูลส่วนขยาย Python ด้วยตัวเอง ให้สร้างสภาพแวดล้อมเสมือนและติดตั้ง Maturin
python -m venv /path/to/virtual/environment
source /path/to/virtual/environment/bin/activate
pip install maturin
maturin build
ไลบรารี Python มีคลาสเดียวชื่อ RegExpBuilder
ซึ่งสามารถนำเข้าได้ดังนี้:
from grex import RegExpBuilder
ไลบรารีนี้สามารถคอมไพล์เป็น WebAssembly (WASM) ซึ่งอนุญาตให้ใช้ grex ในโปรเจ็กต์ที่ใช้ JavaScript ไม่ว่าจะเป็นในเบราว์เซอร์หรือในส่วนหลังที่ทำงานบน Node.js
วิธีที่ง่ายที่สุดในการคอมไพล์คือการใช้ wasm-pack
หลังการติดตั้ง คุณสามารถสร้างไลบรารี่ด้วยเป้าหมายเว็บเพื่อให้สามารถใช้งานได้โดยตรงในเบราว์เซอร์:
wasm-pack build --target web
ซึ่งจะสร้างไดเร็กทอรีชื่อ pkg
ที่ระดับบนสุดของที่เก็บนี้ ซึ่งมีไฟล์ wasm ที่คอมไพล์แล้ว และการโยง JavaScript และ TypeScript ในไฟล์ HTML คุณสามารถเรียก grex ได้ดังต่อไปนี้ เช่น:
< script type =" module " >
import init , { RegExpBuilder } from "./pkg/grex.js" ;
init ( ) . then ( _ => {
alert ( RegExpBuilder . from ( [ "hello" , "world" ] ) . build ( ) ) ;
} ) ;
script >
นอกจากนี้ยังมีการทดสอบการรวมบางส่วนที่ใช้ได้ทั้งสำหรับ Node.js และสำหรับเบราว์เซอร์ Chrome, Firefox และ Safari หากต้องการเรียกใช้งาน เพียงพูดว่า:
wasm-pack test --node --headless --chrome --firefox --safari
หากการทดสอบล้มเหลวในการเริ่มใน Safari คุณต้องเปิดใช้งานไดรเวอร์เว็บของ Safari ก่อนโดยเรียกใช้:
sudo safaridriver --enable
ผลลัพธ์ของ wasm-pack
จะถูกโฮสต์ในพื้นที่เก็บข้อมูลแยกต่างหาก ซึ่งอนุญาตให้เพิ่มการกำหนดค่า การทดสอบ และเอกสารประกอบที่เกี่ยวข้องกับ JavaScript เพิ่มเติม จากนั้น grex จะถูกเพิ่มลงในรีจิสทรี npm เช่นกัน ช่วยให้ดาวน์โหลดและติดตั้งได้ง่ายภายในทุกโครงการ JavaScript หรือ TypeScript
มีเว็บไซต์สาธิตที่คุณสามารถทดลองใช้ grex ได้
กลไกจำกัดที่กำหนดขึ้นเอง (DFA) ถูกสร้างขึ้นจากสตริงอินพุต
จำนวนสถานะและการเปลี่ยนระหว่างรัฐใน DFA จะลดลงโดยการใช้อัลกอริทึมการย่อ DFA ของ Hopcroft
DFA ที่ย่อเล็กสุดจะแสดงเป็นระบบสมการเชิงเส้นซึ่งแก้ไขด้วยวิธีพีชคณิตของ Brzozowski ซึ่งส่งผลให้เกิดนิพจน์ทั่วไปขั้นสุดท้าย
พิจารณาประเด็นที่วางแผนไว้
ในกรณีที่คุณต้องการบริจาคบางอย่างให้กับ grex ฉันขอแนะนำให้คุณทำเช่นนั้น คุณมีไอเดียสำหรับคุณสมบัติเจ๋ง ๆ หรือไม่? หรือคุณพบข้อบกพร่องใด ๆ จนถึงตอนนี้? อย่าลังเลที่จะเปิดประเด็นหรือส่งคำขอดึง เป็นที่ชื่นชมอย่างมาก -