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.

tovare
sumber

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"
hadley
sumber
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"
thelatemail
sumber
27

Mungkin

gsub("[^0-9]", "", "aaa12xxxx")
# [1] "12"
Marek
sumber
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.

Jyotirmoy Bhattacharya
sumber
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.

Robert
sumber
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")
Ragy Isaac
sumber
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.

G. Grothendieck
sumber
1

Solusi lain:

temp = regexpr('\\d', "aaa12xxx");
substr("aaa12xxx", temp[1], temp[1]+attr(temp,"match.length")[1])
pari
sumber
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  
andyyy
sumber
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

Tho Vu
sumber
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
Moody_Mudskipper
sumber
-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)

sumber
4
Ini sama sekali tidak perlu. Lihat jawaban dari "thelatemail" atau "Robert" untuk solusi mudah di dalam R.
Daniel Hoop