smart_word_wrap_simple.sf 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #!/usr/bin/ruby
  2. # Author: Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 15th October 2013
  5. # Translated to Sidef in 17 June 2015
  6. # https://trizenx.blogspot.com
  7. # Smart word wrap algorithm
  8. # See: https://en.wikipedia.org/wiki/Word_wrap#Minimum_raggedness
  9. # Review: https://trizenx.blogspot.ro/2013/11/smart-word-wrap.html
  10. class SmartWordWrap(WIDTH=80) {
  11. method prepare_words(array) {
  12. var root = [];
  13. var len = 0;
  14. for (var i = 0 ; i <= array.end ; i++) {
  15. var word_len = array[i].len;
  16. len += word_len;
  17. len > WIDTH && (
  18. word_len > WIDTH && (
  19. len -= word_len;
  20. array.splice(i, 1, array[i].split(WIDTH)...);
  21. --i; next;
  22. );
  23. break;
  24. );
  25. root.append(Hash.new(array.ft(0, i).join(" ")
  26. => self.prepare_words(array.ft(i + 1, array.end))));
  27. ++len >= WIDTH && break;
  28. }
  29. root ? root : null;
  30. }
  31. method combine(root, hash) {
  32. var row = [];
  33. hash.each { |key, value|
  34. root.append(key);
  35. if (value.is_an(Array)) {
  36. value.each { |item|
  37. row.append(self.combine(root, item)...);
  38. }
  39. }
  40. else {
  41. row = [[root...]];
  42. }
  43. root.pop;
  44. }
  45. row;
  46. }
  47. method find_best(arrays) {
  48. var best = Hash.new(
  49. score => Inf,
  50. value => [],
  51. );
  52. arrays.each { |array_ref|
  53. var score = 0;
  54. array_ref.each { |string|
  55. score += ::pow(WIDTH - string.len, 2);
  56. }
  57. score < best{:score} && (
  58. best{:score} = score;
  59. best{:value} = array_ref;
  60. );
  61. }
  62. best{:value};
  63. }
  64. method wrap(text, width) {
  65. # Temporarily modify the width
  66. local WIDTH = width if defined(width);
  67. # Split the text into words
  68. text.is_a(String) && text.words!;
  69. var lines = [];
  70. self.prepare_words(text).each { |path|
  71. lines.append(self.combine([], path)...);
  72. }
  73. self.find_best(lines).join("\n");
  74. }
  75. }
  76. var sww = SmartWordWrap();
  77. var words = %w(aaa bb cc ddddd);
  78. #var words = %w(Lorem ipsum dolor sit amet, consectetur adipiscing elit.);
  79. var wrapped = sww.wrap(words, 6);
  80. say wrapped;
  81. wrapped == ['aaa', 'bb cc', 'ddddd'].join("\n") || die "error!";