mirror of
https://github.com/typst/typst
synced 2025-05-15 17:45:27 +08:00
Refactor string replacement
This commit is contained in:
parent
be3c4d7876
commit
519e8a7b4c
@ -362,7 +362,7 @@ string and returns the resulting string.
|
|||||||
- pattern: string or regex (positional, required)
|
- pattern: string or regex (positional, required)
|
||||||
The pattern to search for.
|
The pattern to search for.
|
||||||
- replacement: string or function (positional, required)
|
- replacement: string or function (positional, required)
|
||||||
The string to replace the matches with or a function that is passed a match dictionary if a regex was used.
|
The string to replace the matches with or a function that gets a dictionary for each match and can return individual replacement strings.
|
||||||
- count: integer (named)
|
- count: integer (named)
|
||||||
If given, only the first `count` matches of the pattern are placed.
|
If given, only the first `count` matches of the pattern are placed.
|
||||||
- returns: string
|
- returns: string
|
||||||
|
103
src/eval/str.rs
103
src/eval/str.rs
@ -1,7 +1,7 @@
|
|||||||
use std::borrow::{Borrow, Cow};
|
use std::borrow::{Borrow, Cow};
|
||||||
use std::fmt::{self, Debug, Display, Formatter, Write};
|
use std::fmt::{self, Debug, Display, Formatter, Write};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::{Add, AddAssign, Deref};
|
use std::ops::{Add, AddAssign, Deref, Range};
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
@ -258,8 +258,8 @@ impl Str {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Replace at most `count` occurrences of the given pattern with a
|
/// Replace at most `count` occurrences of the given pattern with a
|
||||||
/// replacement string or function (beginning from the start). If no count is given,
|
/// replacement string or function (beginning from the start). If no count
|
||||||
/// all occurrences are replaced.
|
/// is given, all occurrences are replaced.
|
||||||
pub fn replace(
|
pub fn replace(
|
||||||
&self,
|
&self,
|
||||||
vm: &mut Vm,
|
vm: &mut Vm,
|
||||||
@ -267,64 +267,51 @@ impl Str {
|
|||||||
with: Replacement,
|
with: Replacement,
|
||||||
count: Option<usize>,
|
count: Option<usize>,
|
||||||
) -> SourceResult<Self> {
|
) -> SourceResult<Self> {
|
||||||
match with {
|
// Heuristic: Assume the new string is about the same length as
|
||||||
Replacement::Func(func) => {
|
// the current string.
|
||||||
// heuristic: assume the new string is about the same length as the current string
|
let mut output = EcoString::with_capacity(self.as_str().len());
|
||||||
let mut new = String::with_capacity(self.as_str().len());
|
|
||||||
let mut last_match = 0;
|
// Replace one match of a pattern with the replacement.
|
||||||
match &pattern {
|
let mut last_match = 0;
|
||||||
StrPattern::Str(pat) => {
|
let mut handle_match = |range: Range<usize>, dict: Dict| -> SourceResult<()> {
|
||||||
let matches = self
|
// Push everything until the match.
|
||||||
.0
|
output.push_str(&self[last_match..range.start]);
|
||||||
.match_indices(pat.as_str())
|
last_match = range.end;
|
||||||
.map(|(start, s)| (start, start + s.len(), s))
|
|
||||||
.take(count.unwrap_or(usize::MAX));
|
// Determine and push the replacement.
|
||||||
for (start, end, text) in matches {
|
match &with {
|
||||||
// push everything until the match
|
Replacement::Str(s) => output.push_str(s),
|
||||||
new.push_str(&self.as_str()[last_match..start]);
|
Replacement::Func(func) => {
|
||||||
let args = Args::new(
|
let args = Args::new(func.span(), [dict.into()]);
|
||||||
func.span(),
|
let piece = func.call_vm(vm, args)?.cast::<Str>().at(func.span())?;
|
||||||
[match_to_dict((start, text)).into()],
|
output.push_str(&piece);
|
||||||
);
|
}
|
||||||
let res =
|
}
|
||||||
func.call_vm(vm, args)?.cast::<Str>().at(func.span())?;
|
|
||||||
new.push_str(res.as_str());
|
Ok(())
|
||||||
last_match = end;
|
};
|
||||||
}
|
|
||||||
}
|
// Iterate over the matches of the `pattern`.
|
||||||
StrPattern::Regex(re) => {
|
let count = count.unwrap_or(usize::MAX);
|
||||||
let all_captures =
|
match &pattern {
|
||||||
re.captures_iter(self).take(count.unwrap_or(usize::MAX));
|
StrPattern::Str(pat) => {
|
||||||
for caps in all_captures {
|
for m in self.match_indices(pat.as_str()).take(count) {
|
||||||
// `caps.get(0)` returns the entire match over all capture groups
|
let (start, text) = m;
|
||||||
let (start, end) =
|
handle_match(start..start + text.len(), match_to_dict(m))?;
|
||||||
caps.get(0).map(|c| (c.start(), c.end())).unwrap();
|
}
|
||||||
// push everything until the match
|
}
|
||||||
new.push_str(&self.as_str()[last_match..start]);
|
StrPattern::Regex(re) => {
|
||||||
let args =
|
for caps in re.captures_iter(self).take(count) {
|
||||||
Args::new(func.span(), [captures_to_dict(caps).into()]);
|
// Extract the entire match over all capture groups.
|
||||||
let res =
|
let m = caps.get(0).unwrap();
|
||||||
func.call_vm(vm, args)?.cast::<Str>().at(func.span())?;
|
handle_match(m.start()..m.end(), captures_to_dict(caps))?;
|
||||||
new.push_str(res.as_str());
|
|
||||||
last_match = end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// push the remainder
|
|
||||||
new.push_str(&self.as_str()[last_match..]);
|
|
||||||
Ok(new.into())
|
|
||||||
}
|
}
|
||||||
Replacement::Str(s) => match pattern {
|
|
||||||
StrPattern::Str(pat) => match count {
|
|
||||||
Some(n) => Ok(self.0.replacen(pat.as_str(), &s, n).into()),
|
|
||||||
None => Ok(self.0.replace(pat.as_str(), &s).into()),
|
|
||||||
},
|
|
||||||
StrPattern::Regex(re) => match count {
|
|
||||||
Some(n) => Ok(re.replacen(self, n, s.as_str()).into()),
|
|
||||||
None => Ok(re.replace_all(self, s.as_str()).into()),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Push the remainder.
|
||||||
|
output.push_str(&self[last_match..]);
|
||||||
|
Ok(output.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Repeat the string a number of times.
|
/// Repeat the string a number of times.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user