如何使用正则表达式捕获科学记数法中的减号?
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正则表达式,要求只能输入数字和减号,不能输入其他任何字母或特殊字符,但是减号只能在数字的开