Ekstrak substring sesuai dengan pola

136

Misalkan saya memiliki daftar string:

string = c("G1:E001", "G2:E002", "G3:E003")

Sekarang saya berharap untuk mendapatkan vektor string yang hanya berisi bagian setelah titik dua ":", yaitu substring = c(E001,E002,E003).

Apakah ada cara yang nyaman dalam R untuk melakukan ini? Menggunakan substr?

alittleboy
sumber

Jawaban:

239

Berikut ini beberapa cara:

1) sub

sub(".*:", "", string)
## [1] "E001" "E002" "E003"

2) strsplit

sapply(strsplit(string, ":"), "[", 2)
## [1] "E001" "E002" "E003"

3) baca

read.table(text = string, sep = ":", as.is = TRUE)$V2
## [1] "E001" "E002" "E003"

4) substring

Ini mengasumsikan bagian kedua selalu dimulai pada karakter ke-4 (yang merupakan kasus pada contoh dalam pertanyaan):

substring(string, 4)
## [1] "E001" "E002" "E003"

4a) substring / regex

Jika titik dua tidak selalu dalam posisi yang diketahui, kita dapat memodifikasi (4) dengan mencarinya:

substring(string, regexpr(":", string) + 1)

5) strapplyc

strapplyc mengembalikan bagian yang di-kurung:

library(gsubfn)
strapplyc(string, ":(.*)", simplify = TRUE)
## [1] "E001" "E002" "E003"

6) baca.dcf

Yang ini hanya berfungsi jika substring sebelum titik dua adalah unik (seperti yang ada pada contoh di pertanyaan). Juga mengharuskan pemisah menjadi titik dua (yang ada dalam pertanyaan). Jika pemisah yang berbeda digunakan maka kita bisa menggunakannya subuntuk menggantinya dengan titik dua terlebih dahulu. Sebagai contoh, jika separator itu _kemudianstring <- sub("_", ":", string)

c(read.dcf(textConnection(string)))
## [1] "E001" "E002" "E003"

7) terpisah

7a) Menggunakan tidyr::separatekita membuat bingkai data dengan dua kolom, satu untuk bagian sebelum titik dua dan satu untuk setelah, dan kemudian mengekstrak yang terakhir.

library(dplyr)
library(tidyr)
library(purrr)

DF <- data.frame(string)
DF %>% 
  separate(string, into = c("pre", "post")) %>% 
  pull("post")
## [1] "E001" "E002" "E003"

7b) Bergantian separatedapat digunakan untuk membuat postkolom dan kemudian unlistdan unnamebingkai data yang dihasilkan:

library(dplyr)
library(tidyr)

DF %>% 
  separate(string, into = c(NA, "post")) %>% 
  unlist %>%
  unname
## [1] "E001" "E002" "E003"

8) trimws Kita dapat menggunakan trimwsuntuk memotong karakter kata dari kiri dan kemudian menggunakannya lagi untuk memotong titik dua.

trimws(trimws(string, "left", "\\w"), "left", ":")
## [1] "E001" "E002" "E003"

Catatan

Input stringdiasumsikan:

string <- c("G1:E001", "G2:E002", "G3:E003")
G. Grothendieck
sumber
Saya punya variabel dalam tabel lebur yang memiliki _sebagai pemisah dan membuat dua variabel terpisah untuk awalan dan akhiran berdasarkan jawaban @Grothendieck: prefix <- sub("_.*", "", variable)dan suffix <- sub(".*_", "", variable)
swihart
Akan menyenangkan melihat microbenchmarking dari jawaban yang luar biasa ini!
patL
25

Misalnya menggunakan gsubatausub

    gsub('.*:(.*)','\\1',string)
    [1] "E001" "E002" "E003"
agstudy
sumber
dapatkah Anda menjelaskan apa ini '. * (* dan seterusnya, apakah di sana tepatnya? Saya mengalami kesulitan untuk menciptakan ini dalam pengaturan yang hanya sedikit berbeda ...
Peter Pan
1
@PeterPan Ini menangkap dan mengembalikan kelompok karakter yang muncul setelah titik dua. Jika senar yang cocok lebih rumit dan Anda ingin tetap di pangkalan R ini berfungsi dengan baik.
Clark Fitzgerald
14

Ini jawaban sederhana lain

gsub("^.*:","", string)
Ragy Isaac
sumber
9

Terlambat ke pesta, tetapi untuk anak cucu, paket stringr (bagian dari paket "tidyverse" paket populer) sekarang menyediakan fungsi dengan tanda tangan yang diselaraskan untuk penanganan string:

string <- c("G1:E001", "G2:E002", "G3:E003")
# match string to keep
stringr::str_extract(string = string, pattern = "E[0-9]+")
# [1] "E001" "E002" "E003"

# replace leading string with ""
stringr::str_remove(string = string, pattern = "^.*:")
# [1] "E001" "E002" "E003"
CSJCampbell
sumber
2
Bukankah ini menemukan angka pertama yang dimulai dengan E, daripada semuanya setelah titik dua?
Mark Neal
6

Ini harus dilakukan:

gsub("[A-Z][1-9]:", "", string)

memberi

[1] "E001" "E002" "E003"
pengguna1981275
sumber
3

Jika Anda menggunakan data.tablemaka itu tstrsplit()adalah pilihan alami:

tstrsplit(string, ":")[[2]]
[1] "E001" "E002" "E003"
sindri_baldur
sumber
3

The unglue paket menyediakan alternatif, tidak ada pengetahuan tentang ekspresi reguler diperlukan untuk kasus sederhana, di sini kita akan melakukan:

# install.packages("unglue")
library(unglue)
string = c("G1:E001", "G2:E002", "G3:E003")
unglue_vec(string,"{x}:{y}", var = "y")
#> [1] "E001" "E002" "E003"

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

Info lebih lanjut: https://github.com/moodymudskipper/unglue/blob/master/README.md

Moody_Mudskipper
sumber