Ekstrak pencocokan ekspresi reguler


111

Saya mencoba mengekstrak angka dari string.

Dan lakukan sesuatu seperti [0-9]+pada tali "aaa12xxx"dan dapatkan "12".

Saya pikir itu akan menjadi seperti:

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

Dan kemudian saya pikir ...

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

Tapi saya mendapat beberapa bentuk tanggapan yang dilakukan:

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

Ada detail kecil yang saya lewatkan.

Jawaban:


167

Gunakan paket stringr baru yang membungkus semua ekspresi reguler yang ada yang beroperasi dalam sintaks yang konsisten dan menambahkan beberapa yang hilang:

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

3
(hampir) persis seperti yang saya butuhkan, tetapi ketika saya mulai mengetik, ?str_extractsaya melihat str_extract_alldan hidup menjadi baik lagi.
dwanderson

94

Mungkin agak terburu-buru untuk mengatakan ' abaikan fungsi standar ' - file bantuan ?gsubbahkan untuk referensi khusus di 'Lihat juga':

'regmatches' untuk mengekstrak substring yang cocok berdasarkan hasil 'regexpr', 'gregexpr' dan 'regexec'.

Jadi ini akan berhasil, dan cukup sederhana:

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

27

Mungkin

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

15

Anda dapat menggunakan pencocokan malas PERL regex:

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

Mencoba mengganti non-digit akan menyebabkan kesalahan dalam kasus ini.


4
Tidak perlu PERL jika Anda ingin menggunakan "[^ 0-9] * ([0-9] +). *"
Jyotirmoy Bhattacharya

5

Salah satu caranya adalah ini:

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

Sekarang, perhatikan regexpr memberi Anda indeks awal dan akhir dari string:

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

Jadi Anda bisa menggunakan info itu dengan fungsi substr

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

Saya yakin ada cara yang lebih elegan untuk melakukan ini, tetapi ini adalah cara tercepat yang dapat saya temukan. Atau, Anda dapat menggunakan sub / gsub untuk menghapus apa yang Anda tidak ingin meninggalkan apa yang Anda inginkan.


5

Gunakan tanda kurung pengambilan dalam ekspresi reguler dan referensi grup sebagai pengganti. Semua yang ada di dalam tanda kurung akan diingat. Kemudian mereka diakses oleh \ 2, item pertama. Garis miring terbalik pertama lolos dari interpretasi garis miring terbalik di R sehingga diteruskan ke parser ekspresi reguler.

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

2

Menggunakan strapply dalam paket gsubfn. strapply adalah seperti terapkan karena argsnya adalah objek, pengubah dan fungsi kecuali bahwa objek tersebut adalah vektor string (bukan array) dan pengubahnya adalah ekspresi reguler (bukan margin):

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

Ini mengatakan untuk mencocokkan satu atau lebih digit (\ d +) di setiap komponen x melewati setiap kecocokan melalui as.numeric. Ini mengembalikan daftar yang komponennya adalah vektor yang cocok dengan masing-masing komponen x. Melihat outputnya kita melihat bahwa komponen pertama x memiliki satu kecocokan yaitu 13 dan komponen kedua x memiliki dua kecocokan yaitu 12 dan 34. Lihat http://gsubfn.googlecode.com untuk info lebih lanjut.


1

Solusi lain:

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

1

Satu perbedaan penting antara pendekatan ini adalah perilaku dengan yang tidak cocok. Misalnya, metode regmatches tidak boleh mengembalikan string dengan panjang yang sama dengan masukan jika tidak ada kecocokan di semua posisi

> 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

Solusi untuk pertanyaan ini

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

[[: digit:]] : digit [0-9]

{1,} : Cocok setidaknya 1 kali


0

Menggunakan paket unglue kami akan melakukan hal berikut:

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

Dibuat pada 2019-11-06 oleh paket reprex (v0.3.0)

Gunakan convertargumen untuk mengonversi menjadi angka secara otomatis:

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

-2

Anda dapat menulis fungsi regex Anda dengan C ++, mengompilasinya menjadi DLL dan memanggilnya dari 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();
    }
}
    };

panggil R sebagai

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
Ini sama sekali tidak perlu. Lihat jawaban dari "thelatemail" atau "Robert" untuk solusi mudah di dalam R.
Daniel Hoop
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.