mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
expr: Fix parsing range quantifiers in regex
This commit is contained in:
parent
be77e142aa
commit
aae62072d8
2 changed files with 49 additions and 10 deletions
|
@ -191,10 +191,17 @@ impl StringOp {
|
||||||
'\\' if !curr_is_escaped && pattern_chars.peek().is_none() => {
|
'\\' if !curr_is_escaped && pattern_chars.peek().is_none() => {
|
||||||
return Err(ExprError::TrailingBackslash);
|
return Err(ExprError::TrailingBackslash);
|
||||||
}
|
}
|
||||||
|
'{' if curr_is_escaped && is_valid_range_quantifier(&pattern_chars) => {
|
||||||
|
re_string.push(curr);
|
||||||
|
// Set the lower bound of range quantifier to 0 if it is missing
|
||||||
|
if pattern_chars.peek() == Some(&',') {
|
||||||
|
re_string.push('0');
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => re_string.push(curr),
|
_ => re_string.push(curr),
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_is_escaped = prev == '\\' && !prev_is_escaped;
|
prev_is_escaped = curr_is_escaped;
|
||||||
prev = curr;
|
prev = curr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,6 +251,46 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if regex pattern character iterator is at the start of a valid range quantifier.
|
||||||
|
/// The iterator's start position is expected to be after the opening brace.
|
||||||
|
/// Range quantifier ends to closing brace.
|
||||||
|
///
|
||||||
|
/// # Examples of valid range quantifiers
|
||||||
|
///
|
||||||
|
/// - `r"\{3\}"`
|
||||||
|
/// - `r"\{3,\}"`
|
||||||
|
/// - `r"\{,6\}"`
|
||||||
|
/// - `r"\{3,6\}"`
|
||||||
|
/// - `r"\{,\}"`
|
||||||
|
fn is_valid_range_quantifier<I>(pattern_chars: &I) -> bool
|
||||||
|
where
|
||||||
|
I: Iterator<Item = char> + Clone,
|
||||||
|
{
|
||||||
|
// Parse the string between braces
|
||||||
|
let mut quantifier = String::new();
|
||||||
|
let mut pattern_chars_clone = pattern_chars.clone().peekable();
|
||||||
|
let Some(mut prev) = pattern_chars_clone.next() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let mut prev_is_escaped = false;
|
||||||
|
while let Some(curr) = pattern_chars_clone.next() {
|
||||||
|
if prev == '\\' && curr == '}' && !prev_is_escaped {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if pattern_chars_clone.peek().is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
quantifier.push(prev);
|
||||||
|
prev_is_escaped = prev == '\\' && !prev_is_escaped;
|
||||||
|
prev = curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if parsed quantifier is valid
|
||||||
|
let re = Regex::new(r"(\d+|\d*,\d*)").expect("valid regular expression");
|
||||||
|
re.is_match(&quantifier)
|
||||||
|
}
|
||||||
|
|
||||||
/// Check for errors in a supplied regular expression
|
/// Check for errors in a supplied regular expression
|
||||||
///
|
///
|
||||||
/// GNU coreutils shows messages for invalid regular expressions
|
/// GNU coreutils shows messages for invalid regular expressions
|
||||||
|
@ -287,10 +334,7 @@ fn check_posix_regex_errors(pattern: &str) -> ExprResult<()> {
|
||||||
.expect("splitn always returns at least one string"),
|
.expect("splitn always returns at least one string"),
|
||||||
repetition.next(),
|
repetition.next(),
|
||||||
) {
|
) {
|
||||||
("", None) => {
|
("", Some("")) => {}
|
||||||
// Empty repeating pattern
|
|
||||||
invalid_content_error = true;
|
|
||||||
}
|
|
||||||
(x, None | Some("")) => {
|
(x, None | Some("")) => {
|
||||||
if x.parse::<i16>().is_err() {
|
if x.parse::<i16>().is_err() {
|
||||||
invalid_content_error = true;
|
invalid_content_error = true;
|
||||||
|
|
|
@ -875,7 +875,6 @@ mod gnu_expr {
|
||||||
.stdout_only("\n");
|
.stdout_only("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bre17() {
|
fn test_bre17() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
|
@ -884,7 +883,6 @@ mod gnu_expr {
|
||||||
.stdout_only("{1}a\n");
|
.stdout_only("{1}a\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bre18() {
|
fn test_bre18() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
|
@ -893,7 +891,6 @@ mod gnu_expr {
|
||||||
.stdout_only("1\n");
|
.stdout_only("1\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bre19() {
|
fn test_bre19() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
|
@ -1105,7 +1102,6 @@ mod gnu_expr {
|
||||||
.stderr_contains("Invalid content of \\{\\}");
|
.stderr_contains("Invalid content of \\{\\}");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bre45() {
|
fn test_bre45() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
|
@ -1114,7 +1110,6 @@ mod gnu_expr {
|
||||||
.stdout_only("1\n");
|
.stdout_only("1\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bre46() {
|
fn test_bre46() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue