Learning Perl - Biểu thức chính qui part 2 ppsx

5 187 0
Learning Perl - Biểu thức chính qui part 2 ppsx

Đang tải... (xem toàn văn)

Thông tin tài liệu

cần áp dụng, vào bên trong các dấu ngoặc, và ta sẽ được nó, như (a|b)*. Nếu bạn muốn làm rõ ràng biểu thức thứ nhất, thì bạn có thể đóng dấu ngoặc (dư thừa) nó với a|(b*). Khi bạn dùng dấu ngoặc để tác động tới số ưu tiên thì chúng cũng đặt lẫy bộ nhớ, như đã chỉ ra trước đây trong chương này. Tức là tập các dấu ngoặc này sẽ cần được đếm khi bạn muốn nói tới một cái gì đó là \2, \3 hay bất kì cái gì. Nếu bạn muốn dùng dấu ngoặc trong trường hợp này nhưng không muốn lưu lại trong bộ nhớ (dạng \1 \2 \3) bạn hãy dùng (?: ) thay cho ( ). Sau đây là một số thí dụ khác về biểu thức chính qui, và tác động của dấu ngoặc: abc* # sánh với ab, abc, abcc, abccc, abcccc vân vân (abc)* # sánh với "", abc, abcabc, abcabcabc vân vân ^x|y # sánh x tại đầu dòng, hay y ở bất kì đâu ^(x|y) # sánh hoặc với x hoặc với y tại đầu dòng a|bc|d # a hoặc bc hoặc d (a|b)(c|d) # ac, ad, bc hoặc bd (song|blue)bird # songbird hay bluebird 7.4 Thêm về toán tử đối sánh Ta đã nhìn vào cách dùng đơn giản nhất của toán tử đối sánh (một biểu thức chính qui được bao trong sổ chéo). Bây giờ ta hãy nhìn vào vô vàn cách làm cho toán tử này làm được điều gì đó hơi khác hơn. 7.4.1 Chọn một mục tiêu khác (toán tử =~) Đôi khi xâu bạn muốn sánh với khuôn mẫu lại không bên trong biến $_, và đó sẽ là sắc thái để đặt nó ở đó (có lẽ bạn đã có một giá trị trong $_ mà bạn rất thích và không muốn thay đổi nó). Không hề gì. Toán tử =~ sẽ giúp chúng ta ở đây. Toán tử này nhận một toán tử biểu thức chính qui ở vế bên phải, rồi thay đổi đối tượng của toán tử này thành một cái gì đó bên cạnh biến $_ - có nghĩa là một giá trị nào đó có tên bên vế trái của toán tử này. Nó trông tựa như thế này: $a = "hello world"; $a =~ /^he/; $a =~ /(.)\l/; if ($a =~ /(.)\1/) { } Mục tiêu của toán tử =~ có thể là bất kì biểu thức nào cho một giá trị xâu vô hướng nào đó. Chẳng hạn, <STDIN> cho một giá trị xâu vô hướng khi được dùng trong hoàn cảnh vô hướng, cho nên chúng ta có thể tổ hợp điều này với toán tử =~ và một toán tử sánh biểu thức chính qui để được một kiểm tra gọn gàng về cái vào đặc biệt, như trong: print "any more?"; if (<STDIN> =~ /^[yY]/) { # có phải bắt đầu bằng một chữ y không? print "So what is it? "; <STDIN>; # bỏ qua 1 dòng print "Sorry, I'm unable to do that.\n"; } Trong trường hợp này, toán tử <STDIN> đọc 1 dòng từ lồi vào chuẩn (bàn phím), mà rồi ngay lập tức được dùng như xâu đem sánh với khuôn mẫu ^[yY]. Lưu ý rằng bạn chưa bao giờ cất giữ cái vào vào một biến, cho nên nếu bạn muốn sánh cái vào với mẫu khác, hay có thể cho hiện lại dữ liệu trong một thông báo lỗi thì bạn khong gặp may rồi. Nhưng dạng này thường hay đến đúng lúc. 7.4.2 Bỏ qua chữ hoa thường Trong thí dụ trước, tôi đã dùng [yY] để đối sánh hoặc chữ Y hoa hoặc y thường. Với những xâu rất ngắn như y hay jerry thì điều này là dễ dàng, như [fF] [oO] [oO]. Nhưng điều gì xẩy ra nếu xâu tôi muốn sánh lại là từ "procedure" trong hoặc chữ thường hoặc chữ hoa? Trong một số phiên bản của grep, cờ -i chỉ ra "bỏ qua hoa thường". Perl cũng có tuỳ chọn như vậy. Bạn chỉ ra tuỳ chọn bỏ qua hoa thường bằng cách thêm vào chữ i thường vào sau sổ chéo đóng, như trong /somepattern/i. Điều này nói lên rằng các chữ của khuôn mẫu này sẽ sánh với các chữ trong xâu trong cả chữ hoa lẫn thường. Chẳng hạn, để sánh từ "procedure" trong cả hoa lẫn thường tại đầu dòng, bạn hãy dùng /^procedure/i. Bây giờ thí dụ trước của ta trong giống thế này: print "anu more?"; if (<STDIN> =~ /^y/i) { # có! xử lí cho nó } 7.4.3 Dùng một định biên khác Nếu bạn đang tìm kiếm một xâu với một biểu thức chính qui có chứa kí tự sổ chéo (/), thì bạn phải đặt trước mỗi sổ chéo một sổ chéo ngược (\). Chẳng hạn, bạn có thể tìm một xâu bắt đầu bằng /usr/etc tựa như thế này: $path = <STDIN>; # đọc một tên đường dẫn if ($path =~ /^\/usr\/etc/) { # bắt đầu với /usr/etc } Như bạn có thể thấy, tổ hợp sổ chéo ngược-sổ chéo làm cho nó trông giống như có một thung lũng nhỏ giữa hai mẩu văn bản. Làm điều này cho nhiều sổ chéo có thể gây cồng kềnh, cho nên Perl cho phép bạn xác định một kí tự định biên khác. Chỉ cần đặt trước bất kì kí tự phi chữ-số nào (định biên do bạn chọn) với một m, rồi liệt kê khuôn mẫu của bạn theo sau bởi một kí tự định biên y hệt thế nữa, là bạn đã hoàn thành, như trong: /^\/usr/etc/ # dùng định biên sổ chéo chuẩn m@^/usr/etc@ # dùng @ làm định biên m#^/usr/etc# # dùng # làm định biên (sở thích của tôi) Bạn có thể thậm chí dùng cả sổ chéo lần nữa nếu bạn cứ muốn, như trong m/jerry/, cho nên toán tử sánh biểu thức chính qui thông thường thực sự là toán tử m, tuy nhiên, m là tuỳ chọn, nếu bạn chọn sổ chéo làm định biên. 7.4.4 Dùng xen lẫn biến Một biểu thức chính qui là được xen lẫn biến trước khi nó được xem xét cho các kí tự đặc biệt khác. Do đó, bạn có thể xây dựng một biểu thức chính qui từ các xâu được tính toán thay vì chỉ là hằng ký hiệu. Chẳng hạn: $what = "bird"; $sentence = "Every good bird does fly."; if ($sentence =~ /\b$what\b/) { print "$sentence\n"; } Tại đây chúng ta đã xây dựng một cách có hiệu quả toán tử biểu thức chính qui /\bbird\b/ bằng việc dùng một tham khảo biến. Sau đây là một thí dụ có hơi phức tạp hơn: $sentence = "Every good bird does fly."; print "What should I find? "; $what = <STDIN>; chop ($what); if ($sentence =~ /$what/) { # tìm thấy nó! print "Yes, saw $what in $sentence.\n"; } else { print "No nothing!.\n"; } Nếu bạn đưa vào bird, thì nó được tìm ra. Nếu bạn đưa vào scream nó sẽ không tìm thấy. Nếu bạn đưa vào [bw]ird, điều ấy cũng được tìm ra, chỉ ra rằng các kí tự đối sánh khuôn mẫu biểu thức chính qui quả thực là vẫn có ý nghĩa. Tôi sẽ chỉ ra cho bạn trong phần "Thay thế" dưới đây về cách thay đổi xâu để cho các ký tự đối sánh khuôn mẫu chính qui được tắt đi. 7.4.5 Biến chỉ đọc đặc biệt Sau khi đối sánh khuôn mẫu thành công, các biến $1, $2, $3 vân vân sẽ được đặt cho cùng giá trị là \1, \2, \3 tương ứng. Bạn có thể dùng điều này để nhìn vào một phần của việc đối sánh trong đoạn chương trình sau. Chẳng hạn: $_ = “đây là phép kiểm tra”; /(\W+)\W+(\W+)/; # đối sánh hai từ đầu # $1 bây giờ là “đây” còn $2 bây giờ là “là” Bạn cũng có thể thu được cùng các giá trị ($1, $2, $3 vân vân) bằng việc đặt đối sánh trong hoàn cảnh mảng. Kết quả là một danh sách các giá trị mà sẽ được đặt cho $1 cho tới số các vật được ghi nhớ, nhưng chỉ nếu biểu thức chính qui sánh đúng. Ta hãy lấy lại thí dụ trước theo cách khác $_ = "This is a test"; /(\W+)\W+(\W+)/; # đối sánh hai từ ở hai đầu # $1 bây giờ là "this" còn $2 bây giờ là "test" Lưu ý rằng các biến $1 và $2 vẫn không bị thay đổi. Các biến chỉ đọc được xác định trước còn bao gồm $&, là một phần của xâu sánh đúng với biểu thức chính qui; $`, là một phần của xâu trước phần sánh đúng; còn $’ là phần của xâu sau phần sánh đúng. Chẳng hạn: $_ = "this is sample string"; /sa.*le/; # sánh "sample" bên trong xâu # $` bây giờ là "this is a " # $& bây giờ là "sample" # $’ bây giờ là " string" Vì tất cả những biến này đều được đặt lại cho từng lần sánh thành công cho nên bạn nên cất giữ các giá trị trong các biến vô hướng khác nếu bạn cần các giá trị đó về sau trong chương trình. 7.5 Thay thế Chúng ta đã nói về dạng đơn giản nhất của toán tử thay thế: s/old-regex/new-string/. Bây giờ là lúc nói tới vài biến thể của toán tử này. Nếu bạn muốn việc thay thế vận hành trên tất cả các đối sánh có thể thay vì chỉ việc đối sánh đầu tiên thì hãy viết thêm g vào toán tử này, như trong: $_ = "foot fool buffon"; s/foo/bar/g; # $_ bây giờ là "bart barl buffon" Xâu thay thế có biến xen vào, cho phép bạn xác định xâu thay thế vào lúc chạy: $_ = "hello, world"; $new = "goodbye"; s/hello/$new/; # thay thế hello bằng goodbye Các kí tự khuôn mẫu trong biểu thức chính qui cho phép các khuôn mẫu được đối sánh, thay vì chỉ là các kí tự cố định: $_ = "this is a test"; s/(\w+)/<$1>/g; # $_ bây giờ là "<this> <is> <a> <test>" Nhớ lại rằng $1 được đặt là dữ liệu bên trong việc đối sánh đúng mẫu trong dấu ngoặc. Hậu tố i (hoặc trước hoặc sau g nếu có) làm cho biểu thức chính qui trong toán tử thay thế bỏ qua Hậu tố i (hoặc trước hoặc sau g nếu có) làm cho biểu thức chính qui trong toán tử thay thế bỏ qua chữ hoa thường, giống như cùng tuỳ chọn trên toán tử đối sánh đã mô tả trước đây. Cũng vậy, giống như toán tử đối sánh, một dấu định biên khác cũng có thể được tuyển lựa nếu sổ chéo là không tiện. Chỉ cần dùng cùng kí tự đó ba lần: s#jerry#tom#; # thay jerry bằng tom, giống s/jerry/tom/ Cũng vậy, giống toán tử đối sánh, bạn có thể xác định một mục tiêu thay phiên bằng toán tử =~. Trong trường hợp này, mục tiêu được chọn phải là một cái gì đó mà bạn có thể gán cho một giá trị vô hướng vào, như một biến vô hướng hay một phần tử của mảng. Sau đây là một thí dụ: $which = "this is a test"; $which =~ s/test/quiz/; # $which bây giờ là "this is a quiz" $someplace[$here] =~ s/left/right/; # đổi một phần tử của mảng $d{"t"} =~ s/^ /x /; 7.6 Các toán tử split() và join() Biểu thức chính qui có thể được dùng để chặt một xâu thành các trường. Toán tử split() thực hiện điều này còn toán tử join() lại có thể dính các mẩu lại với nhau. 7.6.1 Toán tử split() Toán tử split() nhận một biểu thức chính qui và một xâu rồi tìm tất cả mọi sự xuất hiện của biểu thức chính qui bên trong xâu này (dường như bạn đã thực hiện toán tử s///g). Các bộ phận của xâu không sánh với biểu thức chính qui sẽ được trả về lần lượt như một danh sách các giá trị. Chẳng hạn, sau đây là một cách phân tích các thành tố trong file /etc/passwd: $line = "merlyn::118:10:Jenny:/home/merlyn:/usr/bin/perl"; @fields = split(/:/,$line); # chặt $line ra, dùng : làm dấu định biên # bây giờ @field là ("merlyn", "", "118", "10", "Jenny", "/home/merlyn", "/usr/bin/perl") Lưu ý rằng trường thứ hai rỗng trở thành một xâu rỗng. Nếu bạn không muốn điều này, hãy đối sánh tất cả các hai chấm trong một lần phân tách: @fields = split(/:+/, $line); Điều này sẽ sánh cả hai dấu hai chấm đi kèm, cho nên sẽ không có trường thứ hai rỗng nữa. Một xâu thông dụng để chặt biến $_, và biến thành mặc định là: $_ = "any string"; @words = split(/ /); # hệt như @words = split(/ /, $_); Lưu ý rằng đối với việc chặt này, các khoảng cách liên tiếp trong xâu cần chặt sẽ gây ra các trường không (xâu rỗng) trong kết quả. Một khuôn mẫu tốt hơn sẽ là / +/, hay một cách lí tưởng /\s+/, mà sẽ đối sánh một hay nhiều kí tự khoảng trắng. Trong thực tế, khuôn mẫu này là khuôn mẫu mặc định, cho nên nếu bạn định chặt biến $_ theo các khoảng trắng, thì bạn có thể dùng tất cả các mặc định và đơn thuần nói: @words = split; # hệt như @words = split(/\s+/, $_); Các trường theo sau rỗng không trở thành một phần của danh sách. Điều này nói chung không cần quan tâm-một giải pháp giống thế này: $line = "merlyn::118:10:Jenny:/home/merlyn:/usr/bin/perl"; ($name,$password, $uid,$gid,$gcos,$home,$shell) = split(/:/, $line); # chặt $line ra bằng cách dùng : làm dấu định biên Sẽ đơn thuần cho $shell một giá trị rỗng (undef) nếu dòng này không đủ dài, hay nếu nó chứa các giá trị rỗng trong trường cuối (các trường phụ thì im lặng bị bỏ qua, vì việc gán danh sách làm việc theo cách đó). 7.6.2 Toán tử join() Toán tử join() nhận một danh sách các giá trị và gắn chúng lại với nhau dùng xâu gắn giữa từng phần tử danh sách. Nó trông tựa như thế này: $bigstring = join($glue, @list); $bigstring = join($glue, @list); Chẳng hạn, để xây dựng lại dòng mật hiệu, bạn hãy thử một cách kiểu như: $outline = join(":", @fields); Lưu ý rằng xâu gắn không phải là biểu thức chính qui - chỉ là một xâu bình thường gồm không hay nhiều kí tự. 7.7 Bài tập 1. Bạn hãy viết 1 biểu thức chính qui mà nó sánh: ít nhất 1 ký tự a, theo sau là một số lượng bất kỳ các ký tự b một số lượng bất kỳ các dấu sổ chéo ngược (\) theo sau là một số lượng bất kỳ các dấu hoa thị (*) ba lần xuất hiện liên tiếp của $whatever. bất kỳ 5 ký tự nào, kể cả ký tự xuống dòng một từ được lặp lại 2 lần (hoặc nhiều hơn) trên cùng 1 dòng. 2. Bạn hãy viết 1 chương trình đọc vào danh sách các từ ở <STDIN> , và tìm xem thử có dòng nào chứa cả 5 nguyên âm a,e,i,o,u hay không. Nếu có hãy in dòng đó ra màn hình. Bạn hãy chạy thử chương trình với tệp số liệu /usr/dict/words perl myprog.pl < /usr/dict/words (tệp /usr/dict/words có trên các máy linux và unix, nếu máy bạn không có tệp này, bạn có thể tự tạo cho mình 1 tệp số liệu mẫu để chạy thử chương trình) . một biểu thức chính qui và một xâu rồi tìm tất cả mọi sự xuất hiện của biểu thức chính qui bên trong xâu này (dường như bạn đã thực hiện toán tử s///g). Các bộ phận của xâu không sánh với biểu thức. @fields); Lưu ý rằng xâu gắn không phải là biểu thức chính qui - chỉ là một xâu bình thường gồm không hay nhiều kí tự. 7.7 Bài tập 1. Bạn hãy viết 1 biểu thức chính qui mà nó sánh: ít nhất 1 ký tự a,. nên toán tử sánh biểu thức chính qui thông thường thực sự là toán tử m, tuy nhiên, m là tuỳ chọn, nếu bạn chọn sổ chéo làm định biên. 7.4.4 Dùng xen lẫn biến Một biểu thức chính qui là được xen

Ngày đăng: 26/07/2014, 12:20

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan