Який канонічний спосіб обрізати рядок у Ruby без створення нової струни?


182

Це те, що я маю зараз - що виглядає занадто багатослівним для роботи, яку вона виконує.

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

Припустимо, лексеми - це масив, отриманий шляхом розщеплення лінії CSV. тепер такі функції, як смужка! шипшина! та ін. всі повертаються нульовими, якщо рядок не змінено

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

Який спосіб Ruby сказати обрізати його, якщо він містить додаткові провідні чи кінцеві пробіли без створення копій?

Стає гірше, якщо я хочу це зробити tokens[Title].chomp!.strip!


3
Якщо ви збираєтесь читати речі з лексем неодноразово, можливо, буде більше сенсу попередньо обробляти його. Тобто, "tokens.each {| t | t.strip!}". тоді ви можете просто зробити "@title = tokens [Назва] || ''"
glenn mcdonald

Відповіді:


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 = лексеми [Назва] .strip! виглядає чистіше - шкода, що він повертає нуль замість немодифікованого рядка. Якщо хтось не опублікує кращу анс .. ви отримаєте прийнятий біт.
Gishu

7
Що ж, @title = tokens [Title] .strip зробить трюк, але ви маєте натомість копію, що добре, якщо ви не зміните змінну маркера [Title].
Ігор

9
У Ruby 1.9 є кран, який робить саме те, що ви хочете: @ title.tap {| x | x.strip!}
темкай

2
@timkay Чи можна було б це зробити @title.tap &:strip!? Це здається чистішим за все інше.
Джон Егеланд

16
Чому у світі вона повернеться, nilякщо щось не позбавить? Це, без сумніву, збентежило тонну людей (оскільки це не має сенсу).
Джош М.

53

Btw, тепер рубін вже підтримує смужку без "!".

Порівняйте:

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

рубін 1.9.3p0 (2011-10-30) [i386-mingw32]

Оновлення 1: Як я бачу зараз - воно було створене в 1999 році (див. Рев. № 372 у SVN):

Update2: strip!не створить дублікатів - як у версіях 1.9.x, 2.x, так і в магістралі.


1
"неможливо зняти без дублікатів" - звичайно, це можливо, саме для чого strip!.
Каролі Хорват

@KarolyHorvath не знаєте, "ви бачите вихідний код, написаний на C? Прочитайте уважно, що я написав тут щодо дублікатів.
gaRex

1
Звичайно, я це бачу. Але це вихідний код strip. Я щось неправильно розумію? Як інакше я міг інтерпретувати "неможливе зняття без дублікатів"?
Каролі Хорват

Внутрішній дублікат @KarolyHorvath завжди створюється. Ось про рядок `str = rb_str_dup (str);`
gaRex

1
І якщо ви не хочете дубліката, ви використовуєте strip!ака rb_str_strip_bang.
Каролі Хорват

9

Не потрібно ні смуги, ні дзвінки, оскільки смуга також видалить кінцеві повернення каретки - якщо тільки ви не змінили роздільник записів за замовчуванням, і це те, що вам потрібно.

У відповіді Оллі вже є канонічний спосіб зробити це в Рубі, хоча якщо ви багато чого робите, ви завжди можете визначити метод для цього:

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

Давання:

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

Також пам’ятайте, що оператор if не дозволить @titleпризначити, якщо маркер нульовий, що призведе до збереження його попереднього значення. Якщо ви хочете або не заперечуєте, щоб це @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, ви можете використовувати версію без удару!

смужка! використовуючи багатолінійний підхід

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

4

Я думаю, що ваш приклад є розумним підходом, хоча ви можете трохи спростити його як:

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

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

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

3

Якщо ви хочете використовувати інший метод після того, як вам потрібно щось подібне:

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

Таким чином ви можете зняти і все одно щось робити після :)



1

Якщо у вас є рубін 1.9 або активна підтримка, ви можете це зробити просто

@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"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.