Есть ли у кого-нибудь удобный код, который обрезает строку в Ruby on Rails?
Что-то вроде этого: Пример: "Привет, мир, как дела?" = > "Хелл... ты?"
Есть ли у кого-нибудь удобный код, который обрезает строку в Ruby on Rails?
Что-то вроде этого: Пример: "Привет, мир, как дела?" = > "Хелл... ты?"
Вот измененная версия ответа Майка Вудхауса. Он принимает 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!"
Если вам нужна определенная фиксированная длина независимо от длины строки, вы можете использовать Rails #truncate
:
s.truncate(100, omission: "...#{s.last(50)}")
Как насчет версии Regex:
class String
def ellipsisize
gsub(/(...).{4,}(...)/, '\1...\2')
end
end
"abc".ellipsisize #=> "abc"
"abcdefghi".ellipsisize #=> "abcdefghi"
"abcdefghij".ellipsisize #=> "abc...hij"
EDIT: как предложено в комментариях, параметризованная длина (и использование другой нотации Regex, только для нее)
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"
Поскольку вы не указали, сколько символов вы хотите усечь, я предположим (из вашего примера), что вы хотите усечь строки, длина которых больше шести. Затем вы можете использовать что-то вроде этого:
s = "Hello World, how are you?"
s = s[0, 3] + "..." + s[-3, 3] if s.length > 9
=> "Hel...ou?"
Просто адаптируйте диапазоны, если вам нужно усечь больше символов.
Вот мое предложение:
s[3...-4] = "..." if s.length > 9
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
Другой способ:
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
Это имеет дополнительное преимущество просто усечения, если размер строки < 5.
например. для строки с четным размером:
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"
Я добавил параметр позиции для более грубого метода:
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
Если вам нужно ограничить длину строки байтитом, и вам нужно обработать unicode, то перечисленные решения будут работать некорректно.
Здесь решение, которое использует размер байта и сохраняет текстовые элементы unicode неповрежденными (которые не всегда совпадают с символами Unicode). Протестировано в Ruby 1.8/1.9/2.0.
Это может быть улучшено, чтобы быть более эффективным для очень длинных строк, которые нужно усекать до гораздо меньшей длины.
Необходимо установить жук Unicode.
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 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
Это самый простой способ для меня:
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
С уважением, ребята!
Модифицированная версия рельсов, которая только усечена из середины
def middle_truncate(str, total: 30, lead: 15, trail: 15)
str.truncate(total, omission: "#{str.first(lead)}...#{str.last(trail)}")
end
Сочетание ответов Бенджамина Салливана и Хеллла. Использует встроенный Rails материал и позволяет вам определять длину ребра.
def ellipsize(string, edge_length, separator: '…')
string.truncate(
edge_length * 2 + separator.size, omission: "#{separator}#{string.last(edge_length)}"
)
end