繁体   English   中英

将字符串拆分为最大字符数的块,而不会破坏单词

[英]Split string into chunks of maximum character count without breaking words

我想将一个字符串拆分成块,每个块都在最大字符数内,比如2000,并且不会拆分一个字。

我尝试过如下操作:

text.chars.each_slice(2000).map(&:join)

但有时候,话语会分裂。 我试过一些正则表达式:

text.scan(/.{1,2000}\b|.{1,2000}/).map(&:strip)

这个问题 ,但我不知道它是如何工作的,它给了我一些不稳定的行为,有时给出只包含句子的块。

任何指针将不胜感激。

你可以做一个记事本风格的自动换行。
只需使用每行最大字符量词范围{1,N}构造正则表达式。

以下示例每行使用32个最大值。

https://regex101.com/r/8vAkOX/1

更新 :要在范围内包含换行符,请添加dot-all修饰符(?s)
否则,将过滤掉独立的换行符。

(?s)(?:((?>.{1,32}(?:(?<=[^\\S\\r\\n])[^\\S\\r\\n]?|(?=\\r?\\n)|$|[^\\S\\r\\n]))|.{1,32})(?:\\r?\\n)?|(?:\\r?\\n|$))

块的$1 ,您可以用$1\\r\\n替换以获得显示
看起来很好看

解释

 (?s) # Span line breaks
 (?:
      # -- Words/Characters 
      (                       # (1 start)
           (?>                     # Atomic Group - Match words with valid breaks
                .{1,32}                 #  1-N characters
                                        #  Followed by one of 4 prioritized, non-linebreak whitespace
                (?:                     #  break types:
                     (?<= [^\S\r\n] )        # 1. - Behind a non-linebreak whitespace
                     [^\S\r\n]?              #      ( optionally accept an extra non-linebreak whitespace )
                  |  (?= \r? \n )            # 2. - Ahead a linebreak
                  |  $                       # 3. - EOS
                  |  [^\S\r\n]               # 4. - Accept an extra non-linebreak whitespace
                )
           )                       # End atomic group
        |  
           .{1,32}                 # No valid word breaks, just break on the N'th character
      )                       # (1 end)
      (?: \r? \n )?           # Optional linebreak after Words/Characters
   |  
      # -- Or, Linebreak
      (?: \r? \n | $ )        # Stand alone linebreak or at EOS
 )

def max_groups(str, n)
  arr = []
  pos = 0     
  loop do
    break arr if pos == str.size
    m = str.match(/.{1,#{n}}(?=[ ]|\z)|.{,#{n-1}}[ ]/, pos)
    return nil if m.nil?
    arr << m[0]
    pos += m[0].size
  end
end

例子

str = "Now is the time for all good people to party"
  #    12345678901234567890123456789012345678901234
  #    0         1         2         3         4

max_groups(str, 5)
  #=> nil
max_groups(str, 6)
  #=> ["Now is", " the ", "time ", "for ", "all ", "good ", "people", " to 
max_groups(str, 10)
  #=> ["Now is the", " time for ", "all good ", "people to ", "party"]
max_groups(str, 14)
  #=> ["Now is the ", "time for all ", "good people to", " party"]
max_groups(str, 15)
  #=> ["Now is the time", " for all good ", "people to party"]
max_groups(str, 29)
  #=> ["Now is the time for all good ", "people to party"]
max_groups(str, 43)
  #=> ["Now is the time for all good people to ", "party"]
max_groups(str, 44)
  #=> ["Now is the time for all good people to party"]

str = "How        you do?"
  #    123456789012345678
  #    0         1

max_groups(str, 4)
  #=> ["How ", "    ", "   ", "you ", "do?"]

这对我有用(感谢@ StefanPochmann的评论):

text = "Some really long string\nwith some line breaks"

以下将首先删除所有空格,然后再打破字符串。

text.gsub(/\s+/, ' ').scan(/.{1,2000}(?: |$)/).map(&:strip)

生成的字符串块将丢失原始字符串中的所有换行符( \\n )。 如果您需要维护换行符,则需要使用一些随机占位符(在应用正则表达式之前)替换它们,例如: (br) ,您可以使用它来恢复换行符。 像这样:

text = "Some really long string\nwith some line breaks".gsub("\n", "(br)")

在运行正则表达式之后,我们可以通过将\\n (br)替换所有出现的(br)来恢复新块的换行符,如下所示:

chunks = text.gsub(/\s+/, ' ').scan(/.{1,2000}(?: |$)/).map(&:strip)
chunks.each{|chunk| chunk.gsub!('(br)', "\n")}

看起来像一个漫长的过程,但它对我有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM