Преобразование строки «2½» (два с половиной) в 2,5 - PullRequest
12 голосов
/ 29 января 2012

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

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

Я пробовал метод .to_f, но у меня осталось странное значение 2,02½.

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

Ответы [ 3 ]

13 голосов
/ 29 января 2012

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,
}

Затем, немного ссоры по регулярному выражению, чтобы вытащить ваш номер"apart:

s = "2½"
_, int_part, vulgar_part = *s.match(/(\d+)?(\D+)?/)

И, наконец, соедините их, стараясь правильно разобраться с возможными nil s из регулярного выражения:

float_version = int_part.to_i + vulgar_to_float[vulgar_part].to_f

Помните, что nil.to_i равно 0 и nil.to_f - это 0.0.

6 голосов
/ 29 января 2012

Заменить половинки на ".5"

input = "2½"
input.gsub!("½", ".5")
input.to_f # => 2.5

Кроме того, убедитесь, что вы действительно хотите использовать float, а не что-то вроде BigDecimal .

Здесь - страница, объясняющая проблему с плавающими (это Python, но Ruby и многие другие языки представляют плавающие так же, и поэтому имеют те же проблемы).

2 голосов
/ 29 января 2012

Как и в ответе @ 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" 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...