2010-02-25 33 views
7

Tôi đã gặp phải một số hành vi Perl lạ: sử dụng một lớp nhân vật Posix trong một regexp hoàn toàn thay đổi thứ tự sắp xếp cho các chuỗi kết quả.Tại sao sử dụng một lớp nhân vật POSIX trong mẫu regex của tôi cho kết quả không mong muốn?

Đây là chương trình thử nghiệm của tôi:

sub namecmp($a,$b) { 
    $a=~/([:alpha:]*)/; 
    # $a=~/([a-z]*)/; 
    $aword= $1; 

    $b=~/([:alpha:]*)/; 
    # $b=~/([a-z]*)/; 
    $bword= $1; 
    return $aword cmp $bword; 
}; 

$_= <>; 
@names= sort namecmp split; 
print join(" ", @names), "\n"; 

Nếu bạn chuyển sang regexp nhận xét ra bằng cách sử dụng [a-z], bạn sẽ có được bình thường, tự từ điển thứ tự sắp xếp. Tuy nhiên, Posix [: alpha:] lớp nhân vật mang lại một số thứ tự sắp xếp kỳ lạ-ass, như sau:

$test_normal 
aaa aab aac aba abb abc aca acb acc baa bab bac bba bbb bbc bca bcb bcc caa cbb 
aaa aab aac aba abb abc aca acb acc baa bab bac bba bbb bbc bca bcb bcc caa cbb 

$test_posix 
aaa aab aac aba abb abc aca acb acc baa bab bac bba bbb bbc bca bcb bcc caa cbb 
baa bab bac bba bbb bbc bca bcb bcc caa cbb aba abb abc aca acb acc aab aac aaa 

đoán tốt nhất của tôi là tính chất giai cấp Posix được kích hoạt một số loại công cụ locale Tôi chưa bao giờ nghe nói và không yêu cầu. Tôi cho rằng phản ứng hợp lý với "bác sĩ, bác sĩ, nó đau khi tôi làm này!" là, "tốt, đừng làm rằng, sau đó!".

Nhưng, bất kỳ ai cũng có thể cho tôi biết điều gì đang xảy ra ở đây không và tại sao? Tôi đang sử dụng perl 5.10, nhưng tôi tin rằng nó cũng hoạt động theo perl 5.8.

+7

Có một số lập trình viên, những người, khi phải đối mặt với sản lượng họ không mong đợi, có bản năng đầu tiên là yêu cầu * * Tôi đang làm gì sai? ** và tìm ra. Sau đó, có những người có bản năng đầu tiên là hỏi ** Trình biên dịch/phiên dịch làm gì sai? ** Những người trong danh mục thứ hai có thời gian khó viết mã tốt hơn. –

+4

Lý do phổ biến nhất khiến mọi người nhận được hành vi bất ngờ là họ mong đợi điều sai trái. –

Trả lời

13

Lớp nhân vật [:alpha:] đại diện cho các ký tự alpha trong biểu thức chính quy Perl, nhưng dấu ngoặc vuông làm không có nghĩa là những gì chúng thường làm trong cụm từ thông dụng. Vì vậy, bạn cần:

$a=~/([[:alpha:]]*)/; 

này được đề cập trong perlre:

Nhân vật POSIX lớp cú pháp

[:class:] 

cũng có sẵn. Lưu ý rằng các dấu ngoặc [] là chữ; chúng phải luôn được sử dụng trong một biểu thức lớp ký tự.

# this is correct: 
$string =~ /[[:alpha:]]/; 

# this is not, and will generate a warning: 
$string =~ /[:alpha:]/; 
6

Vì Perl không hỗ trợ các lớp ký tự POSIX trong biểu mẫu này. (Sử dụng [[:alpha:]]. Xem @Greg's answer)

Vì vậy

[:alpha:] 

được hiểu như là một lớp nhân vật bao gồm các ký tự "a", "h", "l", "p" và ":".

Hiện tại, đối với các chuỗi không có gì chứa [ahlp:]ở đầu (vì *), ví dụ: "baa" kết quả khớp sẽ trả về một chuỗi rỗng. Một chuỗi rỗng tất nhiên là tất nhiên nhỏ hơn bất kỳ chuỗi nào khác, vì vậy chúng sẽ được sắp xếp ngay từ đầu.

8

Những gì bạn đang viết không phải là Perl bởi bất kỳ khoảng trí tưởng tượng nào. Bạn có thể thoát khỏi nó vì bạn đã tắt warnings.Nếu bạn đã sử dụng cảnh báo, perl sẽ nói với bạn

POSIX syntax [: :] belongs inside character classes in regex; marked by <-- HERE in m/([:alpha:] <-- HERE *)/ at j.pl line 4.

POSIX syntax [: :] belongs inside character classes in regex; marked by <-- HERE in m/([:alpha:] <-- HERE *)/ at j.pl line 8.

Hãy tưởng tượng điều đó!

Bây giờ, perl sẽ phải cũng nói với bạn:

Illegal character in prototype for main::namecmp : $a,$b at j.pl line 3.

vì, Perl không phải là C. Perl không có nguyên mẫu chức năng của các loại bạn dường như cố gắng sử dụng.

Một cách tốt hơn để viết các chức năng chính xác cùng, trong Perl thời gian này, là:

use warnings; use strict; 

sub namecmp { 
    my ($aword) = $a =~ /([[:alpha:]]*)/; 
    my ($bword) = $b =~ /([[:alpha:]]*)/; 
    return $aword cmp $bword; 
} 

print join(' ', sort namecmp split ' ', scalar <>), "\n"; 
+0

Meh, nó chủ yếu là làm việc. Trên thực tế đọc các tài liệu, nó là đáng ngạc nhiên của tôi "nguyên mẫu" làm việc ở tất cả. Mặc dù, tôi phải đưa ra vấn đề với xác nhận ban đầu của bạn: những gì tôi đã viết * là * perl, theo định nghĩa, bởi vì nó đã được chấp nhận và chạy mà không có khiếu nại. – comingstorm

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