如何使用正则表达式捕获科学记数法中的减号?
How to capture minus sign in scientific notation with regex?
我试图回答一个我认为是关于提取科学记数法的文本表示的问题(后来被删除了)。 (使用 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"
我已经耐心地搜索了诸如“科学记数法正则表达式减号”之类的术语
推断是“(.+)”第一个捕获组的 "greedy" 容量吞噬了第二个捕获组中可选的减号,我终止了第一个捕获组带有否定字符-class,现在成功了。这看起来仍然很笨重,希望有更优雅的东西。在搜索中看到 Python 代码似乎暗示存在 "&real_number">
的正则表达式定义
> 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"
你可以试试
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"
这似乎有效,但与 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+)?).*?$// } @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"
显然不是。我什至通过在 Javascript 中尝试使用 new RegExp("
...")
来确认双引号字符串是正确的,并且它在那里也工作得很好。不确定 R 有什么不同,但删除否定符号字符 class 就可以了。
我试图回答一个我认为是关于提取科学记数法的文本表示的问题(后来被删除了)。 (使用 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"
我已经耐心地搜索了诸如“科学记数法正则表达式减号”之类的术语
推断是“(.+)”第一个捕获组的 "greedy" 容量吞噬了第二个捕获组中可选的减号,我终止了第一个捕获组带有否定字符-class,现在成功了。这看起来仍然很笨重,希望有更优雅的东西。在搜索中看到 Python 代码似乎暗示存在 "&real_number">
的正则表达式定义> 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"
你可以试试
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"
这似乎有效,但与 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+)?).*?$// } @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"
显然不是。我什至通过在 Javascript 中尝试使用 new RegExp("
...")
来确认双引号字符串是正确的,并且它在那里也工作得很好。不确定 R 有什么不同,但删除否定符号字符 class 就可以了。