2015-05-03 7 views
7

Ich habe versucht, eine Frage zu beantworten (das später gelöscht wurde), dass ich Text Darstellungen wissenschaftlicher Notation zu extrahieren frage denken. (Die Implementierung von Regex von R, die doppelte Escapes für Meta-Zeichen erfordert und entweder im reinen PCRE- oder Perl-Modus verwendet werden kann, den Unterschied zwischen denen ich nicht wirklich verstehe.) Ich habe den größten Teil der Aufgabe gelöst, aber scheint immer noch Das führende Minuszeichen in einer Erfassungsgruppe kann nicht erfasst werden. Der einzige Weg, ich scheine es zu bekommen, ist, gelingt durch die führende Open-Klammer mit:Wie zeichne Minuszeichen in wissenschaftlicher Notation mit Regex?

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

I SO mit Begriffen wie `wissenschaftliche Schreibweise regex minus' soweit meiner Geduld gesucht haben

+0

Können Sie auf Ihre Frage aktualisieren eindeutig den Starteingang und gewünschte Ausgabe zu zeigen? –

+0

Die Frage erstellt den Eingabezeichenvektor als Eingabe mit R-Code, und ich habe zwei richtige Antworten gepostet, die auf der Methode beruhen, die ich "Cheaten" nannte. Ich weiß nicht, wie es –

+1

@TimBiegeleisen In den letzten drei '„1.33333e-40“nicht mehr reproduzierbar sein könnte' ist anders – akrun

Antwort

6

können Sie versuchen,

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

Unter Verwendung der Methode basiert nach führenden Klammern auf die Erfassung

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

Ich denke '' straerr' verwendet jetzt den Code in einem anderen Paket, aber ich sehe keine Erwähnung davon im Paket NEWS. –

+0

@BondedDust Es scheint so, ich bekomme die Nachricht, dass 'Perl veraltet ist. Bitte verwenden Sie stattdessen regexp. – akrun

+0

@BondedDust Nach https://github.com/hadley/stringr ist oben auf stringi gebaut, die die ICU-Bibliothek verwendet – akrun

2

Reasoning, dass es die „gierige“ Kapazität der „(. +)“ wurde ersten Einfanggruppe das Minuszeichen zu verschlingen, die in der zweiten Einfang-Gruppe optional war, beenden ich die erste Einfang-Gruppe mit einer Negation-character-Klasse und jetzt Erfolg haben. Das wirkt immer noch klobig und hofft, dass es etwas Eleganteres gibt. Bei der Suche haben Python-Code gesehen, dass es regex Definitionen von „& real_number“> auf den Code

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

Nach einem Blick in str_extract_all scheint zu implizieren, die substr Spiele zu extrahieren verwendet, ich glaube, jetzt sollte ich die gewählt haben gregexpr-regmatches Paradigma für meine Bemühungen, anstatt der Pick-the-Middle-of-a-drei-Capture-Gruppenstrategie:

> 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

Dies scheint zu funktionieren, und eine IP-Adresse nicht überein: Seltsamer

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

, das ist nicht ganz regex ich mit gestartet. Wenn man versuchen, funktionierte nicht, dachte ich, ich würde in Perl zurück und Test gehen:

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

Und das sah gut aus:

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

Also die gleiche Regex sollte in R arbeiten, nicht wahr?

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

Anscheinend nicht. Ich bestätigte auch, dass die Strings in doppelten Anführungszeichen, indem sie es in Javascript versuchen, korrekt ist mit new RegExp(" ... "), und es hat gut funktioniert es auch. Nicht sicher, was an R anders ist, aber das Entfernen der Zeichenklasse mit negiertem Zeichen hat den Trick gemacht.

+0

R verwendet die Version von TRE-Bibliothek von Ville Laurikari (http://laurikari.net/tre/) für den nicht-Perl regex. –

Verwandte Themen