【问题标题】:Ruby: substring to a certain length and also to last whitespace within substringRuby:子字符串到一定长度,也到子字符串中的最后一个空格
【发布时间】:2012-02-29 17:12:31
【问题描述】:

我正在尝试将一长串文本截断到一定长度,但还想确保截断的结果以空格结尾。之后我还要附加一个省略号。

例如:

"This is a very long string that has more characters than I want in it."

变成这样:

"This is a very long string that..."

我是从这个开始的,但显然这并不能解决以空格结束字符串的问题。

<%= item.description[0..30] %>&hellip;

【问题讨论】:

    标签: ruby string ruby-on-rails-4


    【解决方案1】:

    如果您使用的是 Rails 4+,您应该只使用内置的 truncate 辅助方法,例如:

    <%= truncate item.description, length: 30, separator: /\w+/ %>
    

    字符串“…”将被附加到截断的文本中;要指定不同的字符串,请使用 :omission 选项,例如omission: "xxx".

    对于 Rails 3.x,:separator 选项必须是字符串。在许多情况下,提供:separator =&gt; " " 会很好,但只会捕获空格而不是其他空格。一种折衷方案是使用String#squish,它将所有空格序列替换为单个空格(并且还修剪前导和尾随空格),例如"foo\n\tbar ".squish 产生 "foo bar"。它看起来像这样:

    <%= truncate item.description.squish, :length => 30, :separator => /\w/,
                                          :omission => "&hellip;" %>
    

    【讨论】:

    • 我认为您不能在分隔符参数中使用正则表达式
    • 我使用的是 rails 3.2.13 并且 Regexp 不应该用作分隔符。 NoMethodError: /\w/:Regexp 的未定义方法“mb_chars”
    • 我更新了答案,添加了一些关于在 Rails 3.x 中使用 truncate 的注释。
    【解决方案2】:
    s[0..30].gsub(/\s\w+\s*$/, '...')
    

    在 30 个字符的子字符串以空白字符结尾的情况下,原始答案不起作用。这样就解决了。

    >> desc="This is some text it is really long"
    
    >> desc[0..30].gsub(/\s\w+$/,'...')
    "This is some text it is really "
    
    >> desc[0..30].gsub(/\s\w+\s*$/,'...')
    "This is some text it is..."
    

    【讨论】:

    • 感谢您的纯红宝石回答!完美运行。
    • 这不是大多数人想要的。无论字符串实际上是否超过 30 个字符,它都会添加省略号。
    • 这个答案也无缘无故地抛出了最后一句话,即使没有必要。字符串“This is some text it is really...”不是更令人期待的结果吗?
    • 三个句点与省略号不同。请尽可能使用 Unicode 省略号字符,而不是三个句点。
    【解决方案3】:

    @evfwcqcg 的回答非常好。我发现它在

    1. 字符串包含其他非空格非字母数字字符。
    2. 字符串比所需长度短。

    演示:

    >> s = "How about we put some ruby method Class#Method in our string"
    => "How about we put some ruby method Class#Method in our string"
    >> s[0..41].gsub(/\s\w+\s*$/, '...')
    => "How about we put some ruby method Class#Me"
    >> s[0..999].gsub(/\s\w+\s*$/, '...')
    => "How about we put some ruby method Class#Method in our..."
    

    这不是我所期望的。

    这是我用来解决此问题的方法:

    def truncate s, length = 30, ellipsis = '...'
      if s.length > length
        s.to_s[0..length].gsub(/[^\w]\w+\s*$/, ellipsis)
      else
        s
      end
    end
    

    进行测试时,输出如下:

    >> s = "This is some text it is really long"
    => "This is some text it is really long"
    >> truncate s
    => "This is some text it is..."
    

    仍按预期运行。

    >> s = "How about we put some ruby method Class#Method in our string"
    => "How about we put some ruby method Class#Method in our string"
    >> truncate s, 41
    => "How about we put some ruby method Class..."
    >> truncate s, 999
    => "How about we put some ruby method Class#Method in our string"
    

    这更像。

    【讨论】:

    • 虽然这比@evfwcqcg 的回答要好,但我仍然不知道你为什么要拿出最后一句话,即使它符合极限。在你的例子中 - 为什么你看到文本“这是一些文本它是”当“这是一些文本它真的”有 30 个字符并且它也以空格结尾时看到的结果。
    • @gorn 因为一旦添加省略号,它将超过 30 个字符。当然,如果省略号的长度超过最后一个单词的长度,那么它无论如何都会超过 30 个字符。但在大多数情况下,省略号是“...”,如果最后一个单词是 1 个字符,它只会超过 30,我认为这不会经常发生。您有什么建议可以让这变得更好吗?
    • 我知道它“在大多数情况下都有效”,所以我的咆哮具有更多的学术价值而不是实际价值,但当我看到“不正确”的代码时就是这样。对于那个很抱歉。我已经发布了一个解决方案作为单独的答案,因为评论太长了。随意在那里添加您的想法。
    • 如果您使用 Unicode 省略号字符,省略号只有一个字符长。请做。
    【解决方案4】:
    desc.gsub(/([\w\s]{30}).+/,'\1...')
    

    扩展@evfwcqcg 的答案,这是一个解决尾随空格问题的纯正则表达式。

    irb(main):031:0> desc="This is some text it is really long"
    irb(main):033:0> desc.gsub(/([\w\s]{30}).+/,'\1...')
    => "This is some text it is really..."
    irb(main):034:0> desc="This is some text it is really"
    => "This is some text it is really"
    irb(main):035:0> desc.gsub(/([\w\s]{30}).+/,'\1...')
    => "This is some text it is really"
    irb(main):036:0> desc="This is some text it is real"
    => "This is some text it is real"
    irb(main):037:0> desc.gsub(/([\w\s]{30}).+/,'\1...')
    => "This is some text it is real"
    

    【讨论】:

    • 这是完全错误的解决方案。如果您尝试使用原始字符串“这是一个非常长的字符串,其中包含的字符比我想要的多。”比你得到“这是一个很长的字符串...”...
    【解决方案5】:

    令我惊讶的是,没有一个答案是真正正确的(或受使用 rails helper 的限制),尽管这是一个非常古老的问题,所以这里是解决方案。

    让我们首先明确制定目标。我们希望将字符串 s 截断为 30 个字符,并在最后一个单词不能完全放入时将其删掉。如果文本被缩短,我们还希望从结果中截断尾随空格并添加省略号。

    如果文本比限制长,那么缩短就那么容易

    s[0,s.rindex(/\s/,30)].rstrip + '...'
    

    如果我们希望整个结果最多包含 30 个字符,那么它就像从 30 中减去椭圆的长度一样简单。所以因为我们使用了三个点(而不是一个三点字符)而不是我们需要的

    s[0,s.rindex(/\s/,27)].rstrip + '...'
    

    最后的结果(测试我们是否需要截断)是:

    if s.length<=30
      s
    else
      s[0,s.rindex(/\s/,27)].rstrip + '...'
    end
    

    就是这样。


    注意:当期望的结果不明显时,有一些可疑的情况。他们在这里:

    • 如果字符串以大量空格结尾 (s= "Helo word ") 但小于 30。是否应保留空格? - 目前是。
    • 与上述相同,但末尾的空格超过了 30 个限制。如 (s= "Twentyseven chars long text ") - 目前所有结尾的空格都被截断并添加省略号。

    【讨论】:

      【解决方案6】:
      class String
        def trunca(length=100, ellipsis='...')
          self.length > length ? self[0..length].gsub(/\s*\S*\z/, '').rstrip+ellipsis : self.rstrip
        end
      end
      

      例子:

      -bash> irb
      2.0.0p247 :001 > class String
      2.0.0p247 :002?>     def trunca(length=100, ellipsis='...')
      2.0.0p247 :003?>         self.length > length ? self[0..length].gsub(/\s*\S*\z/, '').rstrip+ellipsis : self.rstrip
      2.0.0p247 :004?>       end
      2.0.0p247 :005?>   end
       => nil 
      2.0.0p247 :006 > s = "This is a very long string that has more characters than I want to display."
       => "This is a very long string that has more characters than I want to display." 
      2.0.0p247 :007 > s.trunca(20)
       => "This is a very long..." 
      2.0.0p247 :008 > s.trunca(31)
       => "This is a very long string that..." 
      

      【讨论】:

      • 我认为第一个 rstrip 是不必要的。
      • self[0..length] 将返回长度+1 个字符。
      猜你喜欢
      • 2019-08-16
      • 2013-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-28
      • 1970-01-01
      • 2021-02-09
      相关资源
      最近更新 更多