Я написал классический код fizzbuzz.

Спецификация:

describe "can determine fizzbuxx output for" do
  it "3" do
    expect(Fizzbuzz.nums(3)).to eq "123fizz"
  end 
end

Код:

class Fizzbuzz
  def self.nums(n)
    result=""
    (1..n).each do |inner|
      puts "inner #{inner}"
      result << inner
      if (inner % 3)==0
        result << 'fizz'
      end
      if (inner % 5)==0
        result << 'buzz'
      end
    end
    result
  end
end

Почему я получаю \u001 ... вместо 1?

Failures:

1) can determine fizzbuxx output for 3
 Failure/Error: expect(Fizzbuzz.nums(3)).to eq "123fizz"

   expected: "123fizz"
        got: "\u0001\u0002\u0003fizz"

   (compared using ==)
 # ./fizzbuzz_spec.rb:5:in `block (2 levels) in <top (required)>'

Это какая-то проблема с utf-8?

1
Michael Durrant 16 Окт 2014 в 16:27

3 ответа

Лучший ответ

В Ruby для строки concatenation: <<, если объект является целым числом, он рассматривается как кодовая точка и преобразуется в символ перед объединением. А поскольку в Ruby 1.9 кодировка по умолчанию - UTF-8. Кодовые точки принудительно кодируются с помощью UTF-8:

1.chr(Encoding::UTF_8)
# => "\u0001"

Итак, когда вы это делаете:

"" << 1

На самом деле Ruby рассматривает 1 как кодовую точку и пытается преобразовать его в строку с кодировкой UTF-8, и на самом деле делает это вместо этого:

"" << 1.chr(Encoding::UTF_8)
#=> "\u0001"

Итак, чтобы решить вашу проблему. Вы можете явно преобразовать Fixnum в String, изменив код на:

result << inner.to_s

Или со строковой интерполяцией:

result << "#{inner}"
3
Surya 16 Окт 2014 в 13:03

Это ожидаемое поведение метода String#<<. Из документации Ruby:

Объединяет данный объект в str. Если объект является целым числом, он рассматривается как кодовая точка и преобразуется в символ перед объединением.

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

'' << 1 # => "\u0001"
'' << 1.to_s => "1"
3
toro2k 16 Окт 2014 в 12:49

Для малых чисел их тип - FixNum [содержит целочисленные значения, которые может быть представлен в машинном слове (минус 1 бит). ]

result << inner

Явно преобразуйте его в String, и вы получите желаемый результат.

result << inner.to_s
0
Jeff Price 16 Окт 2014 в 12:46