合理解析科学符号?

2024-06-15 23:17:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我想能够写一个函数,它接收一个用科学符号表示的数字作为一个字符串,并把系数和指数分开作为单独的项。我可以使用一个正则表达式,但是输入的数字可能不是标准化的,我更希望能够标准化,然后将部分分解。

一位同事已经找到了使用VB6解决方案的一部分方法,但还没有完全实现,如下面的文字记录所示。

cliVe> a = 1e6
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 10 exponent: 5 

应该是1和6

cliVe> a = 1.1e6
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 1.1 exponent: 6

更正

cliVe> a = 123345.6e-7
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 1.233456 exponent: -2

更正

cliVe> a = -123345.6e-7
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 1.233456 exponent: -2

应为-1.233456和-2

cliVe> a = -123345.6e+7
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 1.233456 exponent: 12

更正

有什么想法吗?顺便说一下,Clive是一个基于VBScript的CLI,可以在myweblog上找到。


Tags: 函数字符串符号数字科学解决方案指数clive
3条回答

Google在"scientific notation regexp"上显示了许多匹配项,包括this one不要使用它!!!!)使用

*** warning: questionable ***
/[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/

其中包括-.5e7和+00000e33(这两种情况您可能都不允许)。

相反,我强烈建议您使用Doug Crockford的JSON website语法,它显式地记录了JSON中数字的构成。下面是从该页获取的相应语法图:

alt text
(来源:json.org

如果您查看他的json2.js脚本的第456行(在javascript中安全地转换为JSON或从JSON转换为JSON),您将看到regexp的这一部分:

/-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/

讽刺的是,这和他的语法图不匹配。。。。(看起来我应该提交一个bug)我相信实现该语法图的regexp是这样的:

/-?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?/

如果你也想要一个初始的+值,你会得到:

/[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?/

根据您的喜好添加捕获括号。

我还强烈建议您充实一堆测试用例,以确保您包括那些您希望包括(或不包括)的可能性,例如:

allowed:
+3
3.2e23
-4.70e+9
-.2E-4
-7.6603

not allowed:
+0003   (leading zeros)
37.e88  (dot before the e)

祝你好运!

基于最高级别的答案,我稍微修改了regex为/^[+\-]?(?=.)(?:0|[1-9]\d*)?(?:\.\d*)?(?:\d[eE][+\-]?\d+)?$/

这样做的好处是:

  1. 允许像.9这样的匹配数字(我用?使(?:0|[1-9]\d*)可选)
  2. 防止只匹配开头的运算符,并防止匹配零长度字符串(使用lookahead,(?=.)
  3. 防止匹配e9,因为它需要在科学符号之前使用\d

我的目标是用它来捕捉有意义的数字和做有意义的数学。因此,我还将用So:/^[+\-]?(?=.)(0|[1-9]\d*)?(\.\d*)?(?:(\d)[eE][+\-]?\d+)?$/这样的捕获组来分割它。

如何从中获取有效数字的说明:

  1. 整个捕获是您可以传递给parseFloat()的数字
  2. 匹配项1-3将显示为未定义的或字符串,因此组合它们(将undefined替换为'')应给出可从中提取有效数字的原始数字。

这个regex还防止匹配左填充的零,JavaScript有时接受左填充的零,但我已经看到这会导致问题,并且不会给有效数字添加任何内容,所以我认为防止左填充的零是一个好处(特别是在表单中)。不过,我相信regex可以被修改为吞噬左填充的零。

我发现这个regex的另一个问题是它与90.e9或其他类似的数字不匹配。然而,我发现这种或类似的匹配是极不可能的,因为这是科学记数法中的惯例,以避免这样的数字。尽管可以用JavaScript输入,但也可以轻松地输入9.0e10,并获得相同的有效数字。

更新

在我的测试中,我还发现了它可能匹配'.'的错误。因此,应该将look ahead修改为(?=\.\d|\d),这将导致最终的regex:

/^[+\-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:\d[eE][+\-]?\d+)?$/

这里有一些Perl代码,我刚刚很快就破解了。

my($sign,$coeffl,$coeffr,$exp) = $str =~ /^\s*([-+])?(\d+)(\.\d*)?e([-+]?\d+)\s*$/;

my $shift = length $coeffl;
$shift = 0 if $shift == 1;

my $coeff =
  substr( $coeffl, 0, 1 );

if( $shift || $coeffr ){
  $coeff .=
    '.'.
    substr( $coeffl, 1 );
}

$coeff .= substr( $coeffr, 1 ) if $coeffr;

$coeff = $sign . $coeff if $sign;

$exp += $shift;

say "coeff: $coeff exponent: $exp";

相关问题 更多 >