2010-02-03 1 views
73

J'essaie d'extraire un nombre d'une chaîne.Extrait une correspondance d'expression régulière

Et de faire quelque chose comme [0-9]+ sur la chaîne "aaa12xxx" et obtenir "12".

je pensais que ce serait quelque chose comme:

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

Et puis je me suis dit ...

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

Mais j'ai une certaine forme de réponse à faire:

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

Il y a un petit détail qui me manque.

Répondre

120

Utilisez le nouveau paquet stringr qui enveloppe tout l'expression régulière existante fonctionne dans une syntaxe cohérente et ajoute quelques qui manquent:

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

(presque) exactement ce que je avais besoin, mais comme je l'ai commencé à taper dans '? str_extract' j'ai vu' str_extract_all' et la vie était bien à nouveau. – dwanderson

19

Peut-être

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

Une façon serait ceci:

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

Maintenant, remarquez regexpr vous donne le début et les indices de fin de la chaîne:

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

Ainsi, vous pouvez utiliser cette info avec la sous-fonction

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

Je suis sûr qu'il y a une manière plus élégante de faire ceci, mais c'était la manière la plus rapide que j'ai pu trouver. Alternativement, vous pouvez utiliser sub/gsub pour supprimer ce que vous ne voulez pas quitter.

9

Vous pouvez utiliser la correspondance paresseuse de regexs PERL:

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

Si vous essayez de remplacer les non-chiffres, une erreur se produira dans ce cas. Utilisation de strapply dans le paquetage gsubfn

+2

N'avez pas besoin de PERL si vous êtes prêt à utiliser le légèrement plus laid "[^ 0-9] * ([0-9] +). *" –

2

strapply est comme appliquent en ce que les arguments sont l'objet, modificateur et de la fonction, sauf que l'objet est un vecteur de chaînes (plutôt que d'un tableau) et le modificateur est une expression régulière (plutôt que d'une marge):

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

Cela dit de faire correspondre un ou plusieurs chiffres (\ d +) dans chaque composant de x en faisant passer chaque correspondance par le biais de .numeric. Il renvoie une liste dont les composants sont des vecteurs de correspondances des composants respectifs de x. En regardant la sortie, nous voyons que le premier composant de x a une correspondance qui est 13 et la deuxième composante de x a deux correspondances qui sont 12 et 34. Voir http://gsubfn.googlecode.com pour plus d'informations.

2

Utilisez des parenthèses de capture dans l'expression régulière et les références de groupe dans le remplacement. Tout entre parenthèses est mémorisé. Ensuite, ils sont accessibles par \ 2, le premier élément. La première barre oblique inverse échappe à l'interprétation du backslash dans R afin qu'il soit transmis à l'analyseur d'expressions régulières.

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

Il est sans doute un peu hâtif de dire « ignorer les fonctions standard » - le fichier d'aide pour ?gsub même spécifiquement des références dans « Voir aussi »:

« regmatches » pour extraire apparié sous-chaînes basées sur les résultats de 'regexpr', 'gregexpr' et 'regexec'.

donc ça marchera, et est assez simple:

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

Une autre solution:

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

Une différence importante entre ces approches du comportement avec des non-matches. Par exemple, la méthode regmatches ne peut pas retourner une chaîne de la même longueur que l'entrée s'il n'y a pas un match dans toutes les positions

> 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

Vous pouvez écrire vos fonctions REGEX avec C++, les compiler dans une DLL et appel les de 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(); 
    } 
} 
    }; 

appel à R comme

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)