在可变数量的单词上拆分字符串

4
以下问题是@ruhroe在一个小时前发布的。我正要回答时,它被撤下了。这很不幸,因为我认为它非常有趣。我重新发布它,以便原始发帖人能看到,并给其他人提供机会来发布解决方案。
原问题(已编辑):
问题是基于用户提供的数字,将字符串中的某些空格分隔开,具体标准部分取决于该数字。例如,如果数字是5,则每个子字符串包含以下内容之一:
- 一个具有5个或更多字符的单词 - 尽可能多的连续单词(由空格分隔),只要生成的字符串最多有5个字符。
例如,如果字符串是:
"abcdefg fg hijkl mno pqrs tuv wx yz"

结果将是:
["abcdefg", "fg", "hijkl", "mno", "pqrs", "tuv", "wx yz"]
  • "abcdefg" 在单独一行上,因为它至少有五个字符。
  • "fg" 在单独一行上,因为 "fg" 包含 5 个或更少的字符,并且与下一个单词组合时(在它们之间有一个空格),所得到的字符串 "fg hijkl" 包含超过 5 个字符。
  • "hijkl" 在单独一行上,因为它同时满足两个条件。

我该怎么做?


还请注意 https://dev59.com/znE95IYBdhLWcg3wbtbO,虽然不完全相同但类似。 - sawa
不要使用正则表达式进行操作 - 你需要一个既能前瞻又能回顾单词或一组单词的解决方案,同时还要跟踪行的长度。请记住,未来有人需要维护它 - 你想出的任何正则表达式几乎肯定难以理解或难以维护。 - matt
2个回答

3
我相信这样做就可以了:
str = "abcdefg fg hijkl e mn pqrs tuv wx yz"

str.scan(/\b(?:\w{5,}|\w[\w\s]{0,3}\w|\w)\b/)
  #=> ["abcdefg", "fg", "hijkl", "e mn", "pqrs", "tuv", "wx yz"] 

1
@Jonny5,看起来不错。我以为它会包含尾随空格,但实际上并没有。我明白了,这是因为后面跟着(零宽度的)负向先行断言的\b - Cary Swoveland
2
一个变量:\w(?:\w{4,}|.{0,3}\w)?\b 因为它捕获了所有单词,所以开头的单词边界不是必需的。 - Casimir et Hippolyte
@CasimiretHippolyte,看起来不错。是的,我发现最初的\b是不需要的,你可以因素出\w - Cary Swoveland

1
当您遍历集合中的单词时(将原始字符串拆分成单词应该很容易),似乎有三种可能的情况:
  1. 这是一行空白,我们应该将当前单词插入到该行中
  2. 这是一行非空白,而且该单词可以适应该行
  3. 这是一行非空白,但该单词无法适应该行,应该放在新行中
类似这样的代码应该可以工作(注意 - 我没有在您的解决方案之外进行过多测试。您肯定会想要这样做):
words.each do |word|
  if line.blank?
    # this is a new line, so start it with the current word
    line << word
  elsif word_can_fit_line?(line, word, length)
    # the word fits, so append it to the current line
    line << " #{word}"
  else
    # the word doesn't fit, so keep this line and start a new one with
    # the current word
    lines << line
    line = word
  end
end

# add the last line and we're done
lines << line

lines

请注意,实现word_can_fit_line?应该是微不足道的——您只需要查看当前行长度加上一个空格再加上单词长度是否小于或等于所需的行长度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接