1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

Merge pull request #7006 from cakebaker/csplit_fix_invalid_pattern

csplit: allow offset without sign in pattern
This commit is contained in:
Sylvestre Ledru 2024-12-27 17:59:55 +01:00 committed by GitHub
commit 6f678269ab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 51 additions and 28 deletions

View file

@ -106,7 +106,7 @@ pub fn get_patterns(args: &[String]) -> Result<Vec<Pattern>, CsplitError> {
fn extract_patterns(args: &[String]) -> Result<Vec<Pattern>, CsplitError> { fn extract_patterns(args: &[String]) -> Result<Vec<Pattern>, CsplitError> {
let mut patterns = Vec::with_capacity(args.len()); let mut patterns = Vec::with_capacity(args.len());
let to_match_reg = let to_match_reg =
Regex::new(r"^(/(?P<UPTO>.+)/|%(?P<SKIPTO>.+)%)(?P<OFFSET>[\+-]\d+)?$").unwrap(); Regex::new(r"^(/(?P<UPTO>.+)/|%(?P<SKIPTO>.+)%)(?P<OFFSET>[\+-]?\d+)?$").unwrap();
let execute_ntimes_reg = Regex::new(r"^\{(?P<TIMES>\d+)|\*\}$").unwrap(); let execute_ntimes_reg = Regex::new(r"^\{(?P<TIMES>\d+)|\*\}$").unwrap();
let mut iter = args.iter().peekable(); let mut iter = args.iter().peekable();
@ -219,14 +219,15 @@ mod tests {
"{*}", "{*}",
"/test3.*end$/", "/test3.*end$/",
"{4}", "{4}",
"/test4.*end$/+3", "/test4.*end$/3",
"/test5.*end$/-3", "/test5.*end$/+3",
"/test6.*end$/-3",
] ]
.into_iter() .into_iter()
.map(|v| v.to_string()) .map(|v| v.to_string())
.collect(); .collect();
let patterns = get_patterns(input.as_slice()).unwrap(); let patterns = get_patterns(input.as_slice()).unwrap();
assert_eq!(patterns.len(), 5); assert_eq!(patterns.len(), 6);
match patterns.first() { match patterns.first() {
Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Times(1))) => { Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Times(1))) => {
let parsed_reg = format!("{reg}"); let parsed_reg = format!("{reg}");
@ -256,12 +257,19 @@ mod tests {
_ => panic!("expected UpToMatch pattern"), _ => panic!("expected UpToMatch pattern"),
}; };
match patterns.get(4) { match patterns.get(4) {
Some(Pattern::UpToMatch(reg, -3, ExecutePattern::Times(1))) => { Some(Pattern::UpToMatch(reg, 3, ExecutePattern::Times(1))) => {
let parsed_reg = format!("{reg}"); let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test5.*end$"); assert_eq!(parsed_reg, "test5.*end$");
} }
_ => panic!("expected UpToMatch pattern"), _ => panic!("expected UpToMatch pattern"),
}; };
match patterns.get(5) {
Some(Pattern::UpToMatch(reg, -3, ExecutePattern::Times(1))) => {
let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test6.*end$");
}
_ => panic!("expected UpToMatch pattern"),
};
} }
#[test] #[test]
@ -273,14 +281,15 @@ mod tests {
"{*}", "{*}",
"%test3.*end$%", "%test3.*end$%",
"{4}", "{4}",
"%test4.*end$%+3", "%test4.*end$%3",
"%test5.*end$%-3", "%test5.*end$%+3",
"%test6.*end$%-3",
] ]
.into_iter() .into_iter()
.map(|v| v.to_string()) .map(|v| v.to_string())
.collect(); .collect();
let patterns = get_patterns(input.as_slice()).unwrap(); let patterns = get_patterns(input.as_slice()).unwrap();
assert_eq!(patterns.len(), 5); assert_eq!(patterns.len(), 6);
match patterns.first() { match patterns.first() {
Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Times(1))) => { Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Times(1))) => {
let parsed_reg = format!("{reg}"); let parsed_reg = format!("{reg}");
@ -310,12 +319,19 @@ mod tests {
_ => panic!("expected SkipToMatch pattern"), _ => panic!("expected SkipToMatch pattern"),
}; };
match patterns.get(4) { match patterns.get(4) {
Some(Pattern::SkipToMatch(reg, -3, ExecutePattern::Times(1))) => { Some(Pattern::SkipToMatch(reg, 3, ExecutePattern::Times(1))) => {
let parsed_reg = format!("{reg}"); let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test5.*end$"); assert_eq!(parsed_reg, "test5.*end$");
} }
_ => panic!("expected SkipToMatch pattern"), _ => panic!("expected SkipToMatch pattern"),
}; };
match patterns.get(5) {
Some(Pattern::SkipToMatch(reg, -3, ExecutePattern::Times(1))) => {
let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test6.*end$");
}
_ => panic!("expected SkipToMatch pattern"),
};
} }
#[test] #[test]

View file

@ -130,17 +130,21 @@ fn test_up_to_match_sequence() {
#[test] #[test]
fn test_up_to_match_offset() { fn test_up_to_match_offset() {
let (at, mut ucmd) = at_and_ucmd!(); for offset in ["3", "+3"] {
ucmd.args(&["numbers50.txt", "/9$/+3"]) let (at, mut ucmd) = at_and_ucmd!();
.succeeds() ucmd.args(&["numbers50.txt", &format!("/9$/{offset}")])
.stdout_only("24\n117\n"); .succeeds()
.stdout_only("24\n117\n");
let count = glob(&at.plus_as_string("xx*")) let count = glob(&at.plus_as_string("xx*"))
.expect("there should be splits created") .expect("there should be splits created")
.count(); .count();
assert_eq!(count, 2); assert_eq!(count, 2);
assert_eq!(at.read("xx00"), generate(1, 12)); assert_eq!(at.read("xx00"), generate(1, 12));
assert_eq!(at.read("xx01"), generate(12, 51)); assert_eq!(at.read("xx01"), generate(12, 51));
at.remove("xx00");
at.remove("xx01");
}
} }
#[test] #[test]
@ -316,16 +320,19 @@ fn test_skip_to_match_sequence4() {
#[test] #[test]
fn test_skip_to_match_offset() { fn test_skip_to_match_offset() {
let (at, mut ucmd) = at_and_ucmd!(); for offset in ["3", "+3"] {
ucmd.args(&["numbers50.txt", "%23%+3"]) let (at, mut ucmd) = at_and_ucmd!();
.succeeds() ucmd.args(&["numbers50.txt", &format!("%23%{offset}")])
.stdout_only("75\n"); .succeeds()
.stdout_only("75\n");
let count = glob(&at.plus_as_string("xx*")) let count = glob(&at.plus_as_string("xx*"))
.expect("there should be splits created") .expect("there should be splits created")
.count(); .count();
assert_eq!(count, 1); assert_eq!(count, 1);
assert_eq!(at.read("xx00"), generate(26, 51)); assert_eq!(at.read("xx00"), generate(26, 51));
at.remove("xx00");
}
} }
#[test] #[test]