2010-02-03 14 views
73

Estoy tratando de extraer un número de una cadena.Extraiga una coincidencia de expresión regular

Y haga algo como [0-9]+ en la cadena "aaa12xxx" y obtenga "12".

pensé que sería algo así como:

> grep("[0-9]+", "aaa12xxx", value=TRUE) 
[1] "aaa12xxx" 

Y entonces me di cuenta ...

> sub("[0-9]+", "\\1", "aaa12xxx") 
[1] "aaaxxx" 

pero me dio algún tipo de respuesta haciendo:

> sub("[0-9]+", "ARGH!", "aaa12xxx") 
[1] "aaaARGH!xxx" 

Hay un pequeño detalle que me falta.

Respuesta

120

uso del nuevo paquete stringr que envuelve toda la expresión regular existente opera en una sintaxis coherente y añade unos pocos que faltan:

library(stringr) 
str_locate("aaa12xxx", "[0-9]+") 
#  start end 
# [1,]  4 5 
str_extract("aaa12xxx", "[0-9]+") 
# [1] "12" 
+0

(casi) exactamente lo que necesitaba, pero cuando empecé a escribir en '?' str_extract' vi str_extract_all' y la vida era bien otra vez. – dwanderson

19

Tal

gsub("[^0-9]", "", "aaa12xxxx") 
# [1] "12" 
2

Una forma sería la siguiente:

test <- regexpr("[0-9]+","aaa12456xxx") 

Ahora, el aviso RegExpr le da la inicial y final de los índices de la cadena:

> test 
[1] 4 
attr(,"match.length") 
[1] 5 

Por lo que puede utilice esa información con la función substr

substr("aaa12456xxx",test,test+attr(test,"match.length")-1) 

Estoy seguro de que hay una forma más elegante de hacerlo, pero esta fue la forma más rápida que pude encontrar. Alternativamente, puede usar sub/gsub para quitar lo que no desea dejar lo que desea.

9

Puede utilizar la concordancia perezosa Perl regexs':

> sub(".*?([0-9]+).*", "\\1", "aaa12xx99",perl=TRUE) 
[1] "12" 

Intentar sustituir no dígitos generará un error en este caso.

+2

No necesita PERL si está dispuesto a usar el ligeramente más feo "[^ 0-9] * ([0-9] +). *" –

2

Uso de strapply en el paquete gsubfn. strapply es como se aplican en que los args son objeto, modificador y función, excepto que el objeto es un vector de cadenas (en lugar de una matriz) y el modificador es una expresión regular (en lugar de un margen):

library(gsubfn) 
x <- c("xy13", "ab 12 cd 34 xy") 
strapply(x, "\\d+", as.numeric) 
# list(13, c(12, 34)) 

Esto dice que coincida con uno o más dígitos (\ d +) en cada componente de x pasando cada coincidencia por as.numeric. Devuelve una lista cuyos componentes son vectores de coincidencias de los componentes respectivos de x. Mirando la salida vemos que el primer componente de x tiene una coincidencia que es 13 y el segundo componente de x tiene dos coincidencias que son 12 y 34. Consulte http://gsubfn.googlecode.com para obtener más información.

2

Utilice la captura de paréntesis en la expresión regular y las referencias de grupo en la sustitución. Cualquier cosa entre paréntesis es recordado. Luego se accede por \ 2, el primer elemento. La primera barra invertida escapa a la interpretación de la barra invertida en R para que pase al analizador de expresiones regulares.

gsub('([[:alpha:]]+)([0-9]+)([[:alpha:]]+)', '\\2', "aaa12xxx") 
47

Probablemente es un poco apresurado decir 'ignoran las funciones estándar' - el archivo de ayuda para ?gsub referencias incluso específicamente en 'Ver también':

'regmatches' para extraer emparejado subcadenas basadas en los resultados de 'regexpr', 'gregexpr' y 'regexec'.

Así que esto va a funcionar, y es bastante simple:

txt <- "aaa12xxx" 
regmatches(txt,regexpr("[0-9]+",txt)) 
#[1] "12" 
1

Otra solución:

temp = regexpr('\\d', "aaa12xxx"); 
substr("aaa12xxx", temp[1], temp[1]+attr(temp,"match.length")[1]) 
0

Una diferencia importante entre estos enfoques del comportamiento con cualquier no-partidos. Por ejemplo, el método regmatches no puede devolver una cadena con la misma longitud que la entrada si no hay una coincidencia en todas las posiciones

> txt <- c("aaa12xxx","xyz") 

> regmatches(txt,regexpr("[0-9]+",txt)) # could cause problems 

[1] "12" 

> gsub("[^0-9]", "", txt) 

[1] "12" "" 

> str_extract(txt, "[0-9]+") 

[1] "12" NA 
0

Se puede escribir sus funciones de expresiones regulares con C++, compilarlos en un archivo DLL y llamada desde R.

#include <regex> 

    extern "C" { 
    __declspec(dllexport) 
    void regex_match(const char **first, char **regexStr, int *_bool) 
    { 
     std::cmatch _cmatch; 
     const char *last = *first + strlen(*first); 
     std::regex rx(*regexStr); 
     bool found = false; 
     found = std::regex_match(*first,last,_cmatch, rx); 
     *_bool = found; 
    } 

__declspec(dllexport) 
void regex_search_results(const char **str, const char **regexStr, int *N, char **out) 
{ 
    std::string s(*str); 
    std::regex rgx(*regexStr); 
    std::smatch m; 

    int i=0; 
    while(std::regex_search(s,m,rgx) && i < *N) { 
     strcpy(out[i],m[0].str().c_str()); 
     i++; 
     s = m.suffix().str(); 
    } 
} 
    }; 

llamada en I como

dyn.load("C:\\YourPath\\RegTest.dll") 
regex_match <- function(str,regstr) { 
.C("regex_match",x=as.character(str),y=as.character(regstr),z=as.logical(1))$z } 

regex_match("abc","a(b)c") 

regex_search_results <- function(x,y,n) { 
.C("regex_search_results",x=as.character(x),y=as.character(y),i=as.integer(n),z=character(n))$z } 

regex_search_results("aaa12aa34xxx", "[0-9]+", 5) 
Cuestiones relacionadas