Подтвердить что ты не робот

Преобразование строки "2½" (два с половиной) в 2,5

В настоящее время я создаю небольшое приложение, которое импортирует данные из электронной таблицы и из-за природы исходной записи, есть строка, которая считывается с такими значениями, как 8½, 2½ и т.д.

Моя цель с простой функцией состоит в том, чтобы преобразовать 2½ в float 2.5, например.

Я пробовал метод .to_f, но это оставило меня со странным значением 2.02½.

Любые идеи или предложения здесь очень ценятся!

4b9b3361

Ответ 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"