2015-05-03 21 views
7

Stavo cercando di rispondere a una domanda (che in seguito è stata cancellata) che penso stia chiedendo di estrarre rappresentazioni testuali di notazione scientifica. (Utilizzando l'implementazione di re di un'espressione regolare che richiede doppie escape per i meta-caratteri e può essere utilizzata in modalità puro PCRE o Perl, la differenza tra le quali non capisco davvero.) Ho risolto la maggior parte del compito ma sembra ancora non riuscire a catturare il segno meno negativo all'interno di un gruppo di cattura. L'unico modo mi sembra di farlo per avere successo è quello di utilizzare il leader open-parentesi:Come acquisire il segno meno nella notazione scientifica con 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" 

ho cercato SO per quanto di mia pazienza con termini come `notazione scientifica regex meno

+0

È possibile aggiornare alla domanda per mostrare chiaramente l'input iniziale e l'output desiderato? –

+0

La domanda crea il vettore di caratteri di input come input usando il codice R, e ho postato due risposte corrette che si basavano sul metodo che ho chiamato "barare". Non so come potrebbe essere più riproducibile –

+1

@TimBiegeleisen Negli ultimi tre '" 1.33333e-40 "' è diverso – akrun

risposta

6

si può provare

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

Usando metodo basato sulla cattura dopo che conducono parentesi

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

Penso che 'stringr' ora usi il codice in qualche altro pacchetto, ma non ne vedo menzione nel pacchetto NEWS. –

+0

@BondedDust Sembra così, sto ricevendo il messaggio che 'perl è deprecato. Si prega di utilizzare regexp invece'. – akrun

+0

@BondedDust In base a https://github.com/hadley/stringr Si basa su stringi che utilizza la libreria ICU per fornire implementazioni rapide e corrette delle manipolazioni di stringhe comuni – akrun

2

Ragionando che era la capacità "avida" del primo gruppo di cattura "(. +)" A inghiottire il segno meno che era opzionale nel secondo gruppo di cattura, ho terminato il primo gruppo di cattura con una classe di caratteri di negazione e ora hanno successo. Questo sembra ancora rozzo e sperare che ci sia qualcosa di più elegante. Nella ricerca hanno visto codice Python che sembra implicare che non ci sono definizioni regex di "& 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" 

Dopo aver guardato il codice in str_extract_all che utilizza substr per estrarre le partite, ora penso avrei dovuto scegliere la gregexpr-regmatches paradigma per i miei sforzi, piuttosto che il pick-the-middle of-a-tre-capture-Strategy Group:

> 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

Questo sembra funzionare, e non corrisponderà un indirizzo IP:

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

Stranamente, che non è proprio la regex ho iniziato con. Quando provare uno non ha funzionato, ho pensato di tornare indietro e di prova in 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"; 

E che sembrava buono:

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

Così la stessa regex dovrebbe funzionare in R, giusto?

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

Apparentemente no. Ho anche confermato che la stringa doppia citazione è corretta provandola in Javascript con new RegExp(" ... "), e ha funzionato bene anche lì. Non sono sicuro che cosa c'è di diverso in R, ma rimuovere la classe di caratteri con segno negato ha fatto il trucco.

+0

R utilizza la versione della biblioteca TRE di Ville Laurikari (http://laurikari.net/tre/) per la regex non Perl. –

Problemi correlati