Skip to main content

char_classes/
char_classes.rs

1//! # Character Classes
2//!
3//! Demonstrates parsing `[...]` character class expressions including ranges,
4//! negation, escape shorthands inside brackets, and mixed items.
5//!
6//! Run with:
7//!   cargo run -p re-parser --example char_classes
8
9use re_parser::ast::{CharClassItem, EscapeClass, Regex};
10use re_parser::parse;
11
12fn describe_item(item: &CharClassItem) -> String {
13    match item {
14        CharClassItem::Literal(c) => format!("literal({c:?})"),
15        CharClassItem::Range(lo, hi) => format!("range({lo:?}..={hi:?})"),
16        CharClassItem::EscapeClass(ec) => {
17            let name = match ec {
18                EscapeClass::Digit => r"\d",
19                EscapeClass::NonDigit => r"\D",
20                EscapeClass::Word => r"\w",
21                EscapeClass::NonWord => r"\W",
22                EscapeClass::Space => r"\s",
23                EscapeClass::NonSpace => r"\S",
24            };
25            format!("escape({name})")
26        }
27    }
28}
29
30fn print_class(pattern: &str) {
31    let ast = parse(pattern).unwrap();
32    match &ast {
33        Regex::CharClass(cls) => {
34            let negated = if cls.negated { "negated, " } else { "" };
35            let items: Vec<_> = cls.items.iter().map(describe_item).collect();
36            println!("  {pattern:15}  =>  [{negated}{}]", items.join(", "));
37        }
38        other => println!("  {pattern:15}  =>  {other:?}"),
39    }
40}
41
42fn main() {
43    println!("=== Literal sets ===");
44    print_class("[abc]");
45    print_class("[aeiou]");
46
47    println!("\n=== Negated classes ===");
48    print_class("[^abc]");
49    print_class("[^0-9]");
50
51    println!("\n=== Character ranges ===");
52    print_class("[a-z]");
53    print_class("[A-Z]");
54    print_class("[0-9]");
55    print_class("[a-zA-Z]");
56
57    println!("\n=== Escape shorthands inside brackets ===");
58    print_class(r"[\d]");
59    print_class(r"[\w\s]");
60    print_class(r"[^\W_]");   // word chars minus underscore
61
62    println!("\n=== Mixed ===");
63    print_class(r"[a-z\d_]");   // lowercase letter, digit, or underscore
64    print_class(r"[^a-z\s]");   // not a lowercase letter and not whitespace
65
66    println!("\n=== Class inside a larger pattern ===");
67    let pattern = r"[A-Z][a-z]+";
68    println!("  Pattern: {pattern}");
69    println!("  AST:\n{:#?}", parse(pattern).unwrap());
70}