diff --git a/crates/typst/src/foundations/str.rs b/crates/typst/src/foundations/str.rs index 897ca45b3..515a4e210 100644 --- a/crates/typst/src/foundations/str.rs +++ b/crates/typst/src/foundations/str.rs @@ -491,11 +491,11 @@ impl Str { #[func] pub fn trim( &self, - /// The pattern to search for. + /// The pattern to search for. If `{none}`, trims white spaces. #[default] pattern: Option, - /// Can be `start` or `end` to only trim the start or end of the string. - /// If omitted, both sides are trimmed. + /// Can be `{start}` or `{end}` to only trim the start or end of the + /// string. If omitted, both sides are trimmed. #[named] at: Option, /// Whether to repeatedly removes matches of the pattern or just once. @@ -535,16 +535,16 @@ impl Str { } Some(StrPattern::Regex(re)) => { let s = self.as_str(); - let mut last = 0; + let mut last = None; let mut range = 0..s.len(); for m in re.find_iter(s) { // Does this match follow directly after the last one? - let consecutive = last == m.start(); + let consecutive = last == Some(m.start()); - // As long as we're consecutive and still trimming at the - // start, trim. - start &= consecutive; + // As long as we're at the beginning or in a consecutive run + // of matches, and we're still trimming at the start, trim. + start &= m.start() == 0 || consecutive; if start { range.start = m.end(); start &= repeat; @@ -556,11 +556,11 @@ impl Str { range.end = m.start(); } - last = m.end(); + last = Some(m.end()); } // Is the last match directly at the end? - if last < s.len() { + if last.is_some_and(|last| last < s.len()) { range.end = s.len(); } diff --git a/tests/typ/compiler/string.typ b/tests/typ/compiler/string.typ index ed1296a7a..949a2154c 100644 --- a/tests/typ/compiler/string.typ +++ b/tests/typ/compiler/string.typ @@ -180,17 +180,31 @@ #"123".replace("123", (1, 2, 3)) --- -// Test the `trim` method. +// Test the `trim` method; the pattern is not provided. #let str = "Typst, LaTeX, Word, InDesign" #let array = ("Typst", "LaTeX", "Word", "InDesign") #test(str.split(",").map(s => s.trim()), array) #test("".trim(), "") +#test(" ".trim(), "") +#test("\t".trim(), "") +#test("\n".trim(), "") +#test("\t \n".trim(), "") #test(" abc ".trim(at: start), "abc ") +#test("\tabc ".trim(at: start), "abc ") +#test("abc\n".trim(at: end), "abc") #test(" abc ".trim(at: end, repeat: true), " abc") #test(" abc".trim(at: start, repeat: false), "abc") + +--- +// Test the `trim` method; the pattern is a string. #test("aabcaa".trim("a", repeat: false), "abca") #test("aabca".trim("a", at: start), "bca") #test("aabcaa".trim("a", at: end, repeat: false), "aabca") +#test(" abc\n".trim("\n"), " abc") +#test("whole".trim("whole", at: start), "") + +--- +// Test the `trim` method; the pattern is a regex. #test("".trim(regex(".")), "") #test("123abc456".trim(regex("\d")), "abc") #test("123abc456".trim(regex("\d"), repeat: false), "23abc45") @@ -201,6 +215,12 @@ #test("123abc456".trim(regex("\d+"), at: end, repeat: false), "123abc") #test("123abc456".trim(regex("\d{1,2}$"), repeat: false), "123abc4") #test("hello world".trim(regex(".")), "") +#test("12306".trim(regex("\d"), at: start), "") +#test("12306abc".trim(regex("\d"), at: start), "abc") +#test("whole".trim(regex("whole"), at: start), "") +#test("12306".trim(regex("\d"), at: end), "") +#test("abc12306".trim(regex("\d"), at: end), "abc") +#test("whole".trim(regex("whole"), at: end), "") --- // Error: 17-21 expected either `start` or `end`