Ruby: String больше не смешивается в Enumerable в 1.9. - PullRequest
4 голосов
/ 15 февраля 2010

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

'im a string meing!'.pop

Примечание: str.chop недостаточно ответа

Ответы [ 5 ]

10 голосов
/ 15 февраля 2010

Это не то, что перечисляемая строка обычно перечисляет. Является ли строка последовательностью ...

  • строки,
  • символов,
  • кодовые точки или
  • байт

Ответ: все те, любые из тех, или те, или ни те, в зависимости от контекста. Поэтому вы должны указать Ruby, какой из них вам нужен.

В классе String есть несколько методов, которые возвращают перечислители для любого из вышеперечисленных. Если вы хотите поведение до 1.9, ваш пример кода будет

'im a string meing!'.bytes.to_a.pop

Это выглядит некрасиво, но для этого есть причина: строка - это последовательность. Вы рассматриваете это как стек. Стек - это не последовательность, на самом деле она в значительной степени является противоположной последовательности.

2 голосов
/ 15 февраля 2010

Это не красиво :) 1001 *

Также #pop не является частью Enumerable, это часть Array.

Причина, по которой String не перечислима, состоит в том, что нет никаких «естественных» единиц для перечисления, должно ли это быть на символьной или строковой основе? Из-за этой строки нет # каждого

Вместо этого String предоставляет методы #each_char и #each_byte и #each_line для итерации по вашему выбору.

1 голос
/ 10 января 2013

String#slice! и String#insert значительно приблизят вас к тому, что вы хотите, без преобразования ваших строк в массивы.

Например, для имитации Array#pop вы можете сделать:

text = '¡Exclamation!'
mark = text.slice! -1

mark == '!'          #=> true
text                 #=> "¡Exclamation"

Аналогично, для Array#shift:

text = "¡Exclamation!"
inverted_mark = text.slice! 0

inverted_mark == '¡' #=> true
text                 #=> "Exclamation!"

Естественно, чтобы сделать Array#push, вы просто используете один из методов конкатенации:

text = 'Hello'
text << '!'          #=> "Hello!"
text.concat '!'      #=> "Hello!!"

Для имитации Array#unshift вместо этого вы используете String#insert, это очень похоже на инверсию среза:

text = 'World!'
text.insert 0, 'Hello, ' #=> "Hello, World!"

Вы также можете захватывать куски из середины строки несколькими способами с помощью среза.

Сначала вы можете передать начальную позицию и длину:

text = 'Something!'
thing = text.slice 4, 5

И вы также можете передать объект Range, чтобы получить абсолютные позиции:

text = 'This is only a test.'
only = text.slice (8..11)

В Ruby 1.9 использование String#slice подобно этому идентично String#[], но если вы используете метод взрыва String#slice!, он фактически удалит указанную вами подстроку.

text = 'This is only a test.'
only = text.slice! (8..12)
text == 'This is a test.'      #=> true

Вот немного более сложный пример, в котором мы переопределяем простую версию String#gsub! для поиска и замены:

text = 'This is only a test.'
search = 'only'
replace = 'not'

index = text =~ /#{search}/
text.slice! index, search.length
text.insert index, replace

text == 'This is not a test.'  #=> true

Конечно, в 99,999% случаев вы захотите использовать вышеупомянутый String.gsub!, который будет делать то же самое:

text = 'This is only a test.'
text.gsub! 'only', 'not' 

text == 'This is not a test.'  #=> true

ссылки:

1 голос
/ 15 февраля 2010
#!/usr/bin/ruby1.8

s = "I'm a string meing!"
s, last_char = s.rpartition(/./)
p [s, last_char]    # => ["I'm a string meing", "!"]

String.rpartition является новым для 1.9, но он был перенесен на 1.8.7. Он ищет в строке регулярное выражение, начиная с конца и работая в обратном направлении. Он возвращает часть строки до совпадения, совпадение и часть строки после совпадения (которое мы здесь отбрасываем).

1 голос
/ 15 февраля 2010

Так как вам не нравится str [str.length], как насчет

'im a string meing!'[-1]  # returns last character as a character value

или

'im a string meing!'[-1,1]  # returns last character as a string

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

class String
  def pop
    last = self[-1,1]
    self.chop!
    last
  end
end
...