2012-08-10 12 views

Trả lời

3

AFAIK, bạn không thể. Bạn chỉ có thể chụp một số nhóm bằng dấu ngoặc đơn và sau đó kiểm tra độ dài của dữ liệu được nhóm đó nắm bắt.

+3

Yay! Năm upvotes cho * Bạn không thể *. Tôi phải cố gắng hơn nữa! – Borodin

+0

Nó thậm chí có thể làm hoàn toàn trong regex. Xem câu trả lời của tôi. – ikegami

+0

Câu trả lời "AFAIK" trong tiêu cực về cơ bản luôn là lựa chọn đăng bài không tốt. Nếu bạn không thể giải thích tại sao nó là không thể, tại sao nói với họ bạn nghĩ rằng nó là? – Mark

5

Bạn sẽ phải nắm bắt chuỗi phù hợp và xử lý riêng biệt.

Mã này chứng tỏ

use strict; 
use warnings; 

my $str = '> plantagenetgoosewagonattributes'; 

if ($str =~ />(.*)[^a]+/) { 
    my $substr = $1; 
    my %counts; 
    $counts{$_}++ for $substr =~ /./g; 
    print "'$_' - $counts{$_}\n" for sort keys %counts; 
} 

đầu ra

' ' - 1 
'a' - 4 
'b' - 1 
'e' - 4 
'g' - 3 
'i' - 1 
'l' - 1 
'n' - 3 
'o' - 3 
'p' - 1 
'r' - 1 
's' - 1 
't' - 5 
'u' - 1 
'w' - 1 
0

Đầu tiên một nhận xét: Do sự tham lam của *, cuối cùng [^a]+ sẽ không bao giờ phù hợp với nhiều hơn một phi một nhân vật - tức là, bạn cũng có thể thả +.

Và như @mvf đã nói, bạn cần phải nắm bắt chuỗi ký tự đại diện phù hợp để có thể đếm các ký tự trong đó. Cụm từ thông dụng Perl không có cách trả về số lần một nhóm cụ thể trùng khớp - công cụ có thể giữ số xung quanh để hỗ trợ cơ chế {,n}, nhưng bạn không thể nhận được nó.

2

Có một thực nghiệm, đừng sử dụng-me, (?{ code }) xây dựng ...

Từ man perlre:

"({code}?)" CẢNH BÁO: biểu thức chính quy mở rộng này tính năng này được coi là thử nghiệm và có thể được thay đổi mà không cần thông báo . Mã được thực hiện có tác dụng phụ có thể không thực hiện giống hệt từ phiên bản này sang phiên bản khác do ảnh hưởng của việc tối ưu hóa trong tương lai trong công cụ regex.

Nếu điều đó không scare bạn tắt, đây là một ví dụ mà đếm số lượng "p" s

my $p_count; 
">pppppbca" =~ /(?{ $p_count = 0 })>(p(?{$p_count++})|.)*[^a]+/; 
print "$p_count\n"; 
+0

Nhường một kết quả không chính xác bởi vì bạn không tính đến việc quay lại. (Nên trả về 4 cho 'ppppp' và' pppppa', nhưng trả lại 5.) – ikegami

+0

Ngoài ra, sử dụng các biến 'my' được khai báo bên ngoài' (? {}) 'Bên trong' (? {}) 'Sẽ dẫn đến kết quả không đúng trong vài trường hợp. Sử dụng 'local our' thay vì' my'. – ikegami

+0

Cả hai điểm tốt. Tôi thừa nhận tôi không bao giờ sử dụng tính năng này cho đến khi tôi thử viết ví dụ này. Tôi đã nhìn thấy lưu ý về việc sử dụng địa phương để xử lý backtracking. Tôi không chắc tại sao tôi lại đăng câu trả lời này; Tôi sẽ không khuyên bạn nên sử dụng điều này, nhưng nghĩ rằng nó là thú vị, đủ để chỉ ra. – chepner

5

Bên ngoài của regex:

my $p_count = map /p/g, />(.*)[^a]/; 

khép kín:

local our $p_count; 
/
    (?{ 0 }) 
    > 
    (?: p (?{ $^R + 1 }) 
    | [^p] 
    )* 
    [^a] 
    (?{ $p_count = $^R; }) 
/x; 

Trong cả hai trường hợp, bạn có thể dễ dàng mở rộng số này để đếm tất cả các chữ cái . Ví dụ,

my %counts; 
if (my ($seq = />(.*)[^a]/) { 
    ++$counts{$_} for split //, $seq; 
} 

my $p_count = $counts{'p'}; 
+0

Cố gắng chạy mã 'khép kín' của bạn bên ngoài Perl :) (sed, awk, bash - xem thẻ tác giả). ;) Không gây rối khả năng chạy một số mã perl bên trong cú pháp 'mở rộng' của Regexp với chính regexp. – mvf

+1

@mvf, Không thể * để viết một vấn đề chạy trong tất cả các trình thông dịch đó, do đó không có ý nghĩa gì cả. (* - Bạn có thể viết một "quine", nhưng điều đó sẽ liên quan đến việc viết chương trình bằng nhiều ngôn ngữ.) – ikegami

3

Đi dọc theo dòng của giải pháp Borodin của, đây là một bash tinh khiết một:

let count=0 
testarray=(a b c d e f g h i j k l m n o p q r s t u v w x y z) 

string="> plantagenetgoosewagonattributes"     # the string 
pattern=">(.*)[^a]+"         # regex pattern 

limitvar=${#testarray[@]}         #array length 

[[ $string =~ $pattern ]] && 
(while [ $count -lt $limitvar ] ; do sub="${BASH_REMATCH[1]//[^${testarray[$count]}]}" ; echo "${testarray[$count]} = ${#sub}" ; ((count++)) ; done) 

Nhìn từ bash 3.0, bash đã giới thiệu các nhóm chụp có thể được truy cập thông qua BASH_REMATCH [n].

Giải pháp tuyên bố các ký tự được tính là mảng [Kiểm tra declare -a cho khai báo mảng trong trường hợp phức tạp] .Một số ký tự đơn sẽ không yêu cầu biến số, không trong khi xây dựng nhưng biến cho ký tự thay vì mảng.

Nếu bạn bao gồm các phạm vi như trong đoạn mã trên, khai báo mảng này thực hiện điều chính xác.

testarray=(`echo {a..z}`) 

Giới thiệu của một vòng lặp if sẽ chiếm hiển thị các ký tự 0 đếm. Tôi muốn giữ cho giải pháp càng đơn giản càng tốt.