Wyodrębnij dopasowanie wyrażenia regularnego


112

Próbuję wyodrębnić liczbę z ciągu.

I zrób coś podobnego [0-9]+do sznurka "aaa12xxx"i zdobądź"12" .

Pomyślałem, że to będzie coś takiego:

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

A potem pomyślałem ...

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

Ale otrzymałem jakąś formę odpowiedzi:

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

Brakuje mi małego szczegółu.

Odpowiedzi:


167

Użyj nowego pakietu stringr, który opakowuje wszystkie istniejące wyrażenia regularne w spójnej składni i dodaje kilka, których brakuje:

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

3
(prawie) dokładnie to, czego potrzebowałem, ale kiedy zacząłem pisać ?str_extract, zobaczyłem str_extract_alli życie znów było dobre.
dwanderson

94

Prawdopodobnie jest trochę pochopne powiedzenie `` ignoruj ​​standardowe funkcje '' - plik pomocy ?gsubnawet dla konkretnych odniesień w `` Zobacz także '':

„regmatches” do wyodrębniania dopasowanych podciągów na podstawie wyników „regexpr”, „gregexpr” i „regexec”.

Więc to zadziała i jest dość proste:

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


15

Możesz użyć leniwego dopasowywania wyrażeń regularnych PERL:

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

Próba zastąpienia cyfr niecyfrowych doprowadzi w tym przypadku do błędu.


4
Nie potrzebujesz PERL, jeśli chcesz użyć nieco brzydszego „[^ 0-9] * ([0-9] +). *”
Jyotirmoy Bhattacharya,

5

Jednym ze sposobów byłoby to:

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

Teraz zauważ, że wyrażenie regularne podaje początkowe i końcowe indeksy łańcucha:

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

Możesz więc użyć tej informacji z funkcją substr

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

Jestem pewien, że istnieje bardziej elegancki sposób, aby to zrobić, ale był to najszybszy sposób, jaki znalazłem. Alternatywnie możesz użyć sub / gsub, aby usunąć to, czego nie chcesz, zostawić tego, czego chcesz.


5

Użyj nawiasów przechwytujących w wyrażeniu regularnym i grupuj odwołania w zamianie. Wszystko w nawiasach zostaje zapamiętane. Następnie uzyskuje do nich dostęp \ 2, pierwszy element. Pierwszy ukośnik odwrotny wymyka interpretację ukośnika odwrotnego w R, dzięki czemu jest przekazywany do parsera wyrażeń regularnych.

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

2

Używanie strapply w pakiecie gsubfn. strapply jest podobny do zastosowania w tym, że argumenty są obiektem, modyfikatorem i funkcją, z tym wyjątkiem, że obiekt jest wektorem łańcuchów (a nie tablicą), a modyfikator jest wyrażeniem regularnym (a nie marginesem):

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

To mówi, aby dopasować jedną lub więcej cyfr (\ d +) w każdym składniku x, przechodząc przez każde dopasowanie przez as.numeric. Zwraca listę, której składowe są wektorami dopasowań odpowiednich składników x. Patrząc na wynik, widzimy, że pierwszy składnik x ma jedno dopasowanie, które wynosi 13, a drugi składnik x ma dwa dopasowania, czyli 12 i 34. Więcej informacji można znaleźć pod adresem http://gsubfn.googlecode.com .


1

Inne rozwiązanie:

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

1

Jedna ważna różnica między tymi podejściami dotyczy zachowania z jakimikolwiek niezgodnościami. Na przykład metoda regmatches może nie zwrócić ciągu o tej samej długości co dane wejściowe, jeśli nie ma dopasowania na wszystkich pozycjach

> 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

Rozwiązanie na to pytanie

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

[[: digit:]] : cyfra [0–9]

{1,} : pasuje co najmniej 1 razy


0

Odklejając pakiet, wykonalibyśmy następujące czynności:

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

Utworzono 06.11.2019 przez pakiet reprex (v0.3.0)

Użyj convertargumentu, aby automatycznie przekonwertować na liczbę:

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

-2

Możesz napisać swoje funkcje regex w C ++, skompilować je do DLL i wywołać je z 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();
    }
}
    };

zadzwoń w R as

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
To jest zupełnie niepotrzebne. Zobacz odpowiedzi „thelatemail” lub „Robert”, aby znaleźć łatwe rozwiązanie w R.
Daniel Hoop
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.