added ability to opt in to normal string replacement in replace cmd (#5133)

* added ability to opt in to normal string replacement in `replace` cmd

* type-o
This commit is contained in:
Darren Schroeder 2022-04-08 12:23:16 -05:00 committed by GitHub
parent 7ce570e52c
commit 74d0f19291
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -13,6 +13,7 @@ struct Arguments {
replace: String, replace: String,
column_paths: Vec<CellPath>, column_paths: Vec<CellPath>,
literal_replace: bool, literal_replace: bool,
no_regex: bool,
} }
#[derive(Clone)] #[derive(Clone)]
@ -38,6 +39,11 @@ impl Command for SubCommand {
"do not expand the replace parameter as a regular expression", "do not expand the replace parameter as a regular expression",
Some('n'), Some('n'),
) )
.switch(
"string",
"do not use regular expressions for string find and replace",
Some('s'),
)
.category(Category::Strings) .category(Category::Strings)
} }
@ -107,7 +113,22 @@ impl Command for SubCommand {
span: Span::test_data(), span: Span::test_data(),
}), }),
}, },
Example {
description: "Find and replace the first occurence using string replacement *not* regular expressions",
example: r#"'c:\some\cool\path' | str replace 'c:\some\cool' '~' -s"#,
result: Some(Value::String {
val: "~\\path".to_string(),
span: Span::test_data(),
}),
},
Example {
description: "Find and replace all occurences using string replacement *not* regular expressions",
example: r#"'abc abc abc' | str replace -a 'b' 'z' -s"#,
result: Some(Value::String {
val: "azc azc azc".to_string(),
span: Span::test_data(),
}),
},
] ]
} }
} }
@ -118,9 +139,11 @@ fn operate(
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let head = call.head;
let find: Spanned<String> = call.req(engine_state, stack, 0)?; let find: Spanned<String> = call.req(engine_state, stack, 0)?;
let replace: Spanned<String> = call.req(engine_state, stack, 1)?; let replace: Spanned<String> = call.req(engine_state, stack, 1)?;
let literal_replace = call.has_flag("no-expand"); let literal_replace = call.has_flag("no-expand");
let no_regex = call.has_flag("string");
let options = Arc::new(Arguments { let options = Arc::new(Arguments {
all: call.has_flag("all"), all: call.has_flag("all"),
@ -128,8 +151,9 @@ fn operate(
replace: replace.item, replace: replace.item,
column_paths: call.rest(engine_state, stack, 2)?, column_paths: call.rest(engine_state, stack, 2)?,
literal_replace, literal_replace,
no_regex,
}); });
let head = call.head;
input.map( input.map(
move |v| { move |v| {
if options.column_paths.is_empty() { if options.column_paths.is_empty() {
@ -162,6 +186,7 @@ fn action(
replace, replace,
all, all,
literal_replace, literal_replace,
no_regex,
.. ..
}: &Arguments, }: &Arguments,
head: Span, head: Span,
@ -169,6 +194,21 @@ fn action(
match input { match input {
Value::String { val, .. } => { Value::String { val, .. } => {
let FindReplace(find, replacement) = FindReplace(find, replace); let FindReplace(find, replacement) = FindReplace(find, replace);
if *no_regex {
// just use regular string replacement vs regular expressions
if *all {
Value::String {
val: val.replace(find, replacement),
span: head,
}
} else {
Value::String {
val: val.replacen(find, replacement, 1),
span: head,
}
}
} else {
// use regular expressions to replace strings
let regex = Regex::new(find); let regex = Regex::new(find);
match regex { match regex {
@ -203,6 +243,7 @@ fn action(
}, },
} }
} }
}
other => Value::Error { other => Value::Error {
error: ShellError::UnsupportedInput( error: ShellError::UnsupportedInput(
format!( format!(
@ -240,6 +281,7 @@ mod tests {
column_paths: vec![], column_paths: vec![],
literal_replace: false, literal_replace: false,
all: false, all: false,
no_regex: false,
}; };
let actual = action(&word, &options, Span::test_data()); let actual = action(&word, &options, Span::test_data());