diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 93fcf4d3dc..e3f99b8958 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -168,9 +168,8 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, inc(i) inc(j) -{.pop.} -proc strip*(s: string, leading = true, trailing = true, chars: set[char] = Whitespace): string +proc strip*(s: string, leading = true, trailing = true, chars: set[char] = Whitespace): string {.noSideEffect, rtl, extern: "nsuStrip".} = ## Strips `chars` from `s` and returns the resulting string. ## @@ -1396,6 +1395,62 @@ proc format*(formatstr: string, a: varargs[string, `$`]): string {.noSideEffect, {.pop.} +proc removeSuffix*(s: var string, chars: set[char] = Newlines) {. + rtl, extern: "nsuRemoveSuffixCharSet".} = + ## Removes the first matching character from the string (in-place) given a + ## set of characters. If the set of characters is only equal to `Newlines` + ## then it will remove both the newline and return feed. + ## .. code-block:: nim + ## var + ## userInput = "Hello World!\r\n" + ## otherInput = "Hello!?!" + ## userInput.removeSuffix + ## userInput == "Hello World!" + ## userInput.removeSuffix({'!', '?'}) + ## userInput == "Hello World" + ## otherInput.removeSuffix({'!', '?'}) + ## otherInput == "Hello!?" + + var last = len(s) - 1 + + if chars == Newlines: + if s[last] == '\10': + last -= 1 + + if s[last] == '\13': + last -= 1 + + else: + if s[last] in chars: + last -= 1 + + s.setLen(last + 1) + +proc removeSuffix*(s: var string, c: char) {.rtl, extern: "nsuRemoveSuffixChar".} = + ## Removes a single character (in-place) from a string. + ## .. code-block:: nim + ## var + ## table = "users" + ## table.removeSuffix('s') + ## table == "user" + removeSuffix(s, chars = {c}) + +proc removeSuffix*(s: var string, suffix: string) {. + rtl, extern: "nsuRemoveSuffixString".} = + ## Remove the first matching suffix (in-place) from a string. + ## .. code-block:: nim + ## var + ## answers = "yeses" + ## answers.removeSuffix("es") + ## answers == "yes" + + var newLen = s.len + + if s.endsWith(suffix): + newLen -= len(suffix) + + s.setLen(newLen) + when isMainModule: doAssert align("abc", 4) == " abc" doAssert align("a", 0) == "a" diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index 3db484faa9..b15bf0e688 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -10,12 +10,52 @@ import proc testStrip() = write(stdout, strip(" ha ")) -proc main() = +proc testRemoveSuffix = + var s = "hello\n\r" + s.removeSuffix + assert s == "hello\n" + s.removeSuffix + assert s == "hello" + s.removeSuffix + assert s == "hello" + + s = "hello\n\n" + s.removeSuffix + assert s == "hello\n" + + s = "hello\r" + s.removeSuffix + assert s == "hello" + + s = "hello \n there" + s.removeSuffix + assert s == "hello \n there" + + s = "hello" + s.removeSuffix("llo") + assert s == "he" + s.removeSuffix('e') + assert s == "h" + + s = "hellos" + s.removeSuffix({'s','z'}) + assert s == "hello" + s.removeSuffix({'l','o'}) + assert s == "hell" + + # Contrary to Chomp in other languages + # empty string does not change behaviour + s = "hello\r\n\r\n" + s.removeSuffix("") + assert s == "hello\r\n\r\n" + +proc main() = testStrip() + testRemoveSuffix() for p in split("/home/a1:xyz:/usr/bin", {':'}): write(stdout, p) -proc testDelete = +proc testDelete = var s = "0123456789ABCDEFGH" delete(s, 4, 5) assert s == "01236789ABCDEFGH" @@ -24,8 +64,8 @@ proc testDelete = delete(s, 0, 0) assert s == "1236789ABCDEFG" -testDelete() - +testDelete() + assert(insertSep($1000_000) == "1_000_000") assert(insertSep($232) == "232") assert(insertSep($12345, ',') == "12,345")