如何中心截断字符串?

时间:2009-09-20 16:22:44

标签: ruby-on-rails ruby

有没有人有任何代码方便中心在Ruby on Rails中截断字符串?

这样的事情: 例如:“Hello World,你好吗?” => “赫尔......你呢?”

13 个答案:

答案 0 :(得分:27)

如果您想要一定的固定长度而不管字符串的长度,您可以使用Rails #truncate

s.truncate(100, omission: "...#{s.last(50)}")

答案 1 :(得分:13)

正则表达式版本怎么样:

class String
  def ellipsisize
    gsub(/(...).{4,}(...)/, '\1...\2')
  end
end

"abc".ellipsisize #=> "abc"
"abcdefghi".ellipsisize #=> "abcdefghi"
"abcdefghij".ellipsisize #=> "abc...hij"

编辑:正如评论中所建议的,参数化长度(并使用不同的正则表达式,只是为了它)

class String
  def ellipsisize(len = 9)
    len = 9 unless len > 9 # assumes minimum chars at each end = 3
    gsub(%r{(...).{#{len-5},}(...)}, '\1...\2')
  end
end

所以...

"abcdefghij".ellipsisize #=> "abc...hij"

但我们也可以:

"abcdefghij".ellipsisize(10) #=> "abcdefghij"

答案 2 :(得分:10)

这是Mike Woodhouse的答案的修改版本。它需要2个可选参数:字符串被省略的最小长度和边长。

class String
  def ellipsisize(minimum_length=4,edge_length=3)
    return self if self.length < minimum_length or self.length <= edge_length*2 
    edge = '.'*edge_length    
    mid_length = self.length - edge_length*2
    gsub(/(#{edge}).{#{mid_length},}(#{edge})/, '\1...\2')
  end
end


"abc".ellipsisize #=> "abc"
"abcdefghi".ellipsisize #=> "abcdefghi"
"abcdefghij".ellipsisize #=> "abc...hij"
"abcdefghij".ellipsisize(4,4) #=> "abcd...ghij"
"Testing all paramas and checking them!".ellipsisize(6,5) #=> "Testi...them!"

答案 3 :(得分:5)

由于您没有指定要截断的字符数,因此我假设(从您的示例中)您要截断长度大于6的字符串。然后你可以使用这样的东西:

s = "Hello World, how are you?"
s = s[0, 3] + "..." + s[-3, 3] if s.length > 9
=> "Hel...ou?"

如果您需要截断更多字符,只需调整范围即可。

答案 4 :(得分:5)

这是我的建议:

s[3...-4] = "..." if s.length > 9

答案 5 :(得分:3)

class String
  # https://gist.github.com/1168961
  # remove middle from strings exceeding max length.
  def ellipsize(options={})
    max = options[:max] || 40
    delimiter = options[:delimiter] || "..."
    return self if self.size <= max
    remainder = max - delimiter.size
    offset = remainder / 2
    (self[0,offset + (remainder.odd? ? 1 : 0)].to_s + delimiter + self[-offset,offset].to_s)[0,max].to_s
  end unless defined? ellipsize
end

答案 6 :(得分:1)

另一种方式:

class String
  def middle_truncate(len)
    return self if len >= size
    return self[0...len] unless len > 4
    half = len / 2.0
    (result = dup)[(half - 1.5).floor...(1.5 - half).floor] = '...'
    result
  end
end

这有一个额外的好处,就是截断字符串大小&lt; 5。

e.g。对于一个大小合适的字符串:

2.1.1 :001 > s = "12345678901234567890"
 => "12345678901234567890" 
2.1.1 :002 > s.middle_truncate 21
 => "12345678901234567890" 
2.1.1 :003 > s.middle_truncate 20
 => "12345678901234567890" 
2.1.1 :004 > s.middle_truncate 19
 => "12345678...34567890" 
2.1.1 :005 > s.middle_truncate 18
 => "1234567...34567890" 
2.1.1 :006 > s.middle_truncate 5
 => "1...0" 
2.1.1 :007 > s.middle_truncate 4
 => "1234" 

和奇数大小的字符串:

2.1.1 :012 > s = "123456789012345678901"
 => "123456789012345678901" 
2.1.1 :013 > s.middle_truncate 22
 => "123456789012345678901" 
2.1.1 :014 > s.middle_truncate 21
 => "123456789012345678901" 
2.1.1 :015 > s.middle_truncate 20
 => "12345678...345678901" 
2.1.1 :016 > s.middle_truncate 19
 => "12345678...45678901" 
2.1.1 :017 > s.middle_truncate 5
 => "1...1" 
2.1.1 :018 > s.middle_truncate 4
 => "1234" 

答案 7 :(得分:0)

我为grosser的方法添加了位置选项:

def ellipsize(str, options={})
  max = options[:max] || 40
  delimiter = options[:delimiter] || "..."
  position =  options[:position] || 0.8
  return str if str.size <= max
  remainder = max - delimiter.size
  offset_left = remainder * position
  offset_right = remainder * (1 - position)
  (str[0,offset_left + (remainder.odd? ? 1 : 0)].to_s + delimiter + str[-offset_right,offset_right].to_s)[0,max].to_s
end

答案 8 :(得分:0)

如果您需要按字节大小限制字符串长度,并且需要处理unicode,那么列出的解决方案将无法正常工作。

这是一个使用字节大小并保持unicode 文本元素完整的解决方案(它们并不总是与unicode 字符相同)。在Ruby 1.8 / 1.9 / 2.0中测试。

对于需要截断到更小长度的非常长的字符串,可以进行改进。

您必须安装unicode gem。

require 'unicode'

# truncates a unicode string like:
#   >> truncate_string_middle('12345678', 5)
#   => "1...8"
def truncate_string_middle(str, limit, ellipsis='...')
  raise "limit (#{limit}) must not be less than the ellipsis size (#{ellipsis.bytesize})" if limit < ellipsis.bytesize

  return str if str.bytesize <= limit

  chars = Unicode.text_elements(str)
  split_point = (chars.size/2.0).ceil
  front, back = chars[0...split_point], chars[split_point..-1]

  pop_front = chars.size.odd?
  # alternate between popping from the front and shifting from the back until it's small enough
  while (front.join + ellipsis + back.join).bytesize > limit
    if pop_front
      front.pop
    else
      back.shift
    end
    pop_front = !pop_front
  end

  front.join + ellipsis + back.join
end

答案 9 :(得分:0)

这对我来说是最简单的方式:

def ellipsisize(text, minimum_length=12,edge_length=4)
  leftover = text.length - minimum_length
  edge_length = leftover if (edge_length > leftover && leftover >= 0)
  edge_length = 0 if leftover < 0

  return text.truncate(minimum_length) << text.last(edge_length)
end

关心大家!

答案 10 :(得分:0)

仅从中间截断的修改过的rails版本

def middle_truncate(str, total: 30, lead: 15, trail: 15)
  str.truncate(total, omission: "#{str.first(lead)}...#{str.last(trail)}")
end

答案 11 :(得分:0)

本杰明·沙利文和凯勒尔的答案的结合。使用内置的Rails素材,让您定义边缘长度。

对于String#truncate,我认为根本不需要定义最小长度。如果缩短的版本比输入的字符串短,此解决方案将自动缩短字符串。

def ellipsize(string, edge_length, separator: '…')
  string.truncate(
    edge_length * 2 + separator.size, omission: "#{separator}#{string.last(edge_length)}"
  )
end

答案 12 :(得分:0)

这是我的版本,可让您指定最大长度,因此,可以确保字符串不超过所需长度:

class String
    def truncate(maximum_length = 3, separator = '…')
        return '' if maximum_length.zero?
        return self if self.length <= maximum_length

        middle_length = self.length - maximum_length + separator.length
        edges_length = (self.length - middle_length) / 2.0
        left_length = edges_length.ceil
        right_length = edges_length.floor

        left_string = left_length.zero? ? '' : self[0, left_length]
        right_string = right_length.zero? ? '' : self[-right_length, right_length]

        return "#{left_string}#{separator}#{right_string}"
    end
end
'123456'.truncate(0) # ""
'123456'.truncate(1) # "…"
'123456'.truncate(2) # "1…"
'123456'.truncate(3) # "1…6"
'123456'.truncate(4) # "12…6"
'123456'.truncate(5) # "12…56"
'123456'.truncate(6) # "123456"
'123456'.truncate(7) # "123456"