Каков канонический способ обрезки строки в Ruby без создания новой строки?

182

Это то, что я имею сейчас - это выглядит слишком многословно для работы, которую он делает.

@title        = tokens[Title].strip! || tokens[Title] if !tokens[Title].nil?

Предположим, токены - это массив, полученный путем разбиения строки CSV. теперь функции как полоса! грызть! и др. все возвращают ноль, если строка не была изменена

"abc".strip!    # => nil
" abc ".strip!  # => "abc"

Как Ruby может сказать обрезать его, если он содержит дополнительные начальные или конечные пробелы без создания копий?

Становится хуже, если я хочу сделать tokens[Title].chomp!.strip!

Gishu
источник
3
Если вы собираетесь многократно читать вещи из токенов, возможно, имеет смысл предварительно обработать их. То есть "tokens.each {| t | t.strip!}". тогда вы можете просто сделать "@title = tokens [Title] || ''"
Гленн Макдональд

Ответы:

272

Я думаю, что вы хотите, это:

@title = tokens[Title]
@title.strip!

#strip!Метод будет возвращать , nilесли он ничего не раздеться, а сама переменная , если она была лишена.

Согласно стандартам Ruby, метод с суффиксом с восклицательным знаком изменяет переменную на месте.

Надеюсь это поможет.

Обновление: это выходные данные irbдля демонстрации:

>> @title = "abc"
=> "abc"
>> @title.strip!
=> nil
>> @title
=> "abc"
>> @title = " abc "
=> " abc "
>> @title.strip!
=> "abc"
>> @title
=> "abc"
Игорь
источник
1
Хм .. все же я думаю, что @title = tokens [Title] .strip! выглядит чище - жаль, что он возвращает ноль вместо неизмененной строки. Если кто-то не публикует лучший ответ ... вы получаете признанный бит.
Гишу
7
Ну, @title = tokens [Title] .strip добьются цели, но вместо этого у вас будет копия, и это хорошо, если вы оставите переменную tokens [Title] без изменений.
Игорь
9
В Ruby 1.9 есть тап, который делает именно то, что вы хотите: @ title.tap {| x | x.strip!}
Тимкай
2
@timkay Возможно ли это сделать @title.tap &:strip!? Это кажется чище, чем все остальное.
Джон Эгеланн
16
Почему в мире это вернулось бы, nilесли бы оно ничего не раздевало? Это, без сомнения, смутило тонну людей (поскольку это не имеет смысла).
Джош М.
53

Кстати, теперь ruby ​​уже поддерживает просто полосу без "!".

Для сравнения:

p "abc".strip! == " abc ".strip!  # false, because "abc".strip! will return nil
p "abc".strip == " abc ".strip    # true

Также невозможно stripбез дубликатов. Смотрите источники в string.c:

static VALUE
rb_str_strip(VALUE str)
{
    str = rb_str_dup(str);
    rb_str_strip_bang(str);
    return str;
}

ruby 1.9.3p0 (2011-10-30) [i386-mingw32]

Обновление 1: как я вижу сейчас - он был создан в 1999 году (см. Rev # 372 в SVN):

Update2: strip!не будет создавать дубликаты - как в версии 1.9.x, 2.x, так и в транке.

gaRex
источник
1
«невозможно раздеть без дубликатов» - конечно, это возможно, вот для чего strip!.
Кароли Хорват 17
@KarolyHorvath не видите исходный код, написанный на C? Просьба внимательно прочитать, что я написал здесь относительно дубликатов.
gaRex
1
Конечно я это вижу. Но это исходный код strip. Я что-то неправильно понимаю? Как еще я могу интерпретировать «невозможно раздеть без дубликата»?
Кароли Хорват
@KarolyHorvath внутренне дубликат всегда создается. Это примерно строка `str = rb_str_dup (str);`
gaRex
1
И если вы не хотите дубликат, вы используете strip!ака rb_str_strip_bang.
Кароли Хорват
9

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

Ответ Олли уже имеет канонический способ сделать это в Ruby, хотя, если вы делаете это часто, вы всегда можете определить метод для этого:

def strip_or_self!(str)
  str.strip! || str
end

Предоставление:

@title = strip_or_self!(tokens[Title]) if tokens[Title]

Также имейте в виду, что оператор if будет препятствовать @titleназначению, если токен равен nil, что приведет к тому, что он сохранит свое предыдущее значение. Если вы хотите или не возражаете против того, @titleчтобы вас всегда назначили, вы можете перенести проверку в метод и еще больше уменьшить дублирование:

def strip_or_self!(str)
  str.strip! || str if str
end

В качестве альтернативы, если вы чувствуете себя предприимчивым, вы можете определить метод для самой String:

class String
  def strip_or_self!
    strip! || self
  end
end

Предоставление одного из:

@title = tokens[Title].strip_or_self! if tokens[Title]

@title = tokens[Title] && tokens[Title].strip_or_self!

источник
9

Если вы используете Ruby on Rails, есть слабость

> @title = " abc "
 => " abc " 

> @title.squish
 => "abc"
> @title
 => " abc "

> @title.squish!
 => "abc"
> @title
 => "abc" 

Если вы используете только Ruby, вы хотите использовать полосу

В этом и заключается ошибка ... в вашем случае вы хотите использовать полосу без взрыва!

пока раздевайся! конечно, возвращает ноль, если не было никаких действий, он все равно обновляет переменную, так что удалите! не может быть использован inline. Если вы хотите использовать strip inline, вы можете использовать версию без преувеличения!

полоса! используя многострочный подход

> tokens["Title"] = " abc "
 => " abc "
> tokens["Title"].strip!
 => "abc"
> @title = tokens["Title"]
 => "abc"

Стрип однострочный подход ... ВАШ ОТВЕТ

> tokens["Title"] = " abc "
 => " abc "
> @title = tokens["Title"].strip if tokens["Title"].present?
 => "abc"
gateblues
источник
4

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

@title = tokens[Title].strip! || tokens[Title] if tokens[Title]

Альтернативно вы можете поставить его на две строки:

@title = tokens[Title] || ''
@title.strip!
Olly
источник
3

Если вы хотите использовать другой метод после того, как вам нужно что-то вроде этого:

( str.strip || str ).split(',')

Таким образом, вы можете раздеться и сделать что-нибудь после :)

Диого Невес - Мангару
источник
1

Мой путь:

> (@title = " abc ").strip!
 => "abc" 
> @title
 => "abc" 
Hauleth
источник
1

Если у вас есть ruby ​​1.9 или activesupport, вы можете просто

@title = tokens[Title].try :tap, &:strip!

Это действительно здорово, так как он использует :tryи :tapметод, которые являются наиболее мощные функциональные конструкции в рубин, на мой взгляд.

Четная милая форма, передавая функции в целом как символы:

@title = tokens[Title].send :try, :tap, &:strip!
переписан
источник
-1
@title = tokens[Title].strip! || tokens[Title]

Вполне возможно, я не понимаю тему, но разве это не сделает то, что вам нужно?

" success ".strip! || "rescue" #=> "success"
"failure".strip! || "rescue" #=> "rescue"
казарка
источник