Ruby: подстрока определенной длины, а также последний пробел в подстроке - PullRequest
32 голосов
/ 29 февраля 2012

Я пытаюсь обрезать длинную строку текста до определенной длины, но хочу также убедиться, что усеченный результат заканчивается пробелом. Я также собираюсь добавить многоточие потом.

Например, это:

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

Ответы [ 6 ]

41 голосов
/ 29 февраля 2012

Если вы используете Rails 4+, вы должны просто использовать встроенный вспомогательный метод truncate, например:

<%= 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;" %>
40 голосов
/ 29 февраля 2012
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..."
7 голосов
/ 04 сентября 2013

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

Это больше похоже на это.

3 голосов
/ 18 мая 2016
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"
1 голос
/ 07 октября 2016

Я удивлен, что ни один из ответов не является действительно правильным (или ограничен использованием 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. Следует ли сохранять пробелы? - В настоящее время они.
  • То же, что и выше, но пробелы в конце пересекают предел o 30. Как и в (s= "Twentyseven chars long text ") - в настоящее время все пробелы до конца обрезаны и добавлены многоточие.
0 голосов
/ 18 апреля 2014
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..." 
...