2015-05-03 22 views
7

Tôi đã cố gắng trả lời một câu hỏi (mà sau này đã bị xóa) mà tôi nghĩ đã hỏi về việc trích xuất các văn bản đại diện của ký pháp khoa học. (Sử dụng việc thực hiện regex của R yêu cầu thoát kép cho các ký tự meta và có thể được sử dụng ở chế độ PCRE hoặc Perl thuần túy, sự khác biệt giữa chúng tôi không thực sự hiểu rõ.) Tôi đã giải quyết hầu hết các nhiệm vụ nhưng dường như vẫn còn không thể ghi lại dấu trừ hàng đầu trong nhóm chụp. Cách duy nhất tôi dường như để làm cho nó thành công là sử dụng hàng đầu mở ngoặc:Làm thế nào để ghi lại dấu trừ trong ký pháp khoa học với regex?

> txt <- c("this is some random text (2.22222222e-200)", "other random (3.33333e4)", "yet a third(-1.33333e-40)", 'and a fourth w/o the "e" (2.22222222-200)') 
> sub("^(.+\\()([-+]{0,1}[0-9][.][0-9]{1,16}[eE]*[-+]*[0-9]{0,3})(.+$)", "\\2" ,txt) 
[1] "2.22222222e-200" "3.33333e4"  "-1.33333e-40" "2.22222222-200" 

> sub("^(.+\\()([-+]?[0-9][.][0-9]{1,16}[eE]*[-+]*[0-9]{0,3})(.+$)", "\\2" ,txt) 
[1] "2.22222222e-200" "3.33333e4"  "-1.33333e-40" "2.22222222-200" 
#but that seems to be "cheating" ... my failures follow: 

> sub("^(.+)([-+]?[0-9][.][0-9]{1,16}[eE]*[-+]*[0-9]{0,3})(.+$)", "\\2" ,txt) 
[1] "2.22222222e-200" "3.33333e4"  "1.33333e-40"  "2.22222222-200" 
> sub("^(.+)(-?[0-9][.][0-9]{1,16}[eE]*[-+]*[0-9]{0,3})(.+$)", "\\2" ,txt) 
[1] "2.22222222e-200" "3.33333e4"  "1.33333e-40"  "2.22222222-200" 
> sub("^(.+)(-*[0-9][.][0-9]{1,16}[eE]*[-+]*[0-9]{0,3})(.+$)", "\\2" ,txt) 
[1] "2.22222222e-200" "3.33333e4"  "1.33333e-40"  "2.22222222-200" 

Tôi đã tìm kiếm SO đến mức kiên nhẫn của tôi với các điều khoản như `ký hiệu khoa học regex trừ

+0

Bạn có thể cập nhật câu hỏi của mình để hiển thị rõ ràng đầu vào bắt đầu và đầu ra mong muốn không? –

+0

Câu hỏi tạo ra vector ký tự đầu vào làm đầu vào bằng cách sử dụng mã R và tôi đã đăng hai câu trả lời đúng dựa trên phương pháp tôi gọi là "gian lận". Tôi không biết làm thế nào nó có thể được tái tạo hơn nữa –

+1

@TimBiegeleisen Trong ba "1.33333e-40" 'khác nhau – akrun

Trả lời

6

Bạn có thể thử

library(stringr) 
unlist(str_extract_all(txt, '-?[0-9.]+e?[-+]?[0-9]*')) 
#[1] "2.22222222e-200" "3.33333e4"  "-1.33333e-40" "2.22222222-200" 

Sử dụng phương pháp dựa trên chụp sau ngoặc đơn hàng đầu

str_extract(txt, '(?<=\\()[^)]*') 
#[1] "2.22222222e-200" "3.33333e4"  "-1.33333e-40" "2.22222222-200" 
+0

Tôi nghĩ rằng 'stringr' bây giờ sử dụng mã trong một số gói khác, nhưng tôi không thấy đề cập đến trong gói TIN TỨC. –

+0

@BondedDust Có vẻ như vậy, tôi nhận được thông báo rằng 'perl bị phản đối. Vui lòng sử dụng regexp thay thế'. – akrun

+0

@BondedDust Theo https://github.com/hadley/stringr Được xây dựng trên đầu trang của stringi sử dụng thư viện ICU để cung cấp nhanh, thực hiện đúng các thao tác chuỗi phổ biến – akrun

2

Lý do là khả năng "tham lam" của nhóm chụp đầu tiên "(. +)" Để gobble lên dấu trừ là tùy chọn trong nhóm capture thứ hai, tôi đã kết thúc nhóm capture đầu tiên với một lớp nhân vật phủ định và giờ đã thành công. Điều này vẫn còn có vẻ clunky và hy vọng có một cái gì đó thanh lịch hơn. Trong tìm kiếm đã thấy mã Python rằng dường như ngụ ý rằng có những định nghĩa regex của "& real_number">

> sub("^(.+[^-+])([-+]?[0-9][.][0-9]{1,16}[eE]*[-+]*[0-9]{0,3})(.+$)", "\\2" ,txt,perl=TRUE) 
[1] "2.22222222e-200" "3.33333e4"  "-1.33333e-40" "2.22222222-200" 

Sau khi xem xét các mã trong str_extract_all trong đó sử dụng substr để trích xuất trận, bây giờ tôi nghĩ rằng tôi nên đã chọn gregexpr-regmatches mô hình cho những nỗ lực của tôi chứ không phải là pick-the-middle of-a-ba-chụp nhóm chiến lược:

> hits <- gregexpr('[-+]?[0-9][.][0-9]{1,16}[eE]*[-+]*[0-9]{0,3}', txt) 
> ?regmatches 
> regmatches(txt, hits) 
[[1]] 
[1] "2.22222222e-200" 

[[2]] 
[1] "3.33333e4" 

[[3]] 
[1] "-1.33333e-40" 

[[4]] 
[1] "2.22222222-200" 
1

Điều này dường như làm việc, và sẽ không phù hợp với một địa chỉ IP:

sub("^.*?([-+]?\\d+(?:\\.\\d*)*(?:[Ee]?[-+]?\\d+)?).*?$", "\\1", txt) 
[1] "2.22222222e-200" "3.33333e4"  "-1.33333e-40" "2.22222222-200" 

Nhưng kỳ lạ, đó không phải là khá regex tôi bắt đầu với. Khi thử một đã không làm việc, tôi nghĩ tôi sẽ quay trở lại và thử nghiệm trong Perl:

my @txt = (
    "this is some random text (2.22222222e-200)", 
    "other random (3.33333e4)", 
    "yet a third(-1.33333e-40)" , 
    'and a fourth w/o the "e" (2.22222222-200)'); 

map { s/^.*?[^-+]([-+]?\d+(?:\.\d*)*(?:[Ee]?[-+]?\d+)?).*?$/$1/ } @txt; 

print join("\n", @txt),"\n"; 

Và đó nhìn tốt:

2.22222222e-200 
3.33333e4 
-1.33333e-40 
2.22222222-200 

Vì vậy, các regex cùng nên làm việc trong R, phải không?

sub("^.*?[^-+]([-+]?\\d+(?:\\.\\d*)*(?:[Ee]?[-+]?\\d+)?).*?$", "\\1", txt) 
[1] "0" "4" "0" "0" 

Dường như không. Tôi thậm chí đã xác nhận rằng chuỗi được trích dẫn kép là chính xác bằng cách thử bằng Javascript với new RegExp(" ... ") và cũng hoạt động tốt ở đó. Không chắc chắn những gì khác nhau về R, nhưng loại bỏ các ký tự phủ định lớp đã làm các trick.

+0

R sử dụng phiên bản thư viện TRE của Ville Laurikari (http://laurikari.net/tre/) cho regex không phải Perl. –

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