wordwrap.nim 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2018 Nim contributors
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module contains an algorithm to wordwrap a Unicode string.
  10. import strutils, unicode
  11. proc olen(s: string): int =
  12. var i = 0
  13. result = 0
  14. while i < s.len:
  15. inc result
  16. let L = graphemeLen(s, i)
  17. inc i, L
  18. proc wrapWords*(s: string, maxLineWidth = 80,
  19. splitLongWords = true,
  20. seps: set[char] = Whitespace,
  21. newLine = "\n"): string {.noSideEffect.} =
  22. ## Word wraps `s`.
  23. runnableExamples:
  24. doAssert "12345678901234567890".wrapWords() == "12345678901234567890"
  25. doAssert "123456789012345678901234567890".wrapWords(20) == "12345678901234567890\n1234567890"
  26. doAssert "Hello Bob. Hello John.".wrapWords(13, false) == "Hello Bob.\nHello John."
  27. doAssert "Hello Bob. Hello John.".wrapWords(13, true, {';'}) == "Hello Bob. He\nllo John."
  28. result = newStringOfCap(s.len + s.len shr 6)
  29. var spaceLeft = maxLineWidth
  30. var lastSep = ""
  31. for word, isSep in tokenize(s, seps):
  32. let wlen = olen(word)
  33. if isSep:
  34. lastSep = word
  35. spaceLeft = spaceLeft - wlen
  36. elif wlen > spaceLeft:
  37. if splitLongWords and wlen > maxLineWidth:
  38. var i = 0
  39. while i < word.len:
  40. if spaceLeft <= 0:
  41. spaceLeft = maxLineWidth
  42. result.add newLine
  43. dec spaceLeft
  44. let L = graphemeLen(word, i)
  45. for j in 0 ..< L: result.add word[i+j]
  46. inc i, L
  47. else:
  48. spaceLeft = maxLineWidth - wlen
  49. result.add(newLine)
  50. result.add(word)
  51. else:
  52. spaceLeft = spaceLeft - wlen
  53. result.add(lastSep)
  54. result.add(word)
  55. lastSep.setLen(0)
  56. when isMainModule:
  57. when true:
  58. let
  59. inp = """ this is a long text -- muchlongerthan10chars and here
  60. it goes"""
  61. outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
  62. doAssert wrapWords(inp, 10, false) == outp
  63. let
  64. longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow"""
  65. longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow"
  66. doAssert wrapWords(longInp, 8, true) == longOutp
  67. # test we don't break Umlauts into invalid bytes:
  68. let fies = "äöüöäöüöäöüöäöüööäöüöäößßßßüöäößßßßßß"
  69. let fiesRes = "ä\nö\nü\nö\nä\nö\nü\nö\nä\nö\nü\nö\nä\nö\nü\nö\nö\nä\nö\nü\nö\nä\nö\nß\nß\nß\nß\nü\nö\nä\nö\nß\nß\nß\nß\nß\nß"
  70. doAssert wrapWords(fies, 1, true) == fiesRes
  71. let longlongword = """abc uitdaeröägfßhydüäpydqfü,träpydqgpmüdträpydföägpydörztdüöäfguiaeowäzjdtrüöäp psnrtuiydrözenrüöäpyfdqazpesnrtulocjtüö
  72. äzydgyqgfqfgprtnwjlcydkqgfüöezmäzydydqüüöäpdtrnvwfhgckdumböäpydfgtdgfhtdrntdrntydfogiayqfguiatrnydrntüöärtniaoeydfgaoeiqfglwcßqfgxvlcwgtfhiaoen
  73. rsüöäapmböäptdrniaoydfglckqfhouenrtsüöäptrniaoeyqfgulocfqclgwxßqflgcwßqfxglcwrniatrnmüböäpmöäbpümöäbpüöämpbaoestnriaesnrtdiaesrtdniaesdrtnaetdr
  74. iaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολωχσωχνωκψρχκψρτιεαοσηζϵηζιοεννκεωνιαλωσωκνκψρκγτφγτχκγτεκργτιχνκιωχσιλωσλωχξλξλξωχωχ
  75. ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνρκψγκψφϵιηαααοε"""
  76. let longlongwordRes = """
  77. abc uitdaeröägfßhydüäpydqfü,träpydqgpmüdträpydföägpydörztdüöäfguiaeowäzjdtrüöäp
  78. psnrtuiydrözenrüöäpyfdqazpesnrtulocjtüöäzydgyqgfqfgprtnwjlcydkqgfüöezmäzydydqüü
  79. öäpdtrnvwfhgckdumböäpydfgtdgfhtdrntdrntydfogiayqfguiatrnydrntüöärtniaoeydfgaoeiq
  80. fglwcßqfgxvlcwgtfhiaoenrsüöäapmböäptdrniaoydfglckqfhouenrtsüöäptrniaoeyqfgulocf
  81. qclgwxßqflgcwßqfxglcwrniatrnmüböäpmöäbpümöäbpüöämpbaoestnriaesnrtdiaesrtdniaesdr
  82. tnaetdriaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολωχσωχνωκψρχκψ
  83. ρτιεαοσηζϵηζιοεννκεωνιαλωσωκνκψρκγτφγτχκγτεκργτιχνκιωχσιλωσλωχξλξλξωχωχ
  84. ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνρκψγκψφϵιηαααοε"""
  85. doAssert wrapWords(longlongword) == longlongwordRes