From a291f2c2718091e34dbe4a94db1753ea61aed2eb Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 17 Jul 2015 16:25:58 -0400 Subject: [PATCH 1/6] Create Ruby-like chomp proc to allow for easy string ending removal --- lib/pure/strutils.nim | 47 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 93fcf4d3dc..a0fa7a2370 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -168,9 +168,54 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, inc(i) inc(j) +proc chomp*(s: string, chars: set[char] = Newlines): string {.noSideEffect, rtl.} = + 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 + + return s[0..last] + +proc chomp*(s: string, c: char): string {.noSideEffect, rtl.} = + chomp(s, chars = {c}) + +proc chomp*(s: string, suffix: string): string {.noSideEffect, rtl.} = + var last = len(s) - 1 + + if suffix == "": + var previous: char + while last > 0: + + if s[last] == '\13' and previous == '\13': + break + + elif s[last] == '\13': + last -= 1 + previous = '\13' + + elif s[last] == '\10': + last -= 1 + previous = '\10' + + else: + break + + if s.endsWith(suffix): + last -= len(suffix) + + return s[0..last] + {.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. ## From d28862422be912b5f3e0cbcaf05f3712376624af Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 17 Jul 2015 16:26:10 -0400 Subject: [PATCH 2/6] Add tests for chomp --- tests/stdlib/tstrutil.nim | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index 3db484faa9..d807cd11ca 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -10,12 +10,29 @@ import proc testStrip() = write(stdout, strip(" ha ")) -proc main() = +proc testChomp = + assert "hello".chomp == "hello" + assert "hello\n".chomp == "hello" + assert "hello\r\n".chomp == "hello" + assert "hello\n\r".chomp == "hello\n" + assert "hello\n\n".chomp == "hello\n" + assert "hello\r".chomp == "hello" + assert "hello \n there".chomp == "hello \n there" + assert "hello".chomp("llo") == "he" + assert "hellos".chomp('s') == "hello" + assert "hellos".chomp({'s','z'}) == "hello" + assert "hellos".chomp({'o','s'}) == "hello" + assert "hello\r\n\r\n".chomp("") == "hello" + assert "hello\r\n\r\r\n".chomp("") == "hello\r\n\r" + assert "hello\n\n\n\n\n".chomp("") == "hello" + +proc main() = testStrip() + testChomp() 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 +41,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") From 94149f7a48e1fc2730769ee181bbd09942051c9b Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 21 Jul 2015 15:04:10 -0400 Subject: [PATCH 3/6] Update tests to proposed changes --- tests/stdlib/tstrutil.nim | 55 +++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index d807cd11ca..b15bf0e688 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -10,25 +10,48 @@ import proc testStrip() = write(stdout, strip(" ha ")) -proc testChomp = - assert "hello".chomp == "hello" - assert "hello\n".chomp == "hello" - assert "hello\r\n".chomp == "hello" - assert "hello\n\r".chomp == "hello\n" - assert "hello\n\n".chomp == "hello\n" - assert "hello\r".chomp == "hello" - assert "hello \n there".chomp == "hello \n there" - assert "hello".chomp("llo") == "he" - assert "hellos".chomp('s') == "hello" - assert "hellos".chomp({'s','z'}) == "hello" - assert "hellos".chomp({'o','s'}) == "hello" - assert "hello\r\n\r\n".chomp("") == "hello" - assert "hello\r\n\r\r\n".chomp("") == "hello\r\n\r" - assert "hello\n\n\n\n\n".chomp("") == "hello" +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() - testChomp() + testRemoveSuffix() for p in split("/home/a1:xyz:/usr/bin", {':'}): write(stdout, p) From 99b29b3e97a3e6dd3e3396a00d9cf97fb2f538a3 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 21 Jul 2015 15:10:03 -0400 Subject: [PATCH 4/6] Switch to removeSuffix name and modify the string in place --- lib/pure/strutils.nim | 73 ++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 46 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index a0fa7a2370..4def0b3e80 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -168,52 +168,6 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, inc(i) inc(j) -proc chomp*(s: string, chars: set[char] = Newlines): string {.noSideEffect, rtl.} = - 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 - - return s[0..last] - -proc chomp*(s: string, c: char): string {.noSideEffect, rtl.} = - chomp(s, chars = {c}) - -proc chomp*(s: string, suffix: string): string {.noSideEffect, rtl.} = - var last = len(s) - 1 - - if suffix == "": - var previous: char - while last > 0: - - if s[last] == '\13' and previous == '\13': - break - - elif s[last] == '\13': - last -= 1 - previous = '\13' - - elif s[last] == '\10': - last -= 1 - previous = '\10' - - else: - break - - if s.endsWith(suffix): - last -= len(suffix) - - return s[0..last] - -{.pop.} proc strip*(s: string, leading = true, trailing = true, chars: set[char] = Whitespace): string {.noSideEffect, rtl, extern: "nsuStrip".} = @@ -1441,6 +1395,33 @@ proc format*(formatstr: string, a: varargs[string, `$`]): string {.noSideEffect, {.pop.} +proc removeSuffix*(s: var string, chars: set[char] = Newlines) {.rtl.} = + 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.} = + removeSuffix(s, chars = {c}) + +proc removeSuffix*(s: var string, suffix: string) {.rtl.} = + 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" From d2c992c03d498b7427ed393fc203609578fd6c96 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 21 Jul 2015 15:49:05 -0400 Subject: [PATCH 5/6] Add docs --- lib/pure/strutils.nim | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 4def0b3e80..3c6421bd53 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1396,6 +1396,20 @@ proc format*(formatstr: string, a: varargs[string, `$`]): string {.noSideEffect, {.pop.} proc removeSuffix*(s: var string, chars: set[char] = Newlines) {.rtl.} = + ## 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: @@ -1412,9 +1426,22 @@ proc removeSuffix*(s: var string, chars: set[char] = Newlines) {.rtl.} = s.setLen(last + 1) proc removeSuffix*(s: var string, c: char) {.rtl.} = + ## 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.} = + ## 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): From d886c44931e8f69e6b70973e8d85b6b13cf4f75c Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 21 Jul 2015 15:51:47 -0400 Subject: [PATCH 6/6] Add extern pragma --- lib/pure/strutils.nim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 3c6421bd53..e3f99b8958 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1395,7 +1395,8 @@ proc format*(formatstr: string, a: varargs[string, `$`]): string {.noSideEffect, {.pop.} -proc removeSuffix*(s: var string, chars: set[char] = Newlines) {.rtl.} = +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. @@ -1425,7 +1426,7 @@ proc removeSuffix*(s: var string, chars: set[char] = Newlines) {.rtl.} = s.setLen(last + 1) -proc removeSuffix*(s: var string, c: char) {.rtl.} = +proc removeSuffix*(s: var string, c: char) {.rtl, extern: "nsuRemoveSuffixChar".} = ## Removes a single character (in-place) from a string. ## .. code-block:: nim ## var @@ -1434,7 +1435,8 @@ proc removeSuffix*(s: var string, c: char) {.rtl.} = ## table == "user" removeSuffix(s, chars = {c}) -proc removeSuffix*(s: var string, suffix: string) {.rtl.} = +proc removeSuffix*(s: var string, suffix: string) {. + rtl, extern: "nsuRemoveSuffixString".} = ## Remove the first matching suffix (in-place) from a string. ## .. code-block:: nim ## var