2010-02-03 36 views
73

Tôi đang cố trích xuất một số từ một chuỗi.Trích xuất đối sánh cụm từ thông dụng

Và làm điều gì đó như [0-9]+ trên chuỗi "aaa12xxx" và nhận "12".

Tôi nghĩ rằng nó sẽ là một cái gì đó như:

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

Và sau đó tôi đã tìm ...

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

Nhưng tôi có một số hình thức phản ứng thực hiện:

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

Có một chi tiết nhỏ tôi đang thiếu.

Trả lời

120

Sử dụng gói stringr mới mà kết thúc tốt đẹp tất cả các biểu thức chính quy hiện hoạt động trong một cú pháp nhất quán và bổ sung thêm một vài đang thiếu:

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

(gần như) chính xác những gì tôi cần, nhưng khi tôi bắt đầu gõ trong '? str_extract' tôi thấy 'str_extract_all' và cuộc sống tốt nữa. – dwanderson

19

lẽ

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

Một cách sẽ là thế này:

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

Bây giờ, thông báo regexpr mang đến cho bạn bắt đầu và chỉ số kết thúc của chuỗi:

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

Vì vậy, bạn có thể sử dụng thông tin đó với chức năng nền

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

Tôi chắc chắn có một cách thanh lịch hơn để thực hiện việc này, nhưng đây là cách nhanh nhất tôi có thể tìm thấy. Ngoài ra, bạn có thể sử dụng phụ/gsub để loại bỏ những gì bạn không muốn để lại những gì bạn muốn.

9

Bạn có thể sử dụng phù hợp với lười biếng PERL regexs':

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

Cố gắng thay thế các chữ số không sẽ dẫn đến lỗi trong trường hợp này.

+2

Không cần PERL nếu bạn sẵn sàng sử dụng hơi xấu xí hơn "[^ 0-9] * ([0-9] +). *" –

2

Sử dụng strapply trong gói gsubfn. strapply cũng giống như áp dụng trong đó các args là đối tượng, sửa đổi và chức năng ngoại trừ các đối tượng là một vector của chuỗi (chứ không phải là một mảng) và sửa đổi là một biểu thức chính quy (chứ không phải là lợi nhuận):

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

Điều này cho biết để khớp với một hoặc nhiều chữ số (\ d +) trong mỗi thành phần của x chuyển qua mỗi đối sánh thông qua as.numeric. Nó trả về một danh sách có các thành phần là các vectơ phù hợp với các thành phần tương ứng của x. Nhìn vào kết quả đầu ra, chúng ta thấy rằng thành phần đầu tiên của x có một kết hợp là 13 và thành phần thứ hai của x có hai kết quả là 12 và 34. Xem http://gsubfn.googlecode.com để biết thêm thông tin.

2

Sử dụng chụp dấu ngoặc đơn trong biểu thức chính quy và tham chiếu nhóm trong phần thay thế. Bất cứ điều gì trong ngoặc đơn được ghi nhớ. Sau đó, chúng được truy cập bởi \ 2, mục đầu tiên. Dấu gạch chéo ngược đầu tiên thoát khỏi cách giải nghĩa của dấu gạch chéo ngược trong R sao cho nó được chuyển tới trình phân tích cú pháp biểu thức chính quy.

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

Nó có lẽ là một chút vội vàng nói 'bỏ qua các chức năng tiêu chuẩn' - các tập tin trợ giúp cho ?gsub thậm chí đặc biệt tài liệu tham khảo trong 'Xem thêm':

'regmatches' để chiết xuất phù hợp chất nền dựa trên kết quả của 'regexpr', 'gregexpr' và 'regexec'.

Vì vậy, đây sẽ làm việc, và khá đơn giản:

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

Một giải pháp:

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

Một khác biệt quan trọng giữa các phương pháp tiếp cận hành vi với bất kỳ phi diêm. Ví dụ, phương pháp regmatches có thể không trả về một chuỗi chiều dài giống như đầu vào nếu không có một trận đấu ở mọi tư thế

> 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 
0

Bạn có thể viết các chức năng regex của bạn với C++, biên dịch chúng thành một DLL và cuộc gọi chúng từ 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(); 
    } 
} 
    }; 

cuộc gọi trong R như

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) 
Các vấn đề liên quan