科学计数法数字的正则表达式?

13

我正在加载一个包含以下行的.obj文件

vn 8.67548e-017 1 -1.55211e-016

这是用于顶点法线的。如何检测并将它们转换为双精度符号?

7个回答

19

一个相当有效的正则表达式是:

-?[\d.]+(?:e-?\d+)?

可以像这样将字符串转换为数字:String in scientific notation C++ to double conversion

正则表达式是:

-?      # an optional -
[\d.]+  # a series of digits or dots (see *1)
(?:     # start non capturing group
  e     # "e"
  -?    # an optional -
  \d+   # digits
)?      # end non-capturing group, make optional

**1)从技术上讲,这并不完全正确。在点之前只能有一个(或没有)数字,并且只能有一个点。但在实践中,这种情况应该不会发生。因此,正则表达式是一个很好的近似值,假阳性的可能性非常小。请随意使正则表达式更具体。


5
建议将 [\d.]+ 分解为 \d+\.\d+,以防止误匹配。如果小数点前和/或后不要求数字,则使用 \d* - moinudin
1
这个内容不会匹配 5.5.5.5.5.5.5.5.5.5.5.5.5 - Martin York
@Martin:是的,没错。问题是:这样的值可能发生吗?如果是,正则表达式可以很容易地变得更加具体。我猜在这种情况下,“5.5.5.5”场景相当不太可能出现。 - Tomalak
1
我知道这是一个非常老的评论,但是你不选用更有效的选项有没有任何理由呢?实现起来应该相当简单吧?我无法想象它会对性能产生多大影响,并且它会更可靠……? - XtraSimplicity
性能在这里甚至不是一个考虑因素。为一个不会出现在有效数据中的情况准备正则表达式毫无意义。无论如何,人们无法预测每种形式的无效数据,所以仅仅因为这个原因使正则表达式更加复杂是浪费时间的。如果期望输入中出现5.5.5.5.5.5(或者如果这让你感觉更好),请适应正则表达式。;) - Tomalak
-?[\d.]+(?:[e|E|d|D]-?\d+)? 可以匹配几乎所有内容。 - MathArt

6

您可以使用正则表达式-?\d*\.?\d+e[+-]?\d+来识别科学数值。


1
不要使用 {0,1},请改用 ?。前者更长,没有更清晰的效果,并且具有相同的作用。 - Antal Spector-Zabusky
{0,1} 可以被替换为 ?。但是,为什么要让小数点变成可选项呢?这也不允许负数。它还会错误地匹配 .0,这可能不是所需的结果。 - moinudin
@marcog:可能是因为根据示例数据,小数点是可选的。第三个字段只是“1”。 - Ben Voigt

6

我尝试了其他一些解决方案都无效,所以我想出了这个。

       ^(-?\d+)\.?\d+(e-|e\+|e|\d+)\d+$

正则表达式可视化

Debuggex演示

任何与之匹配的内容都被认为是有效的科学计数法。

请注意:此正则表达式接受e+e-e;如果您不想接受e,可以使用这个:^(-?\d+)\.?\d+(e-|e\+|\d+)\d+$

我不确定它是否适用于C++,但在C#中,您可以在正则表达式的^(-之间添加(?i)来切换行内大小写不敏感性。没有它,像1.05E+10这样声明的指数将无法被识别。

编辑:我的先前的正则表达式有一些小问题,所以我已经用上面的替换了它。


我改编了这个答案,得出了 ^(?:-?\d*)\.?\d+[eE][-\+]?\d+$ -- 允许像 .1e5 这样的情况,在 JS 中是有效的。 - Jacob
你为什么在第二个捕获组末尾加上 \d+ 呢?这将使你的正则表达式匹配非科学计数法形式的数字,如 3.1415 - Paul Razvan Berg

3

标准库函数strtod能够正确处理指数形式的数字(atof也可以,但是strtod能够区分解析失败和解析出零值)。


2

如果您确定double类型的格式是科学计数法,可以尝试以下方式:

  string inp("8.67548e-017");
  istringstream str(inp);
  double v;
  str >> scientific >> v;
  cout << "v: " << v << endl;

如果您想检测是否存在该格式的浮点数,则上述正则表达式会起到作用。
编辑:当您流式处理双精度数时,实际上不需要使用“scientific”操纵器,它会自动为您处理(无论是固定还是科学计数法)。

我认为这是C++的正确方法。摆弄有时有效有时无效的正则表达式并不是我的理想方式。相反,这将粗略部分委托给STL的stringstream。这是检查有效科学格式的更高级别版本。 - Martin Wirth

0

C++中使用std::regex提取科学计数法中的数字,我通常会使用以下方法:

((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?((e|E)((\\+|-)?)[[:digit:]]+)?

这对应于

((\+|-)?\d+)(\.((\d+)?))?((e|E)((\+|-)?)\d+)?

Regular expression visualization

Debuggex演示

这将匹配任何形式为+12.3456e-78的数字,其中

  • 符号可以是+-,并且是可选的
  • 逗号以及逗号后的位置是可选的
  • 指数是可选的,并且可以用小写或大写字母编写

相应的解析代码可能如下所示:

std::regex const scientific_regex {"((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?((e|E)((\\+|-)?)[[:digit:]]+)?"};
std::string const str {"8.67548e-017 1 -1.55211e-016"};

for (auto it = std::sregex_iterator(str.begin(), str.end(), scientific_regex); it != std::sregex_iterator(); ++it) {
  std::string const match {it->str()};
  std::cout << match << std::endl;
}

如果您想将找到的子字符串转换为 double 数字,std::stod 应该能够正确地处理转换,正如 Ben Voigt 所指出的那样。

在这里尝试一下!


0

好吧,这并不完全是你要求的,因为它不是 Perl(噫)而且它是一个普通定义而不是正则表达式,但这就是我用来识别 C 浮点文字面量扩展(该扩展允许数字字符串中有“_”),如果你想的话,我相信你可以将其转换成无法阅读的正则表达式:

/* floats: Follows ISO C89, except that we allow underscores */
let decimal_string = digit (underscore? digit) *
let hexadecimal_string = hexdigit (underscore? hexdigit) *

let decimal_fractional_constant =
  decimal_string '.' decimal_string?
  | '.' decimal_string

let hexadecimal_fractional_constant =
  ("0x" |"0X")
  (hexadecimal_string '.' hexadecimal_string?
  | '.' hexadecimal_string)

let decimal_exponent = ('E'|'e') ('+'|'-')? decimal_string
let binary_exponent = ('P'|'p') ('+'|'-')? decimal_string

let floating_suffix = 'L' | 'l' | 'F' | 'f' | 'D' | 'd'
let floating_literal =
  (
    decimal_fractional_constant decimal_exponent? |
    hexadecimal_fractional_constant binary_exponent?
  )
  floating_suffix?

C格式是为编程语言而设计的,而不是数据,因此它可能支持您的输入不需要的功能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接