Skip to content
This repository was archived by the owner on May 29, 2023. It is now read-only.

Commit c582def

Browse files
committed
Fix alternations with empty sub-expressions with regex >= 0.2.7
With regex 0.2.7 and higher, the trick to rewrite `(a|b|)` to `(a|b|.{0})` doesn't work anymore, it fails with this error: > alternations cannot currently contain empty sub-expressions So delegate it like this instead: `((?:a|b)?)`
1 parent f45d058 commit c582def

File tree

2 files changed

+25
-4
lines changed

2 files changed

+25
-4
lines changed

src/lib.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ impl Expr {
448448

449449
pub fn to_str(&self, buf: &mut String, precedence: u8) {
450450
match *self {
451-
Expr::Empty => buf.push_str(".{0}"),
451+
Expr::Empty => (),
452452
Expr::Any { newline } => buf.push_str(
453453
if newline { "(?s:.)" } else { "." }
454454
),
@@ -476,11 +476,26 @@ impl Expr {
476476
if precedence > 0 {
477477
buf.push_str("(?:");
478478
}
479-
children[0].to_str(buf, 1);
480-
for child in &children[1..] {
481-
buf.push('|');
479+
480+
let is_empty = |e| match e {
481+
&Expr::Empty => true,
482+
_ => false,
483+
};
484+
let contains_empty = children.iter().any(&is_empty);
485+
if contains_empty {
486+
buf.push_str("(?:");
487+
}
488+
for (i, child) in children.iter().filter(|&c| !is_empty(c)).enumerate() {
489+
if i != 0 {
490+
buf.push('|');
491+
}
482492
child.to_str(buf, 1);
483493
}
494+
if contains_empty {
495+
// regex fails with `(a|b|)`, so transform to `((?:a|b)?)`
496+
buf.push_str(")?");
497+
}
498+
484499
if precedence > 0 {
485500
buf.push(')');
486501
}

tests/matching.rs

+6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ fn character_class_intersection() {
5757
fn alternation_with_empty_arm() {
5858
assert_match(r"^(a|)$", "a");
5959
assert_match(r"^(a|)$", "");
60+
assert_match(r"^(|a)$", "a");
61+
assert_match(r"^(|a)$", "");
62+
assert_match(r"a|", "a");
63+
assert_match(r"a|", "");
64+
assert_match(r"|a", "a");
65+
assert_match(r"|a", "");
6066
assert_no_match(r"^(a|)$", "b");
6167
}
6268

0 commit comments

Comments
 (0)