strbasics.nim 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2021 Nim Contributors
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module provides some high performance string operations.
  10. ##
  11. ## Experimental API, subject to change.
  12. when defined(nimPreviewSlimSystem):
  13. import std/assertions
  14. const whitespaces = {' ', '\t', '\v', '\r', '\l', '\f'}
  15. proc add*(x: var string, y: openArray[char]) =
  16. ## Concatenates `x` and `y` in place. `y` must not overlap with `x` to
  17. ## allow future `memcpy` optimizations.
  18. # Use `{.noalias.}` ?
  19. let n = x.len
  20. x.setLen n + y.len
  21. # pending https://github.com/nim-lang/Nim/issues/14655#issuecomment-643671397
  22. # use x.setLen(n + y.len, isInit = false)
  23. var i = 0
  24. while i < y.len:
  25. x[n + i] = y[i]
  26. i.inc
  27. # xxx use `nimCopyMem(x[n].addr, y[0].addr, y.len)` after some refactoring
  28. func stripSlice(s: openArray[char], leading = true, trailing = true, chars: set[char] = whitespaces): Slice[int] =
  29. ## Returns the slice range of `s` which is stripped `chars`.
  30. runnableExamples:
  31. assert stripSlice(" abc ") == 1 .. 3
  32. var
  33. first = 0
  34. last = high(s)
  35. if leading:
  36. while first <= last and s[first] in chars: inc(first)
  37. if trailing:
  38. while last >= first and s[last] in chars: dec(last)
  39. result = first .. last
  40. func setSlice*(s: var string, slice: Slice[int]) =
  41. ## Inplace version of `substr`.
  42. runnableExamples:
  43. import std/sugar
  44. var a = "Hello, Nim!"
  45. doAssert a.dup(setSlice(7 .. 9)) == "Nim"
  46. doAssert a.dup(setSlice(0 .. 0)) == "H"
  47. doAssert a.dup(setSlice(0 .. 1)) == "He"
  48. doAssert a.dup(setSlice(0 .. 10)) == a
  49. doAssert a.dup(setSlice(1 .. 0)).len == 0
  50. doAssert a.dup(setSlice(20 .. -1)).len == 0
  51. doAssertRaises(AssertionDefect):
  52. discard a.dup(setSlice(-1 .. 1))
  53. doAssertRaises(AssertionDefect):
  54. discard a.dup(setSlice(1 .. 11))
  55. let first = slice.a
  56. let last = slice.b
  57. assert first >= 0
  58. assert last <= s.high
  59. if first > last:
  60. s.setLen(0)
  61. return
  62. template impl =
  63. for index in first .. last:
  64. s[index - first] = s[index]
  65. if first > 0:
  66. when nimvm: impl()
  67. else:
  68. # not JS and not Nimscript
  69. when not declared(moveMem):
  70. impl()
  71. else:
  72. when defined(nimSeqsV2):
  73. prepareMutation(s)
  74. moveMem(addr s[0], addr s[first], last - first + 1)
  75. s.setLen(last - first + 1)
  76. func strip*(a: var string, leading = true, trailing = true, chars: set[char] = whitespaces) {.inline.} =
  77. ## Inplace version of `strip`. Strips leading or
  78. ## trailing `chars` (default: whitespace characters).
  79. ##
  80. ## If `leading` is true (default), leading `chars` are stripped.
  81. ## If `trailing` is true (default), trailing `chars` are stripped.
  82. ## If both are false, the string is unchanged.
  83. runnableExamples:
  84. var a = " vhellov "
  85. strip(a)
  86. assert a == "vhellov"
  87. a = " vhellov "
  88. a.strip(leading = false)
  89. assert a == " vhellov"
  90. a = " vhellov "
  91. a.strip(trailing = false)
  92. assert a == "vhellov "
  93. var c = "blaXbla"
  94. c.strip(chars = {'b', 'a'})
  95. assert c == "laXbl"
  96. c = "blaXbla"
  97. c.strip(chars = {'b', 'a', 'l'})
  98. assert c == "X"
  99. setSlice(a, stripSlice(a, leading, trailing, chars))