smart_word_wrap.jl 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #!/usr/bin/julia
  2. # Trizen
  3. # Date: 15th October 2013
  4. # https://github.com/trizen
  5. # https://trizenx.blogspot.com/2013/11/smart-word-wrap.html
  6. # Smart word wrap algorithm
  7. # See: https://en.wikipedia.org/wiki/Word_wrap#Minimum_raggedness
  8. # This is the ugliest method! It, recursively,
  9. # prepares the words for the combine() function.
  10. function prepare_words(array, width, callback, depth=0)
  11. root, len, i = [], 0, 0
  12. limit = length(array)
  13. while ((i+=1) <= limit)
  14. len += (word_len = length(array[i]))
  15. if len > width
  16. if word_len > width
  17. len -= word_len
  18. value = array[i]
  19. a = collect((m.match for m = eachmatch(Regex(".{1,$width}"), value)))
  20. splice!(array, i, map(x -> convert(String, x), a))
  21. limit = length(array)
  22. i -= 1
  23. continue
  24. end
  25. break
  26. end
  27. push!(root, Any[
  28. join(array[1:i], ' '),
  29. prepare_words(array[i+1 : limit], width, callback, depth+1)
  30. ])
  31. if depth == 0
  32. callback(root[1])
  33. root = []
  34. end
  35. ((len += 1) >= width) && break
  36. end
  37. root
  38. end
  39. # This function combines the
  40. # the parents with the childrens.
  41. function combine(root, path, block)
  42. key = popfirst!(path)
  43. for value in path
  44. push!(root, key)
  45. if isempty(value)
  46. block(root)
  47. else
  48. for item in value
  49. combine(root, item, block)
  50. end
  51. end
  52. pop!(root)
  53. end
  54. end
  55. # This is the main function of the algorithm
  56. # which calls all the other functions and
  57. # returns the best possible wrapped string.
  58. function smart_wrap(text, width)
  59. words = isa(text, AbstractString) ? split(text) : text
  60. best = Dict{String, Any}(
  61. "score" => Inf,
  62. "value" => [],
  63. )
  64. prepare_words(words, width, function (path)
  65. combine([], path, function (combination)
  66. score = 0
  67. for line in combination[1:length(combination)-1]
  68. score += (width - length(line))^2
  69. end
  70. if score < best["score"]
  71. best["score"] = score
  72. best["value"] = copy(combination)
  73. end
  74. end)
  75. end)
  76. join(best["value"], "\n")
  77. end
  78. #
  79. ## Usage examples
  80. #
  81. text = "aaa bb cc ddddd"
  82. println(smart_wrap(text, 6))
  83. println("-" ^ 80)
  84. text = "As shown in the above phases (or steps), the algorithm does many useless transformations"
  85. println(smart_wrap(text, 20))
  86. println("-" ^ 80)
  87. text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
  88. println(smart_wrap(text, 20))
  89. println("-" ^ 80)
  90. text = "Lorem ipsum dolor ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ amet, consectetur adipiscing elit."
  91. println(smart_wrap(text, 20))
  92. println("-" ^ 80)
  93. text = "Will Perl6 also be pre-installed on future Mac/Linux operating systems? ... I can\'t predict the success of the project...";
  94. println(smart_wrap(text, 20))