2009-05-20 27 views
36

Sau khi đọc một số câu hỏi/câu trả lời trong vài tuần qua, tôi đã thấy việc sử dụng \d trong biểu thức chính quy perl được nhận xét là không chính xác. Như trong các phiên bản sau của perl \d không giống như [0-9], vì \d sẽ đại diện cho bất kỳ ký tự Unicode nào có thuộc tính chữ số và rằng [0-9] đại diện cho các ký tự '0', '1', '2', ..., '9'.Tôi có nên sử dụng d hoặc [0-9] để khớp các chữ số trong regex Perl không?

Tôi đánh giá cao rằng trong một số ngữ cảnh, [0-9] sẽ là điều đúng để sử dụng và trong các trường hợp khác, \d sẽ là. Tôi đã tự hỏi những người cảm thấy là mặc định chính xác để sử dụng?

Cá nhân tôi tìm thấy ký hiệu \d rất gọn gàng và biểu cảm, trong khi so sánh [0-9] thì hơi cồng kềnh. Nhưng tôi có ít kinh nghiệm làm mã đa ngôn ngữ, hay đúng hơn là mã cho các ngôn ngữ không phù hợp với phạm vi ký tự ASCII, và do đó có thể là ngây thơ.

tôi nhận thấy

$find /System/Library/Perl/5.8.8/ -name \*pm | xargs grep '\\d' | wc -l 
    298 
$find /System/Library/Perl/5.8.8/ -name \*pm | xargs grep '\[0-9\]' | wc -l 
    26 

Trả lời

28

Để đảm bảo an toàn tối đa, tôi khuyên bạn nên sử dụng [0-9] bất kỳ lúc nào bạn không có ý định cụ thể để khớp với tất cả các chữ số được định nghĩa unicode.

mỗi perldoc perluniintro, Perl không hỗ trợ sử dụng chữ số khác hơn [0-9] như số, vì vậy tôi chắc chắn sẽ sử dụng [0-9] nếu sau đều đúng:

  1. Bạn muốn sử dụng kết quả như một số (chẳng hạn như thực hiện các phép toán trên nó hoặc lưu trữ nó ở đâu đó mà chỉ chấp nhận các số thích hợp (ví dụ như một cột INT trong một cơ sở dữ liệu)).

  2. Có thể không có chữ số [^0-9] sẽ có mặt trong dữ liệu theo cách mà biểu thức chính quy có thể khớp với chúng. (Lưu ý rằng điều này nên luôn được coi là đúng đối với không tin cậy vào/thù địch.)

Nếu một trong hai trong số này là sai, sẽ hiếm khi có lý do cụ thể không sử dụng \d (và bạn' có thể sẽ cho biết khi nào trường hợp đó xảy ra) và nếu bạn đang cố gắng để khớp với tất cả các chữ số được xác định bằng unicode, bạn chắc chắn sẽ muốn sử dụng \d.

+2

\ d thực sự có thể khớp với hơn 10 ký tự khác nhau, nếu được áp dụng cho chuỗi Unicode. – pts

3

tôi cảm thấy cả hai phải có chỗ đứng của họ. Tuy nhiên, 99.999% thời gian (đặc biệt là trong thế giới hợp tác lớn của tôi đóng cửa của Mỹ) họ có thể hoán đổi cho nhau. Tôi sử dụng perl để thao tác dữ liệu mỗi ngày và không có tập hợp dữ liệu nào mà tôi xử lý có các số không phù hợp với [0-9]. Tuy nhiên, tôi đánh giá cao rằng có một sự khác biệt quan trọng giữa \d[0-9] và bạn nên biết sự khác biệt đó. Tôi sử dụng \d vì nó có vẻ gọn gàng hơn (như bạn đã nói) và sẽ không bao giờ "sai" trong thế giới thao tác dữ liệu nhỏ bé của tôi.

+0

Bạn muốn \ d không/d - nếu bạn muốn. – Telemachus

2

Nếu bạn áp dụng \d cho chuỗi Unicode (chẳng hạn như trong "\X{660}" =~ /\d/), nó sẽ khớp với một chữ số Unicode. Nếu bạn áp dụng \d cho chuỗi nhị phân (chẳng hạn như tương đương UTF-8 ở trên: "\xd9\xa0" =~ /\d/), nó sẽ chỉ khớp với 10 chữ số ASCII. Perl 5.8 không tạo chuỗi Unicode theo mặc định (trừ khi bạn yêu cầu cụ thể, chẳng hạn như trong "\X{...}" hoặc use utf8;, v.v.).

Vì vậy, lời khuyên của tôi là: chỉ chú ý đến sự khác biệt giữa \d[0-9] nếu ứng dụng của bạn sử dụng chuỗi Unicode.

8

Theo perlreref, '\d' là nhận thức về miền địa phương và nhận thức Unicode.

Tuy nhiên, nếu mã bạn đang sử dụng không phải là Unicode, thì bạn không cần phải lo lắng về các chữ số Unicode và nếu mã bạn đang sử dụng giống như Latin-1 (ISO 8859-1 hoặc 8859) -15), thì nhận thức về miền địa phương sẽ không làm tổn thương bạn vì mã vạch không bao gồm bất kỳ ký tự chữ số nào khác.

Vì vậy, đối với nhiều người, phần lớn thời gian, bạn có thể sử dụng '\d' mà không cần quan tâm. Tuy nhiên, nếu dữ liệu Unicode là một phần của công việc của bạn, thì bạn cần phải xem xét những gì bạn đang sau khi cẩn thận hơn.

4

Cũng giống như nuking trang web từ quỹ đạo, [0-9] là cách duy nhất để chắc chắn. Yeah, nó là xấu xí. Vâng, sự lựa chọn để thực hiện \d là UNICODE và nhận thức về miền địa phương là ngu ngốc. Nhưng đây là giường của chúng ta và chúng ta phải nằm trong đó.

Đối với những người cúi đầu trên cát nói rằng nó không ảnh hưởng đến bộ ký tự mà họ đang sử dụng ngày hôm nay, bạn có thể sử dụng ký tự đó hôm nay, nhưng phần còn lại của thế giới đang sử dụng UTF-8 và bạn sẽ sớm sử dụng nó. Hãy nhớ để mã như anh chàng duy trì mã của bạn là một maniac giết người biết nơi bạn sống.

Ồ, và đối với mô-đun Perl sử dụng \d[0-9], ngay cả lõi vẫn có UNICODE problems.

Nếu bạn làm trong thực tế có nghĩa là bất kỳ con số, nhưng muốn để có thể làm toán với kết quả, bạn có thể sử dụng Text::Unidecode:

#!/usr/bin/perl 

use strict; 
use warnings; 

use Text::Unidecode; 

my $number = "\x{1811}\x{1812}\x{1813}\x{1814}\x{1815}"; 
print "$number is ", unidecode($number), "\n"; 

Sau khi một số chi tiết thử nghiệm nó trông giống như chữ :: Unidecode doesn' t xử lý tất cả các chữ số một cách chính xác. Tôi đang viết một số module sẽ hoạt động.

44

Dường như với tôi rất nguy hiểm khi sử dụng \d, Đây là một quyết định thiết kế kém trong ngôn ngữ, như trong hầu hết các trường hợp bạn muốn [0-9]. Mã Huffman sẽ quy định việc sử dụng \d cho các số ASCII.

Hầu hết các áp phích trước đã nhấn mạnh lý do tại sao bạn nên sử dụng [0-9], vì vậy hãy để tôi cung cấp cho bạn nhiều dữ liệu hơn một chút:

  • Nếu tôi đọc các bảng xếp hạng unicode một cách chính xác '۷۰' là một con số (70 trong chỉ dẫn, không dùng từ ngữ của tôi cho nó).

  • Hãy thử điều này:

    $ perl -le '$one = chr 0xFF11; print "$one + 1 = ", $one+1;' 
    1 + 1 = 1 
    
  • Đây là một phần danh sách các số điện thoại hợp lệ (mà có thể hoặc không thể hiển thị đúng trong trình duyệt của bạn, tùy thuộc vào phông chữ bạn sử dụng), đối với mỗi số, chỉ là người đầu tiên của những người bị hiểu là một số khi thực hiện arithmetics với Perl, như trình bày ở trên:

    ZERO: 0٠۰߀०০੦૦୦௦౦೦൦๐໐0 
    ONE: 1١۱߁१১੧૧୧௧౧೧൧๑໑1 
    TWO: 2٢۲߂२২੨૨୨௨౨೨൨๒໒2 
    THREE: 3٣۳߃३৩੩૩୩௩౩೩൩๓໓3 
    FOUR: 4٤۴߄४৪੪૪୪௪౪೪൪๔໔4 
    FIVE: 5٥۵߅५৫੫૫୫௫౫೫൫๕໕5 
    SIX: 6٦۶߆६৬੬૬୬௬౬೬൬๖໖6 
    SEVEN: 7٧۷߇७৭੭૭୭௭౭೭൭๗໗7 
    EIGHT: 8٨۸߈८৮੮૮୮௮౮೮൮๘໘8 
    NINE: 9٩۹߉९৯੯૯୯௯౯೯൯๙໙9�� 
    

bạn vẫn không thuyết phục?

+4

+1 cho danh sách đó! Tôi đã bắt đầu tự hỏi những nhân vật số khác ở đó. – nickf

+1

Nếu Perl đã ôm UNICODE đến nay, thì có vẻ như nó nên đi phần còn lại của con đường và xử lý tất cả các chữ số. Tất nhiên, đó là cách điên rồ, nhưng không phải là điên rồ số phận của tất cả các lập trình viên Perl ;-)? – RBerteig

+0

vẫn còn nhiều ký tự hơn, nhưng tôi chỉ bao gồm những ký tự mà tôi có thể hiển thị trên hệ thống của mình. Tôi đã sử dụng dữ liệu unicode từ http://www.unicode.org/Public/UNIDATA/UnicodeData.txt và trích xuất thông tin ký tự từ đó. – mirod

1

Nếu [0-9] cảm thấy khó khăn có lẽ bạn có thể xác định: $d=qr/[0-9]/; và sử dụng thay vì \d.

0

Như định dạng dữ liệu điều khiển đi lên, nhu cầu về mô hình đặc hiệu đi xuống ...

Ví dụ, nếu bạn đang so khớp một phần dữ liệu đã được máy tạo ra và luôn tuân theo quy tắc định dạng đầu ra tương tự, bạn không cần phải chính xác như vậy. Lấy địa chỉ IPv4. nếu bạn đang cố gắng để trích xuất các địa chỉ IP từ một dòng cấu hình giao diện router, tất cả các bạn thực sự cần là một cái gì đó như:

'ip\haddress\h(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\D' 

NẾU, mặt khác, bạn đang cố gắng để tìm một địa chỉ IP nhúng sâu đâu đó trong , ví dụ, một email X-Header, hoặc nếu bạn đang cố gắng để xác định một địa chỉ IP, tốt .. đó là một câu chuyện toàn bộ 'nother!

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