簡體   English   中英

如何用正則表達式捕獲科學記數法中的減號?

[英]How to capture minus sign in scientific notation with regex?

我試圖回答一個問題(后來被刪除)我認為是在提取科學記數法的文本表示。 (使用R的regex實現,需要對元字符進行雙重轉義,並且可以在純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" 

我用“科學記數法正則表達式減去”之類的術語來搜索我的耐心程度

你可以試試

 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" 

推斷是“(。+)”第一個捕獲組的“貪婪”能力吞噬了第二個捕獲組中可選的減號,我用一個否定字符類終止了第一個捕獲組現在已經成功了。 這仍然顯得笨重,希望有更優雅的東西。 在搜索中看到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" 

在查看使用substr來提取匹配的str_extract_all中的代碼之后,我現在認為我應該為我的努力選擇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"

這似乎有效,並且與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有什么不同,但刪除否定符號字符類就可以了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM