Как работать с ведущими нулями в целых числах

Как правильно работать с ведущими нулями в Ruby?

0112.to_s
 => "74"
0112.to_i
 => 74

Почему он преобразует 0112 в 74?

Как преобразовать 0112 в строку "0112"?


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

Но это не работает для меня, когда у меня есть ведущие нули:

def descending_order(n)
  n.to_s.reverse.to_i
end

person Joel    schedule 16.02.2015    source источник


Ответы (2)


Числовой литерал, который начинается с 0, является восьмеричным представлением, за исключением литералов, начинающихся с 0x, которые представляют шестнадцатеричные числа, или 0b, которые представляют двоичные числа.

1 * 8**2 + 1 * 8**1 + 2 * 8**0 == 74

Чтобы преобразовать его в 0112, используйте String#% или Kernel#sprintf с соответствующей строкой формата:

'0%o' % 0112  # 0: leading zero, %o: represent as an octal
# => "0112"
person falsetru    schedule 16.02.2015
comment
это было быстро и очень правдиво! - person Anthony; 16.02.2015
comment
@falsetru спасибо за быстрый ответ. Как я могу учесть это для метода, который хочет перевернуть число, чтобы оно было в порядке убывания? - person Joel; 16.02.2015
comment
@JoelL, ты имеешь в виду что-то вроде этого? '0112'.chars.sort.reverse.join. Если это так, преобразуйте число в строку, используя способ, указанный в ответе, затем the_string_object.chars.sort.reverse.join.to_i - person falsetru; 16.02.2015
comment
@falsetru Я хочу иметь возможность ввести любое число в метод, описанный выше, и изменить его. Так, например, descending_order(0112) и вернуть 2110 - person Joel; 16.02.2015
comment
@JoelL, в зависимости от ваших потребностей вы можете просто: the_string_object.reverse (если вы не имели в виду сортировку цифр) - person falsetru; 16.02.2015
comment
@JoelL, пожалуйста, перечитайте мой ответ. 0112 == 74 == 0x4a == 0b1001010. Лучше использовать строку вместо числа. - person falsetru; 16.02.2015
comment
@falsetru извини. Я не уверен, что правильно сформулировал. Я хочу взять любое целое число и вернуть его с цифрами в порядке убывания. Даже если в нем есть лизинговые нули. Спасибо еще раз - person Joel; 16.02.2015
comment
@JoelL, ('0%o' % number).reverse или ``('0%o' % number).reverse.to_i`, они будут работать только в том случае, если используется переданное восьмеричное представление. А второй эффективно удалит конечные нули из исходного числа. - person falsetru; 16.02.2015
comment
@JoelL, вызываемая функция не может знать, как вызвал вызывающий абонент (восьмерично, десятично, ....) - person falsetru; 16.02.2015
comment
@JoelL, Другими словами, как вызываемая функция не может различить 0112, 74, 0x4a, 0b1001010. В конце концов, они все равноценны. - person falsetru; 16.02.2015
comment
Давайте продолжим обсуждение в чате. - person Joel; 16.02.2015

Вы не можете, потому что класс Ruby Integer не хранит ведущие нули.

Начальный 0 в числовом литерале интерпретируется как префикс:

  • 0 и 0o: восьмеричное число
  • 0x: шестнадцатеричное число
  • 0b: двоичное число
  • 0d: десятичное число

Это позволяет вам вводить числа в эти базы. Парсер Ruby преобразует литералы в соответствующие Integer экземпляры. Префикс или ведущие нули отбрасываются.

Другой пример — %w для ввода массивов:

ary = %w(foo bar baz)
#=> ["foo", "bar", "baz"]

Невозможно получить %w от ary. Синтаксический анализатор превращает литерал в экземпляр массива, поэтому сценарий никогда не видит литерал.

0112 (или 0o112) интерпретируется (парсером) как восьмеричное число 112 и превращается в целое число 74.

Десятичное число 0112 — это всего лишь 112, независимо от того, сколько нулей вы поставили перед ним:

0d0112   #=> 112
0d00112  #=> 112
0d000112 #=> 112

Это похоже на дополнительные конечные нули для чисел с плавающей запятой:

1.0   #=> 1.0
1.00  #=> 1.0
1.000 #=> 1.0

Вероятно, вам придется использовать строку, например "0112"

Другой вариант — явно указать (минимальную) ширину, например:

def descending_order(number, width = 0)
  sprintf('%0*d', width, number).reverse.to_i
end

descending_order(123, 4)
#=> 3210

descending_order(123, 10)
#=> 3210000000
person Stefan    schedule 16.02.2015
comment
Целые числа в Ruby не имеют ведущих нулей. Я не уверен, что это правильный способ сказать это. Целые числа могут быть представлены в восьмеричном представлении с начальным знаком 0. Однако представление по умолчанию в десятичном формате. - person the Tin Man; 16.02.2015
comment
@Стефан, спасибо за ваш ответ. Можно ли определить метод, который принимает любое целое число и просто возвращает числа в порядке убывания, не зная, сколько цифр оно содержит? - person Joel; 16.02.2015
comment
@JoelL нет, обращение 321000 дает 123, нули теряются. Класс Ruby Integer не может хранить ведущие нули. - person Stefan; 16.02.2015
comment
@theTinMan спасибо, я изменил предложение. Я хотел указать, что есть разница между числовым литералом и экземпляром Integer. - person Stefan; 16.02.2015
comment
Ах, да, определенно есть разница между литералом и целым числом. - person the Tin Man; 16.02.2015
comment
@JoelL, я думаю, вы не понимаете, что Руби видит 0123 и превращает его в 83 до того, как сценарий получает контроль. Вы не можете вводить буквенные значения в восьмеричной системе счисления и обращаться к ним как к чему-либо, кроме целого числа, что в этот момент уже слишком поздно для того, что вы хотите. Вместо этого вы ДОЛЖНЫ использовать некоторую форму строкового представления, которая не будет преобразована. '0123'.reverse # => "3210" например. - person the Tin Man; 16.02.2015
comment
@theTinMan это имеет смысл. Спасибо - person Joel; 16.02.2015
comment
Этот промежуточный шаг — это тот, который поймает всех нас хотя бы один раз. - person the Tin Man; 16.02.2015