Extraire une correspondance d'expression régulière


112

J'essaye d'extraire un nombre d'une chaîne.

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

Je pensais que ce serait quelque chose comme:

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

Et puis j'ai pensé ...

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

Mais j'ai eu une forme de réponse en faisant:

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

Il me manque un petit détail.

Réponses:


167

Utilisez le nouveau package stringr qui encapsule toutes les expressions régulières existantes fonctionne dans une syntaxe cohérente et en ajoute quelques-unes qui manquent:

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

3
(presque) exactement ce dont j'avais besoin, mais en commençant à taper, ?str_extractj'ai vu str_extract_allet la vie était à nouveau belle.
dwanderson

94

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

'regmatches' pour extraire les sous-chaînes correspondantes en fonction des résultats de 'regexpr', 'gregexpr' et 'regexec'.

Donc, cela fonctionnera, et c'est assez simple:

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

27

Peut être

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

15

Vous pouvez utiliser la correspondance différée des expressions rationnelles PERL:

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

Essayer de remplacer des non-chiffres entraînera une erreur dans ce cas.


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

5

Une façon serait la suivante:

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

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

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

Vous pouvez donc utiliser cette information avec la fonction substr

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

Je suis sûr qu'il existe un moyen plus élégant de le faire, mais c'était le moyen le plus rapide que j'ai pu trouver. Alternativement, vous pouvez utiliser sub / gsub pour supprimer ce que vous ne voulez pas laisser ce que vous voulez.


5

Utilisez des parenthèses de capture dans l'expression régulière et des références de groupe dans le remplacement. Tout ce qui est entre parenthèses est mémorisé. Ensuite, ils sont accédés par \ 2, le premier élément. La première barre oblique inverse échappe à l'interprétation de la barre oblique inverse dans R afin qu'elle soit transmise à l'analyseur d'expression régulière.

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

2

Utilisation de strapply dans le package gsubfn. strapply est comme apply en ce que les arguments sont objet, modificateur et fonction sauf que l'objet est un vecteur de chaînes (plutôt qu'un tableau) et que le modificateur est une expression régulière (plutôt qu'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 passant chaque correspondance par as.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 le deuxième composant de x a deux correspondances qui sont 12 et 34. Voir http://gsubfn.googlecode.com pour plus d'informations.


1

Une autre solution:

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

1

Une différence importante entre ces approches est le comportement en cas de non-concordance. Par exemple, la méthode regmatches peut ne pas renvoyer une chaîne de la même longueur que l'entrée s'il n'y a pas de correspondance 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  

1

Une solution à cette question

library(stringr)
str_extract_all("aaa12xxx", regex("[[:digit:]]{1,}"))
# [[1]]
# [1] "12"

[[: chiffre:]] : chiffre [0-9]

{1,} : correspond au moins 1 fois


0

En utilisant le package unglue, nous ferions ce qui suit:

# install.packages("unglue")
library(unglue)
unglue_vec(c("aaa12xxx", "aaaARGH!xxx"), "{prefix}{number=\\d+}{suffix}", var = "number")
#> [1] "12" NA

Créé le 06/11/2019 par le package reprex (v0.3.0)

Utilisez l' convertargument pour convertir automatiquement en nombre:

unglue_vec(
  c("aaa12xxx", "aaaARGH!xxx"), 
  "{prefix}{number=\\d+}{suffix}", 
  var = "number", 
  convert = TRUE)
#> [1] 12 NA

-2

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

appeler 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)

4
Ceci est complètement inutile. Voir les réponses de "thelatemail" ou "Robert" pour une solution facile à l'intérieur de R.
Daniel Hoop
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.