在以下代码中:
x = BigDecimal(10)
s = x.inspect # "#<BigDecimal:6fe4790,'0.1E2',9(36)>"
有没有办法解析s
并获得原始值?原因是我有一些使用inspect编写BigDecimal的文本文件,我需要解析这些值。
答案 0 :(得分:2)
您.to_s
获取字符串中的值。 .inspect
将打印对象
x = BigDecimal(10)
x.to_s
# => "0.1E2"
答案 1 :(得分:1)
"#<BigDecimal:6fe4790,'0.1E2',9(36)>"[/(?<=').+(?=')/]
# => "0.1E2"
答案 2 :(得分:1)
我不知道您使用的是哪个版本的Ruby,所以我检查了some MRI source code for BigDecimal:
2000 /* Returns debugging information about the value as a string of comma-separated
2001 * values in angle brackets with a leading #:
2002 *
2003 * BigDecimal.new("1234.5678").inspect ->
2004 * "#<BigDecimal:b7ea1130,'0.12345678E4',8(12)>"
2005 *
2006 * The first part is the address, the second is the value as a string, and
2007 * the final part ss(mm) is the current number of significant digits and the
2008 * maximum number of significant digits, respectively.
2009 */
2010 static VALUE
2011 BigDecimal_inspect(VALUE self)
2012 {
2013 ENTER(5);
2014 Real *vp;
2015 volatile VALUE obj;
2016 size_t nc;
2017 char *psz, *tmp;
2018
2019 GUARD_OBJ(vp, GetVpValue(self, 1));
2020 nc = VpNumOfChars(vp, "E");
2021 nc += (nc + 9) / 10;
2022
2023 obj = rb_str_new(0, nc+256);
2024 psz = RSTRING_PTR(obj);
2025 sprintf(psz, "#<BigDecimal:%"PRIxVALUE",'", self);
2026 tmp = psz + strlen(psz);
2027 VpToString(vp, tmp, 10, 0);
2028 tmp += strlen(tmp);
2029 sprintf(tmp, "',%"PRIuSIZE"(%"PRIuSIZE")>", VpPrec(vp)*VpBaseFig(), VpMaxPrec(vp)*VpBaseFig());
2030 rb_str_resize(obj, strlen(psz));
2031 return obj;
2032 }
2033
所以,你想要的似乎是inspect-string的第二部分,0.1E2
在你的情况下,等于10
。上面的注释非常清楚,这应该是对象的完整数值。简单的正则表达就足够了。
答案 3 :(得分:1)
BigDecimal#inspect的文档不完整。请考虑以下事项:
require 'bigdecimal`
BigDecimal.new("1.2345").inspect
#=> "#<BigDecimal:7fb06a110298,'0.12345E1',18(18)>"
...
BigDecimal.new("1.234567890").inspect
#=> "#<BigDecimal:7fb06a16ab58,'0.123456789E1',18(27)>"
BigDecimal.new("1.2345678901").inspect
#=> "#<BigDecimal:7fb06a14a6a0,'0.1234567890 1E1',27(27)>"
BigDecimal.new("1.23456789012").inspect
#=> "#<BigDecimal:7fb06a1393a0,'0.1234567890 12E1',27(27)>"
BigDecimal.new("1.234567890123").inspect
#=> "#<BigDecimal:7fb06a123780,'0.1234567890 123E1',27(27)>"
从inspect
的源代码可以看出,如果有超过10个有效数字,则每个10个字符由空格分隔(为了便于阅读):
BigDecimal.new("123.456789012345678901234567").inspect
#=> "#<BigDecimal:7fb06a0ac8b0,'0.1234567890 1234567890 1234567E3',36(36)>"
我建议检索BigDecimal
值的字符串表示形式,如下所示:
str = "#<BigDecimal:7fb06a14a6a0,'0.1234567890 1E1',27(27)>"
str.delete(' ').split(?')[1]
#=> "0.12345678901E1"
我们还没完。我们仍然必须将我们提取的字符串转换为数字对象。但是,如果值的绝对值很大,我们就无法使用BigDecimal#to_f:
"1.23456789012345678".to_f
#=> 1.2345678901234567
最安全的做法是使用方法BigDecimal::new返回BigDecimal
对象,该方法有两个参数:
要转换为BigDecimal
对象的值,可以是Integer,Float,Rational,BigDecimal或String。如果我们将提供的字符串,#34;空格被忽略,而无法识别的字符终止值&#34; (类似于"123.4cat".to_f #=> 123.4
)。
有效位数。如果省略或为零,则从该值确定有效位数。我会省略这个论点。 (例如,BigDecimal.new("0.1234E2").precs #=> [18, 18]
,其中数组包含当前和最大有效位数。
注意第二个参数是必需的,如果第一个是Float或Rational,否则它是可选的。
我们可以写:
require 'bigdecimal'
def convert(str)
BigDecimal.new(str.delete(' ').split(?')[1])
end
convert "#<BigDecimal:7facd39d7ee8,'0.1234E4',9(18)>"
#=> #<BigDecimal:7facd39c7de0,'0.1234E4',9(18)>
convert "#<BigDecimal:7facd39b7be8,'0.1234E2',18(18)>"
#=> #<BigDecimal:7facd39ae610,'0.1234E2',18(18)>
convert "#<BigDecimal:7facd3990638,'0.1234E0',9(18)>"
#=> #<BigDecimal:7facd3980aa8,'0.1234E0',9(18)>
convert "#<BigDecimal:7facd3970e28,'0.1234E-2',9(18)>"
#=> #<BigDecimal:7facd39625d0,'0.1234E-2',9(18)>
v = convert "#<BigDecimal:7fb06a123780,'0.1234567890 123E1',27(27)>"
#=> #<BigDecimal:7fb069851d78,'0.1234567890 123E1',27(27)>
在不损失准确性的情况下查看BigDecimal
对象是否可以转换为浮点数的简单方法是:
def convert_bd_to_float(bd)
f = bd.to_f
(bd==BigDecimal.new(f.to_s)) ? f : nil
end
convert_bd_to_float BigDecimal.new('1234567890123456')
#=> 1.234567890123456e+15
convert_bd_to_float BigDecimal.new('12345678901234567')
#=> nil
答案 4 :(得分:0)
另一种选择:
"#<BigDecimal:95915c4,'0.1E2',9(27)>".split(",")[1].tr! "'", ''
=> "0.1E2"