У техники работы с eval
есть свои «причуды». Например, будьте осторожны, вставляя управляющие последовательности, скажем
.
2.23. Разбор данных, разделенных запятыми
Данные, разделенные запятыми, часто встречаются при программировании. Это в некотором роде «наибольший общий делитель» всех форматов обмена данными. Например, так передаются данные между несовместимыми СУБД или приложениями, которые не поддерживают никакого другого общего формата.
Будем предполагать, что данные представляют собой строки и числа, а все строки заключены в кавычки. Еще предположим, что все символы должным образом экранированы (например, запятые и кавычки внутри строки).
Задача оказывается простой, поскольку такой формат данных подозрительно напоминает встроенные в Ruby массивы данных разных типов. Достаточно заключить все выражение в квадратные скобки, чтобы получить массив.
string = gets.chop!
#Предположим, что прочитана такая строка:
#'Doe, John', 35, 225, '5'10'', '555-0123'
data = eval('[' + string + ']') # Преобразовать в массив.
data.each {|x| puts 'Значение = #{x}'}
Этот код выводит такой результат:
Значение = Doe, John
Значение =35
Значение =225
Значение = 5' 10'
Значение = 555-0123
Более общее решение дает стандартная библиотека CSV. Есть также усовершенствованный инструмент под названием FasterCSV. Поищите его в сети, он не входит в стандартный дистрибутив Ruby.
2.24. Преобразование строки в число (десятичное или иное)
Есть два основных способа преобразовать строку в число: методы Integer
и Float
модуля Kernel
и методы to_i
и to_f
класса String
. (Имена, начинающиеся с прописной буквы, например Integer
, обычно резервируются для специальных функций преобразования.)
Простой случай тривиален, следующие два предложения эквивалентны:
x = '123'.to_i # 123
y = Integer('123') # 123
Но если в строке хранится не число, то поведение этих методов различается:
x = junk'.to_i # Молча возвращает 0.
y = Integer('junk') # Ошибка.
Метод to_i
прекращает преобразование, как только встречает первый символ, не являющийся цифрой, а метод Integer
в этом случае возбуждает исключение:
x = '123junk'.to_i # 123
y = Integer('123junk') # Ошибка.
Оба метода допускают наличие пропусков в начале и в конце строки:
x = ' 123 '.to_i # 123
y = Integer(' 123 ') # 123
Преобразование строки в число с плавающей точкой работает аналогично:
x = '3.1416'.to_f # 3.1416
y = Float('2.718') # 2.718
Оба метода понимают научную нотацию:
x = Float('6.02е23') # 6.02е23
y = '2.9979246е5'.to_f # 299792.46
Методы to_i
и Integer
также по-разному относятся к системе счисления. По умолчанию, естественно, подразумевается система по основанию 10, но другие тоже допускаются (это справедливо и для чисел с плавающей точкой).
Говоря о преобразовании из одной системы счисления в другую, мы всегда имеем в виду строки. Ведь целое число неизменно хранится в двоичном виде.
Следовательно, преобразование системы счисления — это всегда преобразование одной строки в другую. Здесь мы рассмотрим преобразование из строки (обратное преобразование рассматривается в разделах 5.18 и 5.5).
Числу в тексте программы может предшествовать префикс, обозначающий основание системы счисления. Префикс 0b
обозначает двоичное число, 0
— восьмеричное, а 0x
— шестнадцатеричное.
Метод Integer
такие префиксы понимает, а метод to_i
— нет:
x = Integer('0b111') # Двоичное - возвращает 7.
y = Integer('0111') # Восьмеричное - возвращает 73.
z = Integer('0x111') # Шестнадцатеричное - возвращает 291.
x = '0b111'.to_i # 0
y = '0111'.to_i # 0
z = '0x111'.to_i # 0
Однако у метода to_i
есть необязательный второй параметр для указания основания. Обычно применяют только четыре основания: 2, 8, 10 (по умолчанию) и 16. Впрочем, префиксы не распознаются даже при определении основания.
x = '111'.to_i(2) # 7
y = '111'.to_i(8) # Восьмеричное - возвращает 73.
z = '111'.to_i(16) # Шестнадцатеричное - возвращает 291.
x = '0b111'.to_i # 0
y = '0111'.to_i # 0
z = '0x111'.to_i # 0
Из-за «стандартного» поведения этих методов цифры, недопустимые при данном основании, обрабатываются по-разному:
x = '12389'.to_i(8) # 123 (8 игнорируется).
y = Integer('012389') # Ошибка (8 недопустима).
Хотя полезность этого и сомнительна, метод to_i
понимает основания вплоть до 36, когда в представлении числа допустимы все буквы латинского алфавита. (Возможно, это напомнило вам о base64-кодировании; дополнительную информацию по этому поводу вы найдете в разделе 2.37.)
x = '123'.to_i(5) # 66
y = 'ruby'.to_i (36) # 1299022
Для преобразования символьной строки в число можно также воспользоваться методом scanf
из стандартной библиотеки, которая добавляет его в модуль Kernel
, а также классы IO
и String
: