2014-07-16 17 views
11

Tôi đang tìm kiếm một cách hiệu quả để trích xuất tất cả các kết quả khớp giữa hai đoạn trong một chuỗi ký tự. Ví dụ. nói tôi muốn trích xuất tất cả các chuỗi con chứa giữa chuỗiR: cách nhanh nhất để trích xuất tất cả các chất nền chứa giữa hai đế

start="strt" 

stop="stp" 
in string 
x="strt111stpblablastrt222stp" 

Tôi muốn để có được vector

"111" "222" 

cách hiệu quả nhất để làm điều này trong R là gì? Sử dụng một biểu thức chính quy có lẽ? Hay có cách nào tốt hơn?

Trả lời

12

Đối với một cái gì đó đơn giản như thế này, cơ sở R xử lý việc này tốt.

Bạn có thể bật PCRE bằng cách sử dụng perl=T và sử dụng lookaround xác nhận.

x <- 'strt111stpblablastrt222stp' 
regmatches(x, gregexpr('(?<=strt).*?(?=stp)', x, perl=T))[[1]] 
# [1] "111" "222" 

Giải thích:

(?<=   # look behind to see if there is: 
    strt  # 'strt' 
)    # end of look-behind 
.*?   # any character except \n (0 or more times) 
(?=   # look ahead to see if there is: 
    stp   # 'stp' 
)    # end of look-ahead 

EDIT: Cập nhật bên dưới câu trả lời theo cú pháp mới.

Bạn cũng có thể xem xét sử dụng gói stringi.

library(stringi) 
x <- 'strt111stpblablastrt222stp' 
stri_extract_all_regex(x, '(?<=strt).*?(?=stp)')[[1]] 
# [1] "111" "222" 

rm_between từ gói qdapRegex.

library(qdapRegex) 
x <- 'strt111stpblablastrt222stp' 
rm_between(x, 'strt', 'stp', extract=TRUE)[[1]] 
# [1] "111" "222" 
+0

Nhiều thx - đó là hoàn hảo và thx cho lời giải thích rất tốt đẹp! –

+0

@TomWenseleers bạn được chào đón nhiều. – hwnd

+0

+1, để hoàn thành, tôi sẽ đề cập rằng 'strt \ K' có thể thay thế' (? <= Strt) '(không có gì sai với nó, chỉ một tùy chọn khác) – zx81

2

Vì có thể có một số khởi động/dừng chuỗi mỗi đầu vào, tôi nghĩ rằng một regex sẽ là giải pháp hiệu quả nhất:

(?<=strt)(?:(?!stp).)* 

sẽ phù hợp với tất cả mọi thứ sau strt cho đến cuối của chuỗi hoặc stp, nào đến Đầu tiên. Nếu bạn muốn xác nhận rằng luôn có một stp, hãy thêm (?=stp) vào cuối regex. Bạn thậm chí có thể áp dụng regex này cho một vector.

regmatches(subject, gregexpr("(?<=strt)(?:(?!stp).)*", subject, perl=TRUE)); 
5

Bạn cũng có thể xem xét:

library(qdap) 
unname(genXtract(x, "strt", "stp")) 
#[1] "111" "222" 

Speed ​​so

x1 <- rep(x,1e5) 
system.time(res1 <- regmatches(x1,gregexpr('(?<=strt).*?(?=stp)',x1,perl=T))) 
# user system elapsed 
# 2.187 0.000 2.015 

system.time(res2 <- regmatches(x1, gregexpr("(?<=strt)(?:(?!stp).)*", x1, perl=TRUE))) 
#user system elapsed 
# 1.902 0.000 1.780 

system.time(res3 <- str_extract_all(x1, perl('(?<=strt).*?(?=stp)'))) 
# user system elapsed 
# 6.990 0.000 6.636 

system.time(res4 <- genXtract(x1, "strt", "stp")) ##setNames(genXtract(...), NULL) is a bit slower 
# user system elapsed 
# 1.457 0.000 1.414 

names(res4) <- NULL 
identical(res1,res4) 
#[1] TRUE 
+0

Thx cho tùy chọn thêm nhanh hơn một chút - thật tuyệt !! –

4

Nếu bạn đang nói về tốc độ trong chuỗi R chỉ có một gói để làm điều này - stringi

x <- "strt111stpblablastrt222stp" 
hwnd <- function(x1) regmatches(x1,gregexpr('(?<=strt).*?(?=stp)',x1,perl=T)) 
Tim <- function(x1) regmatches(x1, gregexpr("(?<=strt)(?:(?!stp).)*", x1, perl=TRUE)) 
stringr <- function(x1) str_extract_all(x1, perl('(?<=strt).*?(?=stp)')) 
akrun <- function(x1) genXtract(x1, "strt", "stp") 
stringi <- function(x1) stri_extract_all_regex(x1, perl('(?<=strt).*?(?=stp)')) 

require(microbenchmark) 
microbenchmark(stringi(x), hwnd(x), Tim(x), stringr(x)) 
Unit: microseconds 
     expr  min  lq median  uq  max neval 
stringi(x) 46.778 58.1030 64.017 67.3485 123.398 100 
    hwnd(x) 61.498 73.1095 79.084 85.5190 111.757 100 
    Tim(x) 60.243 74.6830 80.755 86.3370 102.678 100 
stringr(x) 236.081 261.9425 272.115 279.6750 440.036 100 

Rất tiếc, tôi không thể kiểm tra giải pháp @akrun vì gói qdap có một số lỗi trong quá trình cài đặt. Và chỉ có giải pháp của mình trông giống như một giải pháp có thể đánh bại chuỗi ...

+6

Tôi hy vọng 'genXtract' sẽ chậm hơn nhiều (chậm hơn 10-20 lần). Nó được xây dựng cho sự linh hoạt và dễ sử dụng. Trong nhiều trường hợp, thời gian của nhà nghiên cứu có giá trị hơn thời gian tính toán. Nếu đó là trường hợp 'genXtract' là một lựa chọn tuyệt vời. Nếu bạn là sau khi tốc độ sau đó tôi, như bạn, là một fan hâm mộ lớn của 'stringi'. –

+5

Tôi không chỉ là fan 'stringi' - tôi là tác giả :) – bartektartanus

Các vấn đề liên quan