Преобразование строки "2½" (два с половиной) в 2,5
В настоящее время я создаю небольшое приложение, которое импортирует данные из электронной таблицы и из-за природы исходной записи, есть строка, которая считывается с такими значениями, как 8½, 2½ и т.д.
Моя цель с простой функцией состоит в том, чтобы преобразовать 2½ в float 2.5, например.
Я пробовал метод .to_f, но это оставило меня со странным значением 2.02½.
Любые идеи или предложения здесь очень ценятся!
Ответы
Ответ 1
Unicode поддерживает только небольшое количество вульгарных фракций, поэтому простая таблица поиска сделает трюк:
# You might want to double check this mapping
vulgar_to_float = {
"\u00BC" => 1.0 / 4.0,
"\u00BD" => 1.0 / 2.0,
"\u00BE" => 3.0 / 4.0,
"\u2150" => 1.0 / 7.0,
"\u2151" => 1.0 / 9.0,
"\u2152" => 1.0 /10.0,
"\u2153" => 1.0 / 3.0,
"\u2154" => 2.0 / 3.0,
"\u2155" => 1.0 / 5.0,
"\u2156" => 2.0 / 5.0,
"\u2157" => 3.0 / 5.0,
"\u2158" => 4.0 / 5.0,
"\u2159" => 1.0 / 6.0,
"\u215A" => 5.0 / 6.0,
"\u215B" => 1.0 / 8.0,
"\u215C" => 3.0 / 8.0,
"\u215D" => 5.0 / 8.0,
"\u215E" => 7.0 / 8.0,
"\u2189" => 0.0 / 3.0,
}
Затем немного передумать, чтобы вытащить "число":
s = "2½"
_, int_part, vulgar_part = *s.match(/(\d+)?(\D+)?/)
И, наконец, объедините их, чтобы правильно справиться с возможным nil
из регулярного выражения:
float_version = int_part.to_i + vulgar_to_float[vulgar_part].to_f
Помните, что nil.to_i
- 0
, а nil.to_f
- 0.0
.
Ответ 2
Замените половинки на ".5"
input = "2½"
input.gsub!("½", ".5")
input.to_f # => 2.5
В стороне, убедитесь, что вы действительно хотите использовать float, а не что-то вроде BigDecimal.
Здесь - это страница, объясняющая проблему с float (это Python, но Ruby и многие другие языки представляют float одинаково и, следовательно, имеют те же проблемы).
Ответ 3
Как и в ответе @muistooshort, я бы использовал хеш в качестве таблицы поиска, но я бы воспользовался sub
:
# encoding: UTF-8
LOOKUP = {
"½" => 1.0/2,
# ...
"⅞" => 7.0/8,
}
LOOKUP_REGEX = Regexp.union(LOOKUP.keys) # => /½|⅞/
'2½'.sub(LOOKUP_REGEX) { |m| LOOKUP[m].to_s[1..-1] } # => "2.5"
'2⅞'.sub(LOOKUP_REGEX) { |m| LOOKUP[m].to_s[1..-1] } # => "2.875"
Чтобы сделать его более удобным и красивым:
class String
def v_to_f
sub(LOOKUP_REGEX) { |m| LOOKUP[m].to_s[1..-1] }
end
end
'2½'.v_to_f # => "2.5"
'2⅞'.v_to_f # => "2.875"