如何使用正则表达式捕获科学记数法中的减号?

Posted

技术标签:

【中文标题】如何使用正则表达式捕获科学记数法中的减号?【英文标题】:How to capture minus sign in scientific notation with regex? 【发布时间】:2015-05-03 19:37:48 【问题描述】:

我试图回答一个我认为是关于提取科学记数法的文本表示的问题(后来被删除)。 (使用 R 的正则表达式实现需要对元字符进行双重转义,并且可以在纯 PCRE 或 Perl 模式下使用,我不太了解它们之间的区别。)我已经解决了大部分任务,但似乎仍然未能在捕获组中捕获前导减号。我似乎让它成功的唯一方法是使用前导左括号:

> txt <- c("this is some random text (2.22222222e-200)", "other random (3.33333e4)", "yet a third(-1.33333e-40)", 'and a fourth w/o the "e" (2.22222222-200)')
> sub("^(.+\\()([-+]0,1[0-9][.][0-9]1,16[eE]*[-+]*[0-9]0,3)(.+$)", "\\2" ,txt)
[1] "2.22222222e-200" "3.33333e4"       "-1.33333e-40"    "2.22222222-200" 

> sub("^(.+\\()([-+]?[0-9][.][0-9]1,16[eE]*[-+]*[0-9]0,3)(.+$)", "\\2" ,txt)
[1] "2.22222222e-200" "3.33333e4"       "-1.33333e-40"    "2.22222222-200" 
 #but that seems to be "cheating" ... my failures follow:

> sub("^(.+)([-+]?[0-9][.][0-9]1,16[eE]*[-+]*[0-9]0,3)(.+$)", "\\2" ,txt)
[1] "2.22222222e-200" "3.33333e4"       "1.33333e-40"     "2.22222222-200" 
> sub("^(.+)(-?[0-9][.][0-9]1,16[eE]*[-+]*[0-9]0,3)(.+$)", "\\2" ,txt)
[1] "2.22222222e-200" "3.33333e4"       "1.33333e-40"     "2.22222222-200" 
> sub("^(.+)(-*[0-9][.][0-9]1,16[eE]*[-+]*[0-9]0,3)(.+$)", "\\2" ,txt)
[1] "2.22222222e-200" "3.33333e4"       "1.33333e-40"     "2.22222222-200" 

我已经在耐心的范围内搜索了诸如“科学记数法正则表达式减号”之类的术语

【问题讨论】:

您能否更新您的问题以清楚地显示起始输入和所需输出? 该问题使用 R 代码创建输入字符向量作为输入,我发布了两个正确答案,它们依赖于我称之为“作弊”的方法。我不知道它怎么能更可复制 @TimBiegeleisen 在最后三个"1.33333e-40" 不同 谢谢...我现在知道了 ^ ^ 使用str_extract_all 似乎可以工作unlist(str_extract_all(txt, '-?[0-9.]+e?[-+]?[0-9]*')) 【参考方案1】:

你可以试试

 library(stringr)
 unlist(str_extract_all(txt, '-?[0-9.]+e?[-+]?[0-9]*'))
 #[1] "2.22222222e-200" "3.33333e4"       "-1.33333e-40"    "2.22222222-200" 

使用基于前括号后捕获的方法

 str_extract(txt, '(?<=\\()[^)]*')
 #[1] "2.22222222e-200" "3.33333e4"       "-1.33333e-40"    "2.22222222-200" 

【讨论】:

我认为 stringr 现在使用其他包中的代码,但我没有在包 NEWS 中看到提及。 @BondedDust 好像是这样,我收到了perl is deprecated. Please use regexp instead的消息。 @BondedDust 根据github.com/hadley/stringr 构建在 stringi 之上,它使用 ICU 库提供常见字符串操作的快速、正确实现 就是这个包但是我在我安装的版本中没有看到任何提及。也许这只是在 Github 版本中? (尝试在 Mac 上编译,结果报错 configure: error: C++ preprocessor "/lib/cpp" fails sanity check .... 所以我还在 CRAN 版本上。) @BondedDust 我不确定【参考方案2】:

理由是“(.+)”第一个捕获组的“贪婪”能力吞噬了第二个捕获组中可选的减号,我用否定终止了第一个捕获组-字符级,现在已经成功。这看起来仍然很笨重,希望有更优雅的东西。在搜索中看到似乎暗示有“&real_number”>

的正则表达式定义的 Python 代码
> sub("^(.+[^-+])([-+]?[0-9][.][0-9]1,16[eE]*[-+]*[0-9]0,3)(.+$)", "\\2" ,txt,perl=TRUE)
[1] "2.22222222e-200" "3.33333e4"       "-1.33333e-40"    "2.22222222-200" 

查看 str_extract_all 中使用 substr 提取匹配项的代码后,我现在认为我应该选择 gregexpr-regmatches 范式而不是选择三捕获组策略的中间选择:

> hits <- gregexpr('[-+]?[0-9][.][0-9]1,16[eE]*[-+]*[0-9]0,3', txt)
> ?regmatches
> regmatches(txt, hits)
[[1]]
[1] "2.22222222e-200"

[[2]]
[1] "3.33333e4"

[[3]]
[1] "-1.33333e-40"

[[4]]
[1] "2.22222222-200"

【讨论】:

【参考方案3】:

这似乎可行,并且与 IP 地址不匹配:

sub("^.*?([-+]?\\d+(?:\\.\\d*)*(?:[Ee]?[-+]?\\d+)?).*?$", "\\1", txt)
[1] "2.22222222e-200" "3.33333e4"       "-1.33333e-40"    "2.22222222-200"

奇怪的是,这不是我开始使用的正则表达式。当尝试一个不起作用时,我想我会回去在 Perl 中测试:

my @txt = (
  "this is some random text (2.22222222e-200)",
  "other random (3.33333e4)",
  "yet a third(-1.33333e-40)" ,
  'and a fourth w/o the "e" (2.22222222-200)');

map  s/^.*?[^-+]([-+]?\d+(?:\.\d*)*(?:[Ee]?[-+]?\d+)?).*?$/$1/  @txt;

print join("\n", @txt),"\n";

看起来不错:

2.22222222e-200
3.33333e4
-1.33333e-40
2.22222222-200

所以相同的正则表达式应该在 R 中工作,对吧?

sub("^.*?[^-+]([-+]?\\d+(?:\\.\\d*)*(?:[Ee]?[-+]?\\d+)?).*?$", "\\1", txt)
[1] "0" "4" "0" "0"

显然不是。我什至通过使用new RegExp("...")javascript 中尝试确认双引号字符串是正确的,并且它在那里也可以正常工作。不确定 R 有什么不同,但删除否定符号字符类就可以了。

【讨论】:

R 使用 Ville Laurikari (laurikari.net/tre) 的 TRE 库版本作为非 Perl 正则表达式。

以上是关于如何使用正则表达式捕获科学记数法中的减号?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用正则表达式验证捕获组中的最后一个字符

正则表达式中 如何取出所有组中的值?

Perl 中的正则表达式组:如何从正则表达式组中捕获与字符串中出现的未知数量/多个/变量匹配的元素到数组中?

急求js正则表达式,要求只能输入数字和减号,不能输入其他任何字母或特殊字符,但是减号只能在数字的开

如何通过 LibreOffice 的 Calc 中的正则表达式语句捕获公司名称

Javascript 正则表达式到数字/十进制和减号