| Crates.io | streplace |
| lib.rs | streplace |
| version | 3.0.0 |
| created_at | 2025-05-21 00:21:50.534232+00 |
| updated_at | 2025-07-10 21:26:37.468488+00 |
| description | A tiny library for matching and replacing in strings and slices with user-defined functions. |
| homepage | |
| repository | https://gitlab.com/MayESchaefer/streplace |
| max_upload_size | |
| id | 1682711 |
| size | 34,421 |
STReplace is a small library for matching and replacing in strings and slices with user-defined functions. It does not currently support overlapping matches.
It provides several extension methods to the String and &str types, for this purpose.
This crate also includes several feature flags:
result: Provides variants of get_matches, replace_matches, and match_and_replace which accept functions that return Result values.convenience: Provides additional convenience Matcher and Replacer implementations, which can be used in place of bare functions.On a very basic benchmark, based on the first example in the section below:
This benchmark is now several versions out of date, but should remain approximately accurate.
use streplace::{InProgressMatch, Match, MatchResult, Matchable};
fn main() {
let test = "hello test, this is a test string";
let new = test.match_and_replace(
|progress, index, character| match progress {
Some(InProgressMatch { start, value }) => {
if index - start >= 4 {
println!("end {start} {value} {character}");
MatchResult::End
} else if "test"
.chars()
.nth(index - start)
.is_some_and(|c| character == c)
{
println!("cont {start} {value}{character}");
MatchResult::Continue
} else {
println!("fail {start} {value} {character}");
MatchResult::Fail
}
}
None => {
if character == 't' {
println!("start {index} {character}");
MatchResult::Start
} else {
println!("none {index} {character}");
MatchResult::None
}
}
},
|Match { start, end, value }| format!("start:{start},end:{end},val:{value}"),
false,
);
println!("{new}");
}
use streplace::{
AccumulatorMatcher, ChainMatchable, InProgressMatch, Match, MatchResult, Matchable,
};
fn main() {
let text = "@first_of(a b c)";
let text = text.match_and_replace(
"@first_of(".chain(AccumulatorMatcher::new(
0,
|progress, index, character, parens| {
let value = progress.map(|p| p.value);
let mut last_chars = value.unwrap_or_default().chars().rev();
let last_char = last_chars.next();
let second_last_char = last_chars.next();
if character == '(' && last_char != Some('\\') {
*parens += 1;
}
if last_char.is_some_and(|c| c == ')') && second_last_char != Some('\\') {
println!("last char is paren");
if *parens == 0 {
*parens = 0;
MatchResult::End
} else {
*parens -= 1;
MatchResult::Continue
}
} else if index == text.len() - 1 && !(character == ')' && last_char != Some('\\'))
{
*parens = 0;
MatchResult::Fail
} else {
MatchResult::Continue
}
},
)),
|Match {
start: _,
end: _,
value,
}| {
let substring = &value["@first_of(".len()..value.len() - 1];
let submatches: Vec<&str> = substring
.get_matches(
AccumulatorMatcher::new(0, |progress, _, character, parens| {
match (progress, character) {
(Some(_), ' ') => {
if *parens == 0 {
MatchResult::End
} else {
MatchResult::Continue
}
}
(
Some(InProgressMatch {
start: _,
value: match_value,
}),
'(',
) => {
if match_value.ends_with('\\') {
MatchResult::Continue
} else {
*parens += 1;
MatchResult::Continue
}
}
(
Some(InProgressMatch {
start: _,
value: match_value,
}),
')',
) => {
if match_value.ends_with('\\') {
MatchResult::Continue
} else {
*parens = (*parens - 1).max(0);
MatchResult::Continue
}
}
(Some(_), _) => MatchResult::Continue,
(None, ' ') => {
*parens = 0;
MatchResult::None
}
(None, _) => {
*parens = 0;
MatchResult::Start
}
}
}),
true,
)
.into_iter()
.map(|m| m.value)
.collect();
let chosen = submatches
.first()
.map(|v| v.to_string())
.unwrap_or_default();
chosen
},
true,
);
println!("{text}");
}
Matcher, Replacer, TryMatcher, and TryReplacer functionsget_matches_acc, match_and_replace_acc, and try_match_and_replace_acc functions, and replaced them with Matcher implementationsMatcher and Replacer for StringsAccumulatorMatcher and ChainMatcher convenience Matchers, TryMatcher variants of those, and the TryMatcherWrapper TryMatchertry_replace_matches, try_match_and_replace, and try_match_and_replace_acc functionsget_matches_acc and match_and_replace_acc functionsmatch_end parameter to matching functions