smart_word_wrap_simple.sf 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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(array.slice(0, i+1).join(" ") => self.prepare_words(array.slice(i+1))))
  26. ++len >= WIDTH && break;
  27. }
  28. root ? root : null;
  29. }
  30. method combine(root, hash) {
  31. var row = [];
  32. hash.each { |key, value|
  33. root.append(key);
  34. if (value.is_an(Array)) {
  35. value.each { |item|
  36. row.append(self.combine(root, item)...);
  37. }
  38. }
  39. else {
  40. row = [[root...]];
  41. }
  42. root.pop;
  43. }
  44. row;
  45. }
  46. method find_best(arrays) {
  47. var best = Hash.new(
  48. score => Inf,
  49. value => [],
  50. );
  51. arrays.each { |array_ref|
  52. var score = 0;
  53. array_ref.each { |string|
  54. score += ::pow(WIDTH - string.len, 2);
  55. }
  56. score < best{:score} && (
  57. best{:score} = score;
  58. best{:value} = array_ref;
  59. );
  60. }
  61. best{:value};
  62. }
  63. method wrap(text, width) {
  64. # Temporarily modify the width
  65. local WIDTH = width if defined(width);
  66. # Split the text into words
  67. text.is_a(String) && text.words!;
  68. var lines = [];
  69. self.prepare_words(text).each { |path|
  70. lines.append(self.combine([], path)...);
  71. }
  72. self.find_best(lines).join("\n");
  73. }
  74. }
  75. var sww = SmartWordWrap();
  76. var words = %w(aaa bb cc ddddd);
  77. #var words = %w(Lorem ipsum dolor sit amet, consectetur adipiscing elit.);
  78. var wrapped = sww.wrap(words, 6);
  79. say wrapped;
  80. wrapped == ['aaa', 'bb cc', 'ddddd'].join("\n") || die "error!";