I-Giới Thiệu về Perl
Môi Trường Phát Triểnhttp://www.perl.org/get.html => 2 phiên bản khác cho Linux và MacOS
Như mọi ngôn ngữ lập trình khác , bạn sẽ được bắt đầu làm quen với ngôn ngữ lập trình Perl bằng chương trình đầu tiên "Hello World" với chức năng in một dòng chữ lên console với nội dung "Hello Perl" trên trình biên dịch Padre Perl IDE cho windows
Tạo mới một file HelloWord.pl và gõ vào nội dung
Function và Statements
Perl có một thư viện phong phú các chức năng, bạn có thể xem một danh sách các câu lệnh , chức năng được xây dựng sẵn trên trang chủ của Perl (http://perl.org).
Lệnh print là một trong số những lệnh được dùng nhiều nhất trong perl , chức năng của nó là hiển thị thông tin lên màn hình hoặc đưa thông tin vào tệp tin (trong phần tiếp theo ta sẽ nói rõ hơn).
print "Ví, ", "dụ ", "P";
Một chương trình Perl bao gồm các statements, mỗi trong số đó kết thúc bằng một dấu chấm phẩy. Statements này không cần phải được trên dòng riêng biệt, có thể có nhiều câu lệnh trên một dòng hoặc một câu lệnh duy nhất có thể được chia trên nhiều dòng.
print "Đây là "; print "2 statements.\n"; print "Nhưng đây ",
"chỉ là 1 statement.\n";
Việc phân cách nhau bởi dấu ";" khiến cho perl hiểu đó là 2 câu lệnh print riêng biệt , còn ở print sau chỉ dùng dấu "," nên nó là một statement
Number , String và Quotes
Có 2 kiểu dữ liệu cơ bản trong perl đó là : kiểu số và kiểu chuỗi (number và string)
Khai báo kiểu dữ liệu số thì rất dễ , chỉ cần đó là một số và không có một meta character nào
Ví dụ
1.000 - sai
1,000 - sai
Ví dụ
print "Đây cũng là chuỗi";
Ví dụ
print 'Dòng này \n là 1 dòng';
Biến
Biến trong perl chia làm 3 loại : biến vô hướng (scalars) , mảng (arrays) và băm(hashes)
Biến vô hướng là biến duy nhất , nó có thể là 1 số hoặc 1 chuỗi , bắt đầu bởi dấu $
Ví dụ
$string = "An Toàn Thông Tin";
Nếu trong chuỗi có một biến vô hướng khác , Perl sẽ chèn giá trị của biến vô hướng đó vào
Ví dụ
$string = "Tôi năm nay $value tuổi";
Số trong Perl có thể thực hiện các tính toán toán học thông thường (+ - * /)
Ví dụ
$j = $i*2;
$k = $j/6;
Hãy nhớ rằng Perl sẽ chuyển giá trị sang kiểu số khi nó minh bạch , như trong ví dụ sau
$b = $a + "3"; # Giá trị $b sẽ là 5
$c = $a. "3" ; # Giá trị $c sẽ là "23"
Mảng là danh sách các vô hướng. Tên mảng bắt đầu với ký tự @. Bạn xác định các mảng bằng cách liệt kê các nội dung của nó trong dấu ngoặc đơn, cách nhau bằng dấu phẩy
Ví dụ
@name=("An","Ánh");
Ví dụ
Ví dụ
Ví dụ
Chú thích
Chú thích dùng để giải thích mục đích của tác giả khi lập trình , trong các ví dụ trên tôi hay sử dụng chú thích . Nó được bắt đầu bởi dấu # và sau nó là chú thích .
Vòng Lặp
Hầu như mỗi khi bạn viết một chương trình, bạn sẽ cần phải sử dụng một vòng lặp. Vòng lặp cho phép bạn chạy một đoạn cụ thể của mã hơn và hơn nữa. Đây là một phần của một khái niệm chung trong lập trình được gọi là kiểm soát dòng chảy.
Perl có chức năng khác nhau mà có ích cho việc kiểm soát dòng chảy, cơ bản nhất trong số đó là for. Khi bạn sử dụng cho các chức năng, bạn chỉ định một biến sẽ được sử dụng cho các chỉ số vòng lặp, và một danh sách các giá trị để lặp hơn. Bên trong một cặp dấu ngoặc nhọn, bạn đặt bất kỳ mã bạn muốn chạy trong vòng lặp:
print "$i\n";
}
Vòng lặp không chỉ là số , bạn có thể sử dụng chuỗi một cách dễ dàng.
Ví dụ
print "$i có $hashes_ex{$i} ngày.\n";
}
Có một yếu tố quan trọng của Perl mà chúng ta bỏ qua trong các bài viết trước: toán tử so sánh. Giống như tất cả ngôn ngữ lập trình khác, Perl cho phép bạn đặt câu hỏi như " Số A lớn hơn số B?'' Hoặc "str1 và str2 có phải là 2 chuỗi giống nhau không!?''. Và làm những việc khác nhau tùy thuộc vào câu trả lời.
Khi bạn đang làm việc với các con số, Perl có bốn toán tử quan trọng: < , > , == và != . Đây là những miêu tả "bé hơn hẳn", "lớn hơn hẳn'', "bằng'' và "không bằng''. (Bạn cũng có thể sử dụng <= , "bé hơn hoặc bằng,'' và >= , "lớn hơn hoặc bằng").
Bạn có thể sử dụng các toán tử cùng với một trong những từ khóa có điều kiện Perl, chẳng hạn như if và unless . Cả hai từ khóa có một điều kiện rằng Perl sẽ kiểm tra, và một khối mã trong dấu ngoặc nhọn rằng Perl sẽ chạy nếu kiểm tra hoạt động. Hai từ này làm việc giống như tương đương tiếng Anh của mình - một if thực thi thành công nếu điều kiện là đúng sự thật, và unless thực thi nếu điều kiện là sai:
print "Y2K has doomed us all! Everyone to the compound.\n";
}
unless ($bank_account > 0) {
print "I'm broke!\n";
}
print "This works - but doesn't do what you want!\n";
}
Cả hai if và unless có thể được theo sau bởi một tuyên bố else và khối mã, nó sẽ thực hiện nếu điều kiện của bạn thất bại. Bạn cũng có thể sử dụng elsif đến chuỗi lại với nhau một loạt các if :
print "It's five!\n";
} elsif ($a == 6) {
print "It's six!\n";
} else {
print "It's something else.\n";
}
unless ($pie eq 'apple') {
print "Ew, I don't like $pie flavored pie.\n";
} else {
print "Apple! My favorite!\n";
}
Hai từ khóa hơi phức tạp hơn là while và until . Cả hai đều có một điều kiện và một khối mã, giống như if và unless , nhưng chúng hành động như các vòng lặp tương tự như for . Perl kiểm tra điều kiện, chạy các khối mã và chạy nó tiếp tục cho đến khi điều kiện là đúng (nếu sử dụng vòng lặp while) hoặc sai (nếu sử dụng vòng lặp until).
Hãy xem đoạn mã sau và cố gắng đoán những gì nó sẽ làm trước khi đọc tiếp:
while ($a != 3) {
$a++;
print "Counting up to $a...\n";
}
until ($a == 0) {
$a--;
print "Counting down to $a...\n";
}
Counting up to 2...
Counting up to 3...
Counting down to 2...
Counting down to 1...
Counting down to 0...
Ở trên là cách bạn so sánh các con số. Bây giờ, so sánh về chuỗi với chuỗi ? Toán tử so sánh chuỗi phổ biến nhất là "eq" , dùng để kiểm tra sự tương đương nhau giữa 2 chuỗi.
Nhớ sự cố xảy ra khi bạn nhầm lẫn sử dụng = và == ? Vâng, bạn cũng có thể nhầm lẫn lên == và eq . Đây là một trong số ít các trường hợp nó không quan trọng cho dù Perl được xử lý một giá trị như là một chuỗi hoặc một số. Thử mã này:
if ($yes_no == "yes") {
print "You said yes!\n";
}
Những điều có thể làm việc theo cách khác, quá. Số 5 là số có giá trị tương đương với chuỗi " 5 " , do đó so sánh chúng với == . Nhưng khi bạn so sánh 5 và " 5 " với eq , Perl sẽ chuyển đổi số vào chuỗi "5" đầu tiên, và sau đó hỏi xem hai chuỗi có cùng giá trị. Khi đó , eq so sánh thất bại. Ví dụ sau sẽ in Numeric equality mà không in String equality
if ($a == " 5 ") { print "Numeric equality!\n"; }
if ($a eq " 5 ") { print "String equality!\n"; }
Nếu bạn muốn lấy một phần của một chuỗi (Như: "Lấy bốn ký tự đầu tiên" hoặc "Một đoạn gồm 10 ký tự nằm ở giữa"), sử dụng substr() . Phải mất hai hoặc ba thông số: chuỗi bạn muốn xem, vị trí ký tự bắt đầu (ký tự đầu tiên là vị trí 0) và số ký tự để lấy. Nếu bạn bỏ qua tham số là số ký tự, bạn sẽ lấy lại tất cả mọi thứ cho đến cuối của chuỗi.
print substr($a, 0, 7); # "Welcome"
print substr($a, 7); # " to Perl!\n"
print substr($a, -6, 4); # "Perl"
Bạn cũng có thể thao tác các chuỗi bằng cách sử dụng substr() để gán một giá trị mới cho một phần của nó. Một thủ thuật hữu ích là sử dụng chiều dài là 0 để chèn các ký tự thành một chuỗi:
substr($a, 11, 4) = "Perl"; # $a is now "Welcome to Perl!\n";
substr($a, 7, 3) = ""; # ... "Welcome Perl!\n";
substr($a, 0, 0) = "Hello. "; # ... "Hello. Welcome Perl!\n";
@a = split(/ /, $a); # Three items: "Hello.", "Welcome", "Perl!\n"
@a = split(/ /, $a, 2); # Two items: "Hello.", "Welcome Perl!\n";
Thao tác tệp
Xong về chuỗi. Chúng ta hãy xem các tập tin
Đọc hay ghi vào một tập tin, bạn phải mở nó. Khi bạn mở một tập tin, Perl yêu cầu hệ điều hành nếu các tập tin có thể được truy cập - không có tập tin tồn tại nếu bạn đang cố gắng để đọc nó (hoặc nó có thể được tạo ra nếu bạn đang cố gắng để tạo ra một tập tin mới), và làm bạn có quyền thao tác trên tập tin cần thiết để làm những gì bạn muốn? Nếu bạn đang cho phép sử dụng các tập tin, hệ điều hành sẽ chuẩn bị cho bạn, và Perl sẽ cung cấp cho bạn một filehandle.
Bạn yêu cầu Perl tạo ra một filehandle cho bạn bằng cách sử dụng chức năng open() , trong đó có hai đối số: filehandle bạn muốn tạo và các tập tin bạn muốn làm việc. Đầu tiên, chúng ta sẽ tập trung vào đọc các tập tin. Các lệnh sau mở file log.txt sử dụng filehandle LOGFILE :
Mở một tập tin bao gồm một số đằng sau hậu trường công việc mà Perl và hệ điều hành thực hiện cùng nhau, chẳng hạn như kiểm tra xem các tập tin bạn muốn mở thực sự tồn tại (hoặc tạo ra nó nếu bạn đang cố gắng để tạo ra một tập tin mới) và đảm bảo bạn được phép thao tác các tập tin (bạn có quyền truy cập tập tin cần thiết, ví dụ). Perl sẽ làm tất cả những điều này cho bạn, vì vậy nói chung bạn không cần phải lo lắng về nó.
Một khi bạn đã mở một tập tin để đọc, bạn có thể lấy dòng từ nó bằng cách sử dụng các <> xây dựng. Bên trong dấu ngoặc nhọn, đặt tên của filehandle của bạn. Những gì được trả về bởi điều này phụ thuộc vào những gì bạn muốn nhận được: trong một bối cảnh vô hướng (một cách kỹ thuật nói `` nếu bạn gán nó vào một vô hướng''), bạn lấy dòng tiếp theo từ tập tin, nhưng nếu bạn đang tìm kiếm một danh sách, bạn sẽ có được một danh sách của tất cả các dòng còn lại trong tập tin. (Một thủ thuật thông thường là sử dụng for $lines (<FH>) để lấy tất cả các dòng từ một tập tin - sự for có nghĩa là bạn đang yêu cầu một danh sách.)
Bạn có thể, tất nhiên, close một filehandle mà bạn đã mở. Bạn không luôn luôn phải làm điều này, bởi vì Perl đủ thông minh để đóng một filehandle khi chương trình của bạn kết thúc hoặc khi bạn cố gắng để tái sử dụng một filehandle hiện có. Đó là một ý tưởng tốt, tuy nhiên, để sử dụng close. Không chỉ nó sẽ làm cho mã của bạn dễ đọc hơn, mà vì hệ điều hành của bạn đã được xây dựng trong giới hạn về số lượng tập tin có thể được mở cùng một lúc, và mỗi filehandle mở sẽ chiếm bộ nhớ có giá trị.
Đây là một chương trình đơn giản mà sẽ hiển thị nội dung của tập tin log.txt , và giả định rằng dòng đầu tiên của tập tin là tiêu đề của nó:
# We'll discuss the "or die" in a moment.
$title = <LOGFILE>;
print "Report Title: $title";
for $line (<LOGFILE>) {
print $line;
}
close LOGFILE;
Ghi tệp
Bạn cũng sử dụng open() khi bạn đang viết một tập tin. Có hai cách để mở một tập tin văn bản: ghi đè lên và nối thêm. Khi bạn mở một tập tin trong chế độ ghi đè, bạn xóa bất cứ gì có trước đó. Trong chế độ chèn, bạn đính kèm dữ liệu mới của mình vào cuối của tập tin hiện tại mà không xóa bất cứ những gì đã có.
Để cho biết rằng bạn muốn có một filehandle để viết, bạn đặt một dấu > trước tên tệp bạn muốn thao tác. Điều này sẽ mở các tập tin trong chế độ ghi đè. Để mở nó trong chế độ chèn, sử dụng >>
# The original contents are gone, wave goodbye.
open (APPEND, ">>append.txt") or die "$! error trying to append";
# Original contents still there, we're adding to the end of the file
Ngay khi filehandle của chúng ta là open, chúng ta có thể sử dụng lệnh print viết nội dung cho nó. Xác định filehandle bạn muốn viết nội dung cho và một danh sách các giá trị bạn muốn viết:
print APPEND "We're adding to the end here.\n", "And here too.\n";
Live free or die!
Bạn nhận thấy rằng hầu hết trong ví dụ các lệnh open() được theo sau bởi or die "some sort of message" . Điều này là do chúng ta đang sống trong một thế giới không hoàn hảo, nơi mà các chương trình không luôn luôn cư xử một cách chính xác như chúng ta muốn. Nó luôn luôn có thể cho một open() có kết quả thất bại, có lẽ bạn đang cố gắng để viết vào một tập tin mà bạn không được phép để viết, hoặc bạn đang cố gắng để đọc từ một tập tin không tồn tại. Trong Perl, bạn có thể bảo vệ chống lại những vấn đề này bằng cách sử dụng or và and .
Một loạt các mệnh đề phân cách bằng or sẽ tiếp tục cho đến khi làm điều gì khác, hoặc trả về một giá trị true. Đoạn mã này minh họa cho việc mở handle OUTPUT thành công hay không , nếu không thì thông báo và thoát.
Các tuyên bố die kết thúc chương trình của bạn với một thông báo lỗi. Biến đặc biệt $! có lời giải thích của Perl về lỗi. Trong trường hợp này, bạn có thể thấy một cái gì đó như thế này nếu bạn đang không được phép ghi vào tập tin. Lưu ý rằng bạn có được cả hai thông báo lỗi thực tế ("Permission denied'') và lines code , nơi nó xảy ra
Chương trình phòng thủ như thế này là hữu ích cho việc chương trình của bạn thêm lỗi - bạn không muốn viết vào một tập tin mà bạn đã không mở thành công!
Đây là một ví dụ: bạn viết một chương trình ghi lại kết quả của nó trong một tập tin gọi là vitalreport.txt . Bạn sử dụng đoạn mã sau:
Nếu open() gọi không thành công (ví dụ, vitalreport.txt được sở hữu bởi một người dùng đã không cho bạn quyền write), bạn sẽ không bao giờ biết điều đó cho đến khi một người nào đó nhìn vào các tập tin sau đó và tự hỏi tại sao các báo cáo quan trọng không được ghi vào bằng văn bản. (Chỉ cần tưởng tượng niềm vui nếu có một người nào đó , chẳng hạn là sếp của bạn, nhìn thấy điều này vào ngày trước khi đánh giá hiệu suất hàng năm của bạn.) Khi bạn sử dụng or die , bạn tránh được tất cả điều này:
Thay vì tự hỏi liệu chương trình của bạn có viết báo cáo quan trọng của bạn, bạn sẽ ngay lập tức có một thông báo lỗi rằng cả hai sẽ cho bạn biết những gì đã sai và trên những dòng chương trình của bạn xảy ra lỗi.
Bạn có thể sử dụng or cho nhiều hơn thay vì chỉ là thử nghiệm hoạt động tập tin:
or print "But I wanted apple, cherry, or blueberry!\n";
Theo thứ tự này, nếu bạn có một chiếc bánh thích hợp, Perl bỏ qua phần còn lại của chuỗi. Một khi một tuyên bố là đúng, phần còn lại được bỏ qua. Toán tử and thực hiện ngược lại: Nó làm việc và ngừng lại ngay khi gặp một tuyên bố không thỏa mãn.
Đoạn code trên chỉ cho bạn thấy dòng "Logfile is open!" nếu handle open() thành công - Bạn đã hiểu vì sao !?
Subs
Cho đến nay, chương trình Perl của chúng ta đã có được một loạt các lệnh trong series. Đến đây là ổn nếu bạn đang viết chương trình rất nhỏ, nhưng như nhu cầu của bạn muốn phát triển, bạn sẽ thấy nó hạn chế. Đây là lý do tại sao hầu hết các ngôn ngữ lập trình hiện đại cho phép bạn xác định chức năng của riêng bạn, trong Perl, chúng ta gọi đó subs
Một lệnh riêng được định nghĩa với từ khóa sub , và cho biết thêm một chức năng mới với khả năng của chương trình của bạn. Khi bạn muốn sử dụng chức năng mới này, bạn gọi nó bằng tên. Ví dụ, đây là một định nghĩa ngắn của một sub gọi là boo :
print "Boo!\n";
}
boo(); # Eek!
(Phiên bản cũ của Perl yêu cầu có ký tự & trước tên của lệnh khi bạn gọi nó. Bạn không còn phải làm điều này, nhưng nếu bạn nhìn thấy mã &boo trong Perl của người khác, đó là lý do tại sao.)
Subs rất hữu ích bởi vì họ cho phép bạn chia nhỏ chương trình của mình thành từng khối có thể tái sử dụng. Nếu bạn cần phải phân tích một chuỗi trong bốn địa điểm khác nhau trong chương trình của bạn, nó dễ dàng hơn để viết lệnh có thể dùng nhiều lần thay vì viết nhiều lần một lệnh
Bạn cũng có thể xây dựng hàm có kết quả trả về, Bất cứ khi nào bạn gọi một sub, danh sách tham số sẽ được truyền vào thông qua một mảng đặc biệt là @_ . Bạn cũng có thể trả về một giá trị hoặc một danh sách bằng cách sử dụng từ khóa return.
my (@ops) = @_;
return $ops[0] * $ops[1];
}
for $i (1 .. 10) {
print "$i squared is ", multiply($i, $i), "\n";
}
Tại sao chúng tôi sử dụng từ khóa "my". Đó là biến cục bộ chỉ dùng trong hàm mà không ảnh hưởng đến các biến cùng tên khác trong chương trình.
my ($i, $j);
for $i (1 .. 100) {
$j .= "Is this annoying yet?\n";
}
print $j;
}
Nếu bạn không chỉ định rõ ràng cách sử dụng return , sub sẽ trả về kết quả của báo cáo cuối cùng. Giá trị trả lại tiềm ẩn này đôi khi có thể hữu ích, nhưng nó làm giảm khả năng đọc chương trình của bạn.
hơn bạn viết nó!
SimpleMatching
Các biểu thức thông thường đơn giản được kết hợp biểu thức.Người lập trình thực hiện các kiểm tra bằng cách sử dụng các từ khóa như if , while và unless . Hoặc kết hợp sử dụng với and và or . Một biểu thức chính quy phù hợp sẽ trả về giá trị true điều bạn muốn thực thi là đúng. Khi bạn muốn sử dụng một regular expressio để phù hợp với một chuỗi, bạn sử dụng toán tử đặc biệt =~
if ($user_location =~ /thirteen/) {
print "Eek, bad luck!\n";
}
Chú ý cú pháp của biểu thức chính quy: một chuỗi trong một cặp dấu gạch chéo. Mã $user_location =~ /thirteen/ hỏi liệu các chuỗi chữ thirteen xảy ra bất cứ nơi nào bên trong $user_location . Nếu có, trả về true, nếu không, trả về false.
Metacharacters
Một siêu ký tự là một ký tự hoặc chuỗi ký tự có ý nghĩa đặc biệt. Chúng ta đã thảo luận metacharacters trong bối cảnh hai trích dẫn chuỗi, nơi mà các chuỗi \n có nghĩa là các ký tự xuống dòng, không phải là một dấu gạch chéo ngược, và ký tự n và \t có nghĩa là các ký tự tab.
Biểu thức thông thường có một vốn từ vựng phong phú của metacharacters cho phép bạn đặt câu hỏi thú vị như, "Có biểu hiện này xảy ra ở cuối chuỗi" Hoặc "Chuỗi này chứa một loạt các con số!?"
Hai metacharacters đơn giản nhất là ^ và $ . Chúng có ý nghĩa là "đầu chuỗi" và "cuối chuỗi'' tương ứng. Ví dụ, biểu thức chính quy /^Bob/ sẽ phù hợp với "Bob đã ở đây", "Bob'' và "Bobby.'' Nó sẽ không phù hợp với "Đó là Bob và David'', bởi vì Bob không hiển thị ở đầu của chuỗi. Các ký tự $ , mặt khác, có nghĩa là kết thúc của một chuỗi. Regexp /David$/ sẽ phù hợp với "Bob và David'', nhưng không phù hợp với "David và Bob'' .Đây là một ví dụ đơn giản mà sẽ đưa dòng từ một tập tin và chỉ in URL HTML.:
# "If the line starts with http: and ends with html...."
if (($line =~ /^http:/) and
($line =~ /html$/)) {
print $line;
}
}
Một tập hữu ích của metacharacters được gọi là ký tự đại diện. Nếu bạn đã từng sử dụng một shell Unix hoặc Windows DOS, bạn đã quen thuộc với các kí hiệu nhân vật như * và ? . Ví dụ khi bạn gõ ls a*.txt , bạn sẽ thấy tất cả các tên tập tin bắt đầu bằng chữ cái a và kết thúc bằng .txt . Perl là phức tạp hơn một chút, nhưng hoạt động trên nguyên tắc chung giống nhau.
Trong Perl, các ký tự đại diện chung là "." . Một thời điểm bên trong một biểu hiện thường xuyên sẽ phù hợp với bất kỳ ký tự nào, ngoại trừ một dòng mới. Ví dụ, biểu thức chính quy /ab/ sẽ phù hợp với bất cứ điều gì có chứa a , một ký tự đó không phải là một dòng mới, tiếp theo là b - " aab", "A3B'', "ab'', và vv.
Nếu bạn muốn theo nghĩa đen phù hợp với một siêu ký tự, bạn phải thoát khỏi nó với một dấu gạch chéo ngược. Regex /Mr./ phù hợp với bất cứ điều gì có chứa "Mr.'' tiếp theo ký tự khác. Nếu bạn chỉ muốn để phù hợp với một chuỗi thực sự có "Mr.'' bạn phải sử dụng /Mr\./ .
Các . siêu ký tự không phải là rất hữu ích, đó là lý do Perl cung cấp ba lượng hóa ký tự đại diện: + , ? và * . Mỗi lượng hóa có nghĩa là một cái gì đó khác nhau.
Các + lượng hóa là dễ hiểu: Nó có nghĩa là để phù hợp với ký tự ngay trước hoặc siêu ký tự một hoặc nhiều lần. Các biểu hiện thường xuyên /ab+c/ sẽ phù hợp với "abc'', "abbc'', "abbbc'' và tương tự.
Các * lượng hóa phù hợp với ký tự ngay trước hoặc siêu ký tự không hoặc nhiều lần. Điều này là khác nhau từ + lượng hóa! /ab*c/ sẽ phù hợp với "abc", "abbc',' và tương tự, giống như /ab+c/ đã làm, nhưng nó cũng sẽ phù hợp với "ac'', bởi vì có không xuất hiện của b trong chuỗi.
Cuối cùng, ? lượng hóa sẽ phù hợp với ký tự trước đó không hoặc một lần. Regex /ab?c/ sẽ phù hợp với "ac'' (không xuất hiện của b ) và "abc'' (xuất hiện của b ). Nó sẽ không phù hợp với "abbc'', "abbbc'' và tương tự.
Chúng ta có thể viết lại code đọc URL-phù hợp với chúng ta để ví dụ sử dụng các metacharacters. Điều này sẽ làm cho nó ngắn gọn hơn. Thay vì sử dụng hai biểu thức riêng biệt thường xuyên ( /^http:/ và /html$/ ), chúng tôi kết hợp chúng thành một biểu thức chính quy: /^http:.+html$/ . Để hiểu điều này không, đọc từ trái sang phải: regex này sẽ phù hợp với bất kỳ chuỗi bắt đầu với "http:'' theo sau bởi một hoặc nhiều lần xuất hiện của bất kỳ ký tự nào và kết thúc với "html''. Bây giờ, RegExp của chúng ta là:
if ($line =~ /^http:.+html$/) {
print $line;
}
}
Nhớ là biểu thức /^something$/ này rất hữu dụng
Character classes
Chúng tôi đã thảo luận về một siêu ký tự đặc biệt, . , phù hợp với bất kỳ ký tự ngoại trừ một dòng mới. Nhưng bạn sẽ thường muốn để phù hợp với chỉ các loại cụ thể của ký tự. Perl cung cấp một số metacharacters cho việc này. <\ D> sẽ phù hợp với một chữ số duy nhất, \w sẽ phù hợp với bất kỳ "từ'' , và \s phù hợp với một ký tự khoảng trắng (space và tab, như cũng như \n và \r ký tự).
Các metacharacters làm việc giống như bất kỳ ký tự khác: Bạn có thể kết hợp chống lại nó, hoặc bạn có thể sử dụng lượng hóa như + và * . Regex /^\s+/ sẽ phù hợp với bất kỳ chuỗi bắt đầu với khoảng trắng, và /\w+/ sẽ phù hợp với một chuỗi có chứa ít nhất một từ. (Nhưng hãy nhớ rằng định nghĩa của "từ'' của Perl bao gồm chữ số và gạch dưới, vì vậy hay không, bạn nghĩ _ hoặc 25 là những từ, Perl không!)
Một ví dụ tốt cho \d được thử nghiệm để xem liệu chúng có chứa số. Ví dụ, bạn có thể cần phải xác minh rằng một chuỗi có chứa một số điện thoại theo phong cách Mỹ, trong đó có các hình thức 555-1212 . Bạn có thể sử dụng mã như thế này:
print "That's not a phone number!\n";
}
Tất cả những \d metacharacters làm cho regex khó đọc. May mắn thay, Perl cho phép chúng ta cải tiến về điều đó. Bạn có thể sử dụng các số bên trong dấu ngoặc nhọn để chỉ ra một số lượng bạn muốn để phù hợp , như thế này:
print "That's not a phone number!\n";
}
Chuỗi \d{3} có nghĩa là so sánh chính xác ba con số, và \d{4} phù hợp chính xác bốn chữ số. Nếu bạn muốn sử dụng một loạt các con số, bạn có thể tách chúng bằng dấu phẩy; để lại số thứ hai làm cho phạm vi mở. \d{2,5} sẽ phù hợp với 2-5 chữ số, và <\ w {3 ,}> sẽ phù hợp với một từ đó là ít nhất ba ký tự.
Bạn cũng có thể đảo ngược \d , \s và \w . metacharacters để đề cập đến bất cứ điều gì nhưng mà loại ký tự \D phù hợp nondigits; \W phù hợp với bất kỳ ký tự đó không phải là một sympol, chữ số hoặc gạch dưới, và \S phù hợp với bất cứ điều gì đó không phải là khoảng trắng.
Nếu những metacharacters sẽ không làm những gì bạn muốn, bạn có thể định nghĩa của riêng bạn. Bạn định nghĩa một lớp nhân vật bằng cách kèm theo một danh sách các ký tự cho phép trong dấu ngoặc vuông. Ví dụ, một lớp chỉ chứa các nguyên âm chữ thường là [aeiou] . /b[aeiou]g/ sẽ phù hợp với bất kỳ chuỗi có chứa "bag',' "beg'', "big'' ,"bog'' hay "bug''.. Bạn sử dụng dấu gạch ngang để chỉ ra một loạt các nhân vật, giống như [af] . (Nếu Perl không cho chúng ta dùng siêu ký tự \d , chúng ta có thể làm điều tương tự với [0-9] .) Bạn có thể kết hợp các lớp nhân vật với lượng hóa:
print "This string contains at least
two vowels in a row.\n";
}
Bạn cũng có thể đảo ngược các lớp nhân vật bằng cách bắt đầu chúng với ký tự ^. Một lớp nhân vật sẽ phù hợp với bất cứ điều gì ngược với bạn không liệt kê. [^aeiou] phù hợp với tất cả các nhân vật ngoại trừ các nguyên âm chữ thường. (Có, ^ cũng có thể có nghĩa là "đầu chuỗi'', vì vậy hãy cẩn thận.)
Flags
Theo mặc định, các RegEXP là trường hợp nhạy cảm (có nghĩa là, /bob/ không phù hợp với "Bob''). Bạn có thể đặt những flags sau khi một regexp để thay đổi hành vi của nó. Flags thường được sử dụng là i , mà làm cho một trận đấu trường nhạy cảm:
if ($greet =~ /bob/i) {
print "Hi, Bob!\n";
}
Chúng ta sẽ nói rõ hơn về flags sau
Subexpressions
Bạn có thể muốn kiểm tra nhiều hơn một điều tại một thời điểm. Ví dụ, bạn đang viết một chương trình mà bạn sử dụng để quét e-mail gửi đi cho các cụm từ có khả năng gây thiệt hại. Bạn có thể sử dụng ký tự ống | để tách những thứ khác nhau bạn đang tìm kiếm:
# but here we'll just provide some convenient filler.
@email_lines = ("Dear idiot:",
"I hate you, you twit. You're a dope.",
"I bet you mistreat your llama.",
"Signed, Doug");
for $check_line (@email_lines) {
if ($check_line =~ /idiot|dope|twit|llama/) {
print "Be careful! This line might
contain something offensive:\n",
$check_line, "\n";
}
Các biểu hiện phù hợp /idiot|dope|twit|llama/ sẽ là đúng nếu "idiot,'' "dope,'' "twit'' hay " llama' xuất hiện bất cứ nơi nào trong chuỗi.
Một trong những điều thú vị hơn bạn có thể làm với biểu thức thông thường là subexpression phù hợp, hoặc nhóm. Một subexpression là như nhau, regex nhỏ hơn nằm trong regexp của bạn lớn hơn, và được đặt bên trong dấu ngoặc đơn. Chuỗi gây ra subexpression để phù hợp sẽ được lưu trữ trong các biến đặc biệt $1 . Chúng ta có thể sử dụng để làm cho chương trình trên rõ ràng hơn về những vấn đề với e-mail của bạn:
if ($check_line =~ /(idiot|dope|twit|llama)/) {
print "Be careful! This line contains the
offensive word $1:\n",
$check_line, "\n";
}
}
Tất nhiên, bạn có thể đặt các biểu thức phù hợp trong subexpression của bạn. Chương trình của bạn có thể được mở rộng để ngăn cản bạn gửi e-mail có chứa hơn ba dấu chấm than trong một hàng. Chúng tôi sẽ sử dụng đặc biệt {3,} lượng hóa để đảm bảo chúng tôi có được tất cả các dấu chấm than.
if ($check_line =~ /(!{3,})/) {
print "Using punctuation like '$1'
is the sign of a sick mind:\n",
$check_line, "\n";
}
}
Nếu regex của bạn có nhiều hơn một subexpression, kết quả sẽ được lưu trữ trong các biến có tên là $1 , $2 , $3 và như vậy. Dưới đây là một số mã mà sẽ thay đổi tên trong " LastName, FirstName'' định dạng trở lại bình thường:
$name =~ /(\w+), (\w+)/;
# $1 contains last name, $2 contains first name
$name = "$2 $1";
# $name now contains "Larry Wall"
Bạn có thể thậm chí lồng subexpressions bên trong nhau.Dưới đây là một ví dụ về cách để lấy toàn bộ thời gian, giờ, phút và giây riêng từ một chuỗi có chứa một dấu thời gian trong định dạng hh:mm:ss . (Chú ý rằng chúng ta đang sử dụng {1,2} lượng hóa để một dấu thời gian như "09:30:50''.)
$string =~ /((\d{1,2})\d{2})\d{2}))/;
@time = ($1, $2, $3, $4);
Đây là một gợi ý mà bạn có thể thấy hữu ích: Bạn có thể gán cho một danh sách các giá trị vô hướng bất cứ khi nào bạn đang giao từ một danh sách. Nếu bạn thích có thể đọc được tên biến thay vì một mảng, hãy thử sử dụng dòng này thay vì:
Gán cho một danh sách các biến khi bạn đang sử dụng subexpressions thường xuyên đủ để cung cấp cho bạn một phím tắt tiện dụng:
($string =~ /((\d{1,2})\d{2})\d{2}))/);
Watch out!
Biểu thức thông thường có hai loại bẫy mà tạo ra lỗi trong chương trình Perl của bạn: Họ luôn luôn bắt đầu vào đầu của chuỗi, và lượng hóa luôn luôn phù hợp với càng nhiều các chuỗi càng tốt.
Dưới đây là một số mã đơn giản để đếm tất cả các số trong một chuỗi và hiển thị chúng cho người dùng. Chúng ta sẽ sử dụng while để lặp qua chuỗi, phù hợp hơn và hơn cho đến khi chúng ta đã tính tất cả các số.
while ($number =~ /(\d+)/) {
print "I found the number $1.\n";
$number_count++;
}
print "There are $number_count numbers here.\n";
Mã này thực sự là đơn giản như vậy nó không hoạt động! Khi bạn chạy nó, Perl sẽ in I found the number 200 hơn và hơn nữa. Perl luôn luôn bắt đầu kết hợp vào đầu chuỗi, do đó nó sẽ luôn luôn tìm thấy 200, và không bao giờ đến được với các con số sau đây.
Bạn có thể tránh điều này bằng cách sử dụng các flags với regex của bạn. Lá cờ này sẽ cho Perl để nhớ nơi nó có được trong chuỗi khi nó trở lại đó. Khi bạn chèn flags, mã của chúng ta sẽ như thế này:
while ($number =~ /(\d+)/g) {
print "I found the number $1.\n";
$number_count++;
}
print "There are $number_count numbers here.\n";
Giờ ta sẽ có
I found the number 5.
I found the number 4.
There are 3 numbers here.
Cái bẫy thứ hai là một lượng hóa sẽ luôn luôn phù hợp với nhiều ký tự như nó có thể. Nhìn vào code ví dụ này:
$book_pref =~ /(cat.*at)/;
print $1, "\n";
Hãy đoán xem: Có gì trong $1 bây giờ? Bây giờ chạy mã. Điều này có vẻ không đúng !?
Các biểu hiện phù hợp (cat.*at) là quá rộng. Nó có chứa "cat in the hat is where it's at" , vì đó là chuỗi lớn nhất phù hợp. Nhớ, đọc từ trái sang phải: "cat'' tiếp theo bất kỳ số lượng ký tự, tiếp theo là "at'' Nếu bạn muốn để phù hợp với chuỗi. "cat in the hat" , bạn phải viết lại biểu thức chính quy của bạn để nó không hiểu quá rộng. Có hai cách để làm điều này:
1. Làm cho regexp hơn (thử /(cat.*hat)/ thay thế). Tất nhiên, điều này vẫn có thể không làm việc - hãy thử sử dụng biểu thức chính quy này chống lại "The cat in the hat is who I hate" .
2. Sử dụng một ký tự ? . sau khi một lượng hóa để xác định phù hợp với nongreedy .*? thay vì .* có nghĩa là Perl sẽ cố gắng để phù hợp với chuỗi nhỏ nhất có thể thay vì lớn nhất:
$book_pref =~ /(cat.*?at)/;
Search and replace
Bây giờ chúng ta đã nói chuyện về kết hợp, có một điều khác biểu thức thông thường có thể làm cho bạn: thay thế.
Nếu bạn đã từng sử dụng một trình soạn thảo văn bản hoặc trình xử lý, bạn đã quen với việc tìm kiếm và thay thế chức năng. Cơ sở regexp Perl bao gồm một cái gì đó tương tự, toán tử s/// , trong đó có cú pháp sau: s/regex/replacement string/ . Nếu chuỗi bạn đang thử nghiệm phù hợp với regex, sau đó bất cứ điều gì phù hợp được thay thế bằng các nội dung của chuỗi thay thế. Ví dụ, đoạn mã này sẽ thay đổi một con mèo thành một con chó:
$pet =~ s/cat/dog/;
print $pet;
Bạn cũng có thể sử dụng subexpressions trong biểu hiện phù hợp với bạn, và sử dụng các biến $1 , $2 và như vậy, mà nó tạo ra. Các chuỗi thay thế sẽ thay thế này, hoặc bất kỳ biến khác, như thể nó là một chuỗi dấu ngoặc kép. Ghi mã của chúng ta để thay đổi Wall, Larry vào Larry Wall ? Chúng ta có thể viết lại nó như một biểu thức đơn s///
$name =~ s/(\w+), (\w+)/$2 $1/; # "Larry Wall"
s/// có thể mất flags, giống như biểu thức phù hợp. Hai lá cờ quan trọng nhất là g (toàn cầu) và i (trường hợp không nhạy cảm). Thông thường, thay người sẽ chỉ xảy ra một lần, nhưng xác định g lá cờ sẽ làm cho nó xảy ra miễn là regex phù hợp với chuỗi. Thử mã này, và sau đó loại bỏ các g cờ và thử lại lần nữa:
$pet =~ s/cat/dog/g;
print $pet;
Chú ý rằng nếu không có flags "g", mèo Bill không biến thành một con chó.
Các flags "i" hoạt động giống như nó đã làm khi chúng ta chỉ sử dụng các biểu thức phù hợp: Nó buộc tìm kiếm phù hợp với bạn để được trường hợp không nhạy cảm.
Có bạn nào code Perl ở HN ko? cty mình (SETA ASIA) đang tuyển 3 dev perl.
Trả lờiXóaLương 600$->900$
gửi CV cho mình nhé: nguyendvphp@gmail.com
e chào a.a cho e hỏi là e có một file dữ liệu giờ e muốn lấy ra các thông tin như mong muốn thì e phải dùng lệnh nào ạ. e đã thử dùng grep và foreach mà không được.e cám ơn!
Trả lờiXóa