2015-05-03 18 views
7

Bilimsel gösterimin metin gösterimlerini çıkarmayı düşündüğümü düşündüğüm bir soruyu (daha sonra silindi) yanıtlamaya çalışıyordum. (R'nin meta-karakterler için çift kaçış gerektiren regex uygulamalarını kullanarak ve saf PCRE veya Perl modlarında, gerçekten anlamadığım farklar arasında kullanılabilir). Görevin çoğunu çözdüm ama yine de Bir yakalama grubu içinde önde gelen eksi işaretini yakalayamamak.İfade ile bilimsel gösterimde eksi işareti nasıl alınır?

> 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" 

ben `bilimsel gösterim regex eksi

+0

Başlangıç ​​girişini ve istenen çıktıyı net bir şekilde göstermek için sorunuzu güncelleyebilir misiniz? –

+0

Soru, giriş karakteri vektörünü R kodu kullanarak girdi olarak yaratır ve "aldatma" adını verdiğim yönteme dayanan iki doğru yanıtı yayınladım. Ben daha fazla reprodüktif olabilir nasıl bilmiyorum –

+1

@TimBiegeleisen Son üç '" 1.33333e-40 "' farklı – akrun

cevap

6

Deneyebilirsin

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

kullanma yöntemi Bu iş gibi görünüyor lider parantez

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

Sanırım 'stringr' şimdi kodu başka bir paket içinde kullanıyor, ancak bunu NEWS paketinde görmüyorum. –

+0

@BondedDust Öyle görünüyor ki, perl'in kullanımdan kaldırıldığı mesajını alıyorum. Lütfen yerine regexp kullanın. – akrun

+0

@BondedDust https://github.com/hadley/stringr adresine göre ICU kütüphanesini kullanan, ortak dizge manipülasyonlarının hızlı ve doğru uygulamalarını sağlamak için ICU kütüphanesini kullanan bir dizidir. – akrun

2

gibi terimlerle benim sabır ölçüde SO aradık: Ben başarılı olmak almak gibi tek yolu açan açık parantez kullanmaktır İkinci yakalama grubunda isteğe bağlı olan eksi işaretini yükseltmek için "(. +)" Ilk yakalama grubunun "açgözlülük" kapasitesi olduğunu düşünerek, ilk yakalama grubunu bir negatif karakter sınıfıyla sonlandırdım. ve şimdi başarı var. Bu hala cılız ve daha zarif bir şey olduğunu umarak görünüyor. arama olarak eşleşmeleri ayıklamak için substr kullanan str_extract_all kod baktıktan sonra "& real_number" nin regex tanımları olduğunu ima etmek gibi görünüyor Python kodunu>

> 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" 

gördük, şimdi ben seçmiş gerektiğini düşünüyorum benim çabaları yerine bir-üç-yakalama-grubunun pick--orta için gregexpr-regmatches paradigma stratejisi:

> 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" 
1

sonra yakalama dayanır ve bir IP adresi uymayacak:

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

İşin garibi, ben ile başladı oldukça düzenli ifade değil. işe yaramadı birini çalıştığımda, ben Perl geri ve test gitmek düşündük:

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"; 

Ve bu iyi görünüyordu:

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

Yani aynı regex doğru, R çalışması gerekir?

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

Görünüşe göre değil. Hatta çift tırnaklı dizginin, new RegExp(" ... ") ile Javascript'te denendikten sonra doğru olduğunu da doğruladım ve o da iyi çalıştı. R ile ilgili farklı olan şeyden emin değilsiniz, ancak negatif işaret karakter sınıfını kaldırmak hile yaptı.

+0

R, Perl olmayan regex için Ville Laurikari'nin (http://laurikari.net/tre/) TRE kütüphanesinin sürümünü kullanır. –

İlgili konular