Почему Ruby неправильно разбирает строки с запятыми как плавающие? - PullRequest
0 голосов
/ 08 ноября 2018

Суть моего вопроса такова:

irb(main):001:0> "5,280".to_f
=> 5.0

Почему Ruby делает это?

Я мог бы почти понять "5,280".to_i == 5, поскольку в некоторых локалях , является разделителем десятичного типа, но потеря точности здесь сбивает с толку меня, тем более что "5.280".to_f возвращает 5.28 как и ожидалось.

Это просто ошибка?

Ruby-версия на случай, если это имеет значение:

$ ruby --version
ruby 2.3.7p456 (2018-03-28 revision 63024) [universal.x86_64-darwin17]

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Я не считаю, что это ошибка, я думаю, что это связано с тем, какую часть строки Ruby считает, когда вызывает to_f.

Ruby просматривает строку, начинающуюся слева, и любой символ 0-9, первый десятичный знак и следующие символы 0-9 будут соответствовать и пытаться преобразовать их в число с плавающей точкой. Все, что справа от этого, игнорируется.

Если ни один символ не соответствует этому критерию, возвращается 0.0.

https://apidock.com/ruby/String/to_f

Примеры:

>>'5.5'.to_f 
=> 5.5

>>'5.5stuff'.to_f 
=> 5.5   

>>'5.stuff5'.to_f 
=> 5.0

>>'5,5'.to_f 
=> 5.0

>>'stuff5.5'.to_f 
=> 0.0
0 голосов
/ 08 ноября 2018

Руби просто вызов strtod С функции https://github.com/ruby/ruby/blob/38caab29bc759be2694013fc3930116e64fcc1d4/object.c#L3278

d = strtod(p, &end);

и функция strtod имеет что-то вроде этого:

/*
 * Count the number of digits in the mantissa (including the decimal
 * point), and also locate the decimal point.
 */

decPt = -1;
for (mantSize = 0; ; mantSize += 1)
{
c = *p;
if (!isdigit(c)) {
    if ((c != '.') || (decPt >= 0)) {
    break;
    }
    decPt = mantSize;
}
p += 1;
}

https://opensource.apple.com/source/tcl/tcl-10/tcl/compat/strtod.c

в соответствии с if ((c != '.') || (decPt >= 0)) { break; strtod остановить, если найти какой-либо не точечный символ, например:

irb(main):002:0> "2;58".to_f
=> 2.0
irb(main):003:0> "2@58".to_f
=> 2.0
irb(main):004:0> 

UPD: этот подход действителен для реализации mri 2.6 ruby. В других версиях / реализациях это может отличаться.

0 голосов
/ 08 ноября 2018

Из руководства штраф 2.3.7 (но текущие документы говорят то же самое):

to_f → float
Возвращает результат интерпретации начальных символов в str как число с плавающей запятой.Посторонние символы после конца действительного числа игнорируются.Если в начале str нет действительного числа, возвращается 0.0.Этот метод никогда не вызывает исключение.

Так что "5,280".to_f делает именно то, что должен.Все до (но не включая) запятая является допустимым числом, и посторонние символы (",280" в этом случае) игнорируются.Результат аналогичен вызову '5'.to_f.

Это не ошибка, это ожидаемое и задокументированное поведение.Это было поведение String#to_f, так как по крайней мере Ruby 1.8.6 .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...