Regex 合理地解析科学符号?

Regex 合理地解析科学符号?,regex,parsing,scientific-notation,Regex,Parsing,Scientific Notation,我希望能够编写一个函数,它以科学记数法的形式接收一个数字作为字符串,并从中分离出系数和指数作为单独的项。我可以只使用正则表达式,但传入的数字可能无法正常化,我更希望能够正常化,然后分解部分 一位同事已经用VB6实现了部分解决方案,但正如下面的文字记录所示,还没有完全实现 cliVe> a = 1e6 cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a) coeff: 10 exponent: 5

我希望能够编写一个函数,它以科学记数法的形式接收一个数字作为字符串,并从中分离出系数和指数作为单独的项。我可以只使用正则表达式,但传入的数字可能无法正常化,我更希望能够正常化,然后分解部分

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

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

正确的

正确的

应为-1.233456和-2

正确的


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

这里是一些我刚刚快速拼凑的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";
Google on显示了许多匹配项,包括(不要使用它!!!!)使用

*** warning: questionable ***
/[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/
其中包括-.5e7和+00000e33(这两种情况您可能不希望允许)

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


(来源:)

如果您查看他的脚本第456行(javascript中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)

祝你好运

在最高评分答案的基础上,我将正则表达式稍微修改为
/^[+\-]?(?=)(?:0[1-9]\d*)?(?:\.\d*)?(?:\d[eE][+\-]?\d+)$/

它提供的好处是:

  • 允许匹配数字,如
    .9
    (我将
    (?:0 |[1-9]\d*)
    一起设置为可选)
  • 防止仅在开始处匹配运算符,并防止匹配零长度字符串(使用前瞻,
    (?=)
  • 防止匹配
    e9
    ,因为它需要
    \d
    在科学符号之前
  • 我的目标是用它来捕捉重要的数字和做重要的数学。因此,我还将通过如下方式捕获组将其切分:
    /^[+\-]?(?=)(0[1-9]\d*)?(\.\d*)?(?:(\d)[eE][+\-]?\d+)$/

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

  • 整个捕获是您可以交给
    parseFloat()
  • 匹配项1-3将显示为未定义的或字符串,因此将它们组合(将
    未定义的
    替换为
    '
    )应给出可从中提取有效数字的原始数字
  • 这个正则表达式还防止匹配左填充的零,JavaScript有时会接受,但我看到这会导致问题,并且不会给有效数字添加任何内容,因此我认为防止左填充的零是一个好处(尤其是在表单中)。然而,我确信正则表达式可以被修改为吸收左填充的零

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

    更新

    在我的测试中,我还发现了它可能匹配的错误。。因此,应将前瞻修改为
    (?=\.\d |\d)
    ,从而生成最终的正则表达式:

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

    如果有一个有效输入=>output的列表,会比当前已损坏的实现的输出更有用。“应该是-1.233456和-2”应该是“应该是-1.233456和-7”,对吧?我不这么认为-1.233456e-7也可以表示为-0.01233456。。。?只要使用JSON网站上显示的regexp/diagram就可以了。那么为什么不试试前面的regex,也就是“如果您还想允许使用首字母+的话”之前的regex呢?我知道这是一个非常古老的论坛,但我想指出一点。您的模式似乎允许这种类型的条目“e324ewfg”,它显然不是一个有效的数字。发布的regexp不包括开头的
    ^
    ,或结尾的
    $
    ,这将阻止这些条目,如果匹配项只是一个数字,则应使用它;但是regexp的一些用法有更大的模式。哈哈。。。arg。。。我想这会更简单。这是最普遍的情况。
    /-?(?: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)
    
    /^[+\-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:\d[eE][+\-]?\d+)?$/