2012-02-29 38 views
28

我想截断一长串文本到一定的长度,但也想确保截断的结果在空白处结束。之后我也会追加一个省略号。Ruby:子字符串到一定的长度,也可以在子字符串中留下空白

例如这样的:

"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; 

回答

36
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..." 
+0

感谢您的纯红宝石答案!完美工作。 – 2012-02-29 17:28:30

+2

这不是大多数人想要的。无论字符串是否超过30个字符,它都会添加省略号。 – gamut 2016-03-29 13:12:22

+0

此外,这个答案没有理由抛出最后一个词,即使它没有必要。不要成为字符串“这是一些文本,它真的......”是更有预期的结果吗? – gorn 2016-10-06 20:39:44

34

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

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

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

对于Rails 3.x,:separator选项必须是字符串。在很多情况下,给予:separator => " "会很好,但只能捕获空格而不捕获其他空格。一个妥协是使用String#squish,它用单个空间替换所有空白序列(并且还修剪前导和尾随空白),例如, "foo\n\tbar ".squish收率为"foo bar"。它看起来像这样:

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

我正在使用rails。谢谢,那就是诀窍。 – 2012-02-29 17:26:01

+0

我不认为你可以在分隔符参数中使用正则表达式 – fearofawhackplanet 2013-07-14 17:15:37

+0

我正在使用rails 3.2.13,并且正则表达式不适用于分隔符。 NoMethodError:未定义的方法'mb_chars'为/ \ w /:Regexp – roychri 2013-09-04 00:55:23

7

@ 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" 

这更像是它。

+0

尽管这比@ evfwcqcg的答案还要好,但我不知道为什么你要拿出最后一个字,即使它符合极限。在你的例子中 - 为什么你看到文本“这是一些文本”,因为当“这是一些文本时它真的”有30个字符,并且它以空格结尾。 – gorn 2016-10-06 20:51:37

+0

@gorn因为一旦你添加了省略号,它会超过30个字符。当然,如果省略号的长度超过最后一个字的长度,反正它将超过30个字符。但在大多数情况下,省略号为“...”,如果最后一个字是1个字符,它只会超过30个字符,我认为这种情况不会经常发生。你有什么建议可以让这个更好吗? – roychri 2016-10-07 02:09:48

+0

我知道它会“在大多数情况下工作”,所以我的咆哮比实际价值更具学术性,但是当我看到“不正确”的代码时,就是这样。对于那个很抱歉。我已经发布了一个解决方案作为单独的答案,因为它太长了评论。随意在那里添加你的想法。 – gorn 2016-10-07 08:12:04

0
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..." 
+1

省略号的长度是多少? '123 456'.trunca(4).length => 6,而不是4 ... – 2015-03-23 07:12:25

+0

我认为第一个rstrip不是必须的。 – gorn 2016-10-06 21:39:04

1
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" 
+0

这显然是错误的解决方案。如果您尝试使用原始字符串“这是一个非常长的字符串,其字符数超过了我想要的字符数”。比你得到“这是一个很长的字符串......”... – gorn 2016-10-06 20:56:22

0

我很惊讶,没有一个答案是正确的真(或使用轨道帮手限制),虽然这是很老的问题,所以这里是解决方案。

让我们清楚地阐述它的目标是什么。我们希望将字符串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应该较短的空间会保留吗? - 目前他们是。
  • 与上面相同,但末尾的空格跨越限制o 30.与(s= "Twentyseven chars long text ")类似 - 当前所有空格和结尾都被截断并添加了省略号。
相关问题