【问题标题】:Converting String "2½" (two and a half) into 2.5将字符串“2½”(两个半)转换为 2.5
【发布时间】:2012-02-21 12:29:24
【问题描述】:

现在我正在构建一个从电子表格导入数据的小应用程序,由于原始条目的性质,正在读取的字符串具有诸如 8½、2½ 等值。

例如,我使用简单函数的目标是将 2½ 转换为浮点 2.5。

我已经尝试过 .to_f 方法,但这给我留下了一个奇怪的 2.02½ 值。

非常感谢您提供任何见解或建议!

【问题讨论】:

  • 可以更改源电子表格吗?如果字段类型可以更改为十进制/数字,我认为您可以完全避免这种情况
  • 它可以,我正在权衡是否以编程方式执行它是否会更快。我有 17 个电子表格,每个电子表格大约 17 行。真的不应该改变太多
  • 自动化肯定是值得尊敬的!我个人不知道如何做到这一点,但这个线程表明它可能不容易完成(特别是 2½)=> stackoverflow.com/a/2259624/691986 如果这是混合数字的 only 情况,a将该解决方案与一些特定的代码处理相结合可能会让你到达你需要的地方

标签: ruby-on-rails ruby string character-encoding floating-point


【解决方案1】:

Unicode 只支持small number of vulgar fractions,所以一个简单的查找表就可以解决问题:

# 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+)?/)

最后,将它们放在一起,注意正确处理正则表达式中可能出现的nils:

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

记住nil.to_i0nil.to_f0.0

【讨论】:

  • -1,重新实现 Unicode 很差。 (例如,您错过了 2189。)
  • @Joe:"\u2189" 是什么?零。所以对结果没有影响。而且只有19 vulgar fractions in Unicode,罗马数字等数字形式与本题无关。
【解决方案2】:

类似于@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" 

【讨论】:

  • -1,类似于 muistooshort 的回答,你重新实现 Unicode 标准数据很糟糕。
  • 您为什么不解释您的担忧并提供解决方案?标记答案并引用 Unicode 表并不能帮助 OP 找到解决方案。
  • Unicode 表是解决方案。您解析 Unicode 表。这将为您提供每个代码点的正确值。
  • 解析 Unicode 表将提供“1/2”,在 Ruby 中为 1/2==0。这比1.0/2==0.5 更可取吗?您的建议不可行。
  • 我的解决方案假定您具有 Ruby 的基本知识(例如,即使提供的分子和分母的文本都没有小数点,如何评估简单分数),如果提问者已经加载了电子表格这似乎不是一个糟糕的假设。
【解决方案3】:

".5"替换一半

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

顺便说一句,确保你真的想使用浮点数,而不是像BigDecimal 这样的东西。

Here 是一个解释浮点数问题的页面(它是 Python,但 Ruby 和许多其他语言以相同的方式表示浮点数,因此存在相同的问题)。

【讨论】:

  • 不应该是input.gsub!("½", ".5")吗?
  • 具体化容易理解。它比任何其他答案都容易理解。无论如何,没有指定一般问题,所以一般答案必须是猜测。从历史上看,猜测需求是不可靠的(想想 YAGNI 和“可能工作的最简单的东西”)。
猜你喜欢
  • 1970-01-01
  • 2011-10-14
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多