2011-01-18 27 views
8

(Lưu ý: Tiêu đề dường như không rõ ràng - nếu ai đó có thể nói lại điều này tôi tất cả vì nó!)Sử dụng luân phiên hoặc lớp nhân vật để đối sánh một ký tự đơn?

Với regex: (.*_e\.txt), khớp với một số tên tệp, tôi cần thêm một số ký tự đơn khác hậu tố ngoài e. Tôi có nên chọn một lớp nhân vật hoặc tôi nên sử dụng một thay thế cho điều này? (Hay nó thực sự quan trọng ??)

Đó là, mà trong hai sau đây có vẻ "tốt hơn", và lý do tại sao:

a) (.*(e|f|x)\.txt), hoặc

b) (.*[efx]\.txt)

+1

Bạn sẽ khó đẩy để đo __any__ hiệu suất sự khác biệt giữa hai. Đừng lo lắng và chỉ sử dụng rõ ràng nhất. – bobbogo

+1

@bobbogo: Lưu ý cách câu hỏi không cụ thể về hiệu suất, nhưng chỉ là về "tốt hơn" + lý do. –

+0

@Mrtin: Tôi đồng ý hoàn toàn. Xóa mã là ưu tiên ở đây. – bobbogo

Trả lời

16

Sử dụng [efx] - đó là chính xác những gì các lớp nhân vật được thiết kế cho: để phù hợp với một trong những nhân vật được bao gồm. Vì vậy nó cũng là giải pháp dễ đọc nhất và ngắn nhất.

Tôi không biết nếu nó nhanh hơn, nhưng tôi sẽ rất ngạc nhiên nếu nó không được. Nó chắc chắn sẽ không chậm hơn.

lập luận của tôi (mà không bao giờ có viết một engine regex, vì vậy đây là phỏng đoán tinh khiết):

Các regex thẻ [abc] sẽ được áp dụng trong một bước duy nhất của động cơ regex: "Là nhân vật tiếp theo một trong a , b hoặc c? "

(a|b|c) tuy nhiên kể động cơ regex để

  • nhớ vị trí hiện tại trong chuỗi cho backtracking, nếu cần thiết
  • kiểm tra nếu nó có thể phù hợp với a. Nếu vậy, thành công. Nếu không:
  • kiểm tra xem nó có thể khớp với b hay không. Nếu vậy, thành công. Nếu không:
  • kiểm tra xem nó có thể khớp với c hay không. Nếu vậy, thành công. Nếu không:
  • bỏ cuộc.
1

Với một ký tự đơn, nó sẽ có sự khác biệt tối thiểu đến mức không quan trọng. (trừ khi bạn đang làm rất nhiều hoạt động)

Tuy nhiên, để dễ đọc (và tăng hiệu suất nhỏ), bạn nên sử dụng phương pháp lớp ký tự.

Để biết thêm thông tin - mở một khung tròn ( làm cho Perl bắt đầu quay lại vị trí hiện tại, vì bạn không còn phù hợp để chống lại, bạn thực sự không cần regex. Một lớp nhân vật sẽ không làm điều này.

+1

Bạn có thể kiểm soát việc sao lưu trong một nhóm bằng cách sử dụng '(?>…)', Nhóm con độc lập. Bằng cách đó, bản thân nhóm sẽ không được xem xét lại khi một số khả năng đã được quyết định. Tuy nhiên, hơi khó sử dụng. – tchrist

+0

@tchrist: đơn giản hơn rất nhiều khi sử dụng đơn giản '(?: ...)' mỗi lần bạn không muốn chụp nhóm con. –

11

Dưới đây là một chuẩn mực:

được cập nhật theo bình luận tchrist, sự khác biệt có ý nghĩa hơn

#!/usr/bin/perl 
use strict; 
use warnings; 
use 5.10.1; 
use Benchmark qw(:all); 

my @l; 
foreach(qw/b c d f g h j k l m n ñ p q r s t v w x z B C D F G H J K L M N ñ P Q R S T V W X Z/) { 
    push @l, "abc$_.txt"; 
} 

my $re1 = qr/^(.*(b|c|d|f|g|h|j|k|l|m|n|ñ|p|q|r|s|t|v|w|x|z)\.txt)$/; 
my $re2 = qr/^(.*[bcdfghjklmnñpqrstvwxz]\.txt)$/; 
my $cpt; 

my $count = -3; 
my $r = cmpthese($count, { 
    'alternation' => sub { 
     for(@l) { 
      $cpt++ if $_ =~ $re1; 
     } 
    }, 
    'class' => sub { 
     for(@l) { 
      $cpt++ if $_ =~ $re2; 
     } 
    } 
}); 

kết quả:

   Rate alternation  class 
alternation 2855/s   --  -50% 
class  5677/s   99%   -- 
+2

Thật thú vị - và, tôi nghĩ, hữu ích - minh họa. Có rất nhiều thứ không đi vào. Nếu bạn thay đổi dữ liệu đầu vào, bạn sẽ nhận được hiệu suất khác nhau, cũng như bạn, nếu bạn thay đổi các mẫu. Ví dụ: '[bcdfghjklmnñpqrstvwxz]' vs '(b | c | d | f | g | h | j | k | l | m | n | ñ | p | q | r | s | t | v | w | x | z) 'cho các phụ âm tiếng Tây Ban Nha dài hơn rất nhiều và có lẽ sẽ hiển thị các đặc tính hiệu suất khác nhau. – tchrist

+0

Tôi nghĩ bạn nên sử dụng 'use utf8;' pragma vì '$ re1' và' $ re2' của bạn không khớp với nhau ;-) –

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