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 String
sAccumulatorMatcher
and ChainMatcher
convenience Matcher
s, TryMatcher
variants of those, and the TryMatcherWrapper
TryMatcher
try_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