Daily Archives: 04/05/2016

Ruby – Nhập xuất

Trong phần này chúng ta sẽ tìm hiểu về hệ thống nhập xuất trong Ruby. Khi chạy một chương trình thì chương trình có thể nhận các dòng dữ liệu đi vào, có thể là từ bàn phím, file hoặc từ chính một chương trình khác. Tương tự, chương trình cũng có thể xuất các dòng dữ liệu đi ra ngoài, thường là sẽ đi đến màn hình, đi vào một file hoặc đi vào một chương trình khác.

Xuất dữ liệu ra

Xuyên suốt series này chúng ta đã thực hiện việc xuất dữ liệu rất nhiều lần bằng các phương thức có trong Ruby. Các phương thức này tồn tại trong module Kernel.

Ví dụ 1:

print "Apple "
print "Apple\n"

puts "Orange"
puts "Orange"

Hai phương thức printputs là 2 phương thức xuất dữ liệu là các chuỗi text ra màn hình, trong đó phương thức puts sẽ in chuỗi rồi xuống dòng còn phương thức print thì không.

print "Apple\n"

Nếu muốn phương thức print có xuống dòng thì chúng ta thêm kí tự \n vào.

Apple Apple
Orange
Orange

Ví dụ 2:

p "Lemon"
p "Lemon"

printf "There are %d apples\n", 3

putc 'K'
putc 0xA

Chúng ta tiếp tục tìm hiểu một số phương thức in dữ liệu khác.

p "Lemon"

Phương thức p sẽ gọi phương thức inspect của đối tượng. Phương thức inspect là một phương thức của lớp Object, thường thì phương thức này sẽ in ra tên lớp cùng các thông tin liên quan.

printf "There are %d apples\n", 3

Phương thức printf in chuỗi và cho phép truyền tham số vào trong chuỗi.

putc 'K'
putc 0xA

Phương thức putc chỉ đơn giản là in một kí tự ra màn hình. Giá trị 0xA là giá trị của kí tự xuống dòng trong bảng mã ASCII. Tức thay vì ở đây chúng ta dùng putc "\n" thì chúng ta có thể in 0xA thay thế.

"Lemon"
"Lemon"
There are 3 apples
K

Đọc dữ liệu vào

Ví dụ 1:

print "Enter your name: "
name = gets
puts "Hello #{name}"

Để đọc dữ liệu vào thì chúng ta dùng phương thức gets.

name = gets

Phương thức gets sẽ nhận một chuỗi nhập vào từ bàn phím. Khi chạy chương trình, đến đoạn gọi phương thức gets thì chương trình sẽ dừng lại chờ chúng ta gõ một chuỗi nào đó rồi bấm ENTER thì chuỗi đó sẽ được truyền vào biến name.

Enter your name: Pho Code
Hello Pho Code

Ví dụ 2:

print "Enter a string: "
str = gets

puts "String size: #{str.size}"

Phương thức size sẽ trả về số lượng kí tự có trong chuỗi

Enter a string: abc
String size: 4

Kết quả in ra là 4 trong khi chuỗi của chúng ta nhập vào chỉ là "abc" tức là chỉ có 3 chữ cái thôi, lý do là vì phương thức gets tính luôn cả kí tự ENTER mà chúng ta gõ phía sau nữa nên thành 4.

Để loại bỏ kí tự ENTER này ra khỏi chuỗithì chúng ta dùng phương thức chomp.

print "Enter a string: "
str = gets.chomp

puts "String size: #{str.size}"

Như thế phương thức size sẽ cho ra đúng số lượng kí tự đã được nhập vào.

Enter a string: abc
String size: 3

File

Tất cả các công việc nhập dữ liệu vào và xuất dữ liệu ra đều được quản lý bởi một lớp có tên là IO, ngoài ra Ruby còn có các lớp con khác kế thừa từ lớp IO nhằm mục đích thực hiện việc nhập xuất trên các dòng dữ liệu khác nhau, trong đó có lớp File dùng để nhập xuất file.

Ví dụ 1:

f = File.open('C:\\output.txt', 'w')
f.puts "The Ruby tutorial"
f.close

Trong ví dụ này chúng ta thực hiện ghi dữ liệu lên file.

f = File.open('C:\\output.txt', 'w')

Để ghi dữ liệu vào file thì trước tiên chúng ta phải mở file đó đã bằng phương thức File.open(), phương thức này nhận vào tham số là đường dẫn đến file và chế độ mở, ở đây tên file là output.txt và chế độ mở là (write) tức là mở file để ghi.

f.puts "The Ruby tutorial"

Phương thức open sẽ trả về một đối tượng stream, nói cho đơn giản thì bạn cứ hình dung stream chính là những thứ như Kernel vậy, nếu bạn đã từng làm việc với C++ thì stream ở đây giống như đối tượng std::cout ấy. Và ở đây chúng ta có thể dùng đối tượng stream đó để ghi dữ liệu lên file bằng phương thức puts. 

f.close

Sau khi đã làm việc với file xong thì chúng ta đóng file lại bằng phương thức close.

Ví dụ 2:

File.open('C:\\output.txt', 'w') do |f|
   
    f.puts "Ruby"
    f.write "Java\n"
    f << "Python\n"
    
end

Nếu chúng ta mở file trong khối lệnh File.open()...end thì sau khi kết thúc chúng ta không cần phải đóng file nữa mà Ruby sẽ tự đóng cho chúng ta.

f.puts "Ruby"
f.write "Java\n"
f << "Python\n"

Ngoài ra ở đây chúng ta dùng thêm phương thức write và toán tử << để in chuỗi ra màn hình.

Ví dụ 3:

puts File.exists? 'C:\\tempfile'

f = File.new 'C:\\tempfile', 'w'
puts File.mtime 'C:\\tempfile'
puts f.size

File.rename 'C:\\tempfile', 'C:\\tempfile2'

f.close

Lớp File ngoài việc hỗ trợ nhập xuất còn có một số phương thức khác.

puts File.exists? 'C:\\tempfile'

Phương thức exists? kiểm tra xem một file có tồn tại hay không.

f = File.new 'C:\\tempfile', 'w'

Phương thức new sẽ tạo một file mới trên đĩa cứng.

puts File.mtime 'C:\\tempfile'

Phương thức mtime lấy thời gian chỉnh sửa file lần cuối cùng.

puts f.size

Phương thức size trả về kích thước của file.

File.rename 'C:\\tempfile', 'C:\\tempfile2'

Phương thức rename sẽ đổi tên file.

false
2011-11-05 16:19:36 +0100
0

Ví dụ 4:

f = File.open("C:\\input.txt")

while line = f.gets do
    puts line
end

f.close

Trong ví dụ này chúng ta sẽ đọc một file.

f = File.open("C:\\input")

Để đọc một file thì trước tiên chúng ta cũng phải mở file đó đã, ở đây chúng ta không đưa vào tham số chế độ mở là vì mặc định Ruby sẽ mở file theo chế độ đọc.

while line = f.gets do
    puts line
end

Phương thức gets sẽ đọc từng dòng dữ liệu trong file, chúng ta lưu dữ liệu đó trong biến line, vòng lặp while có tác dụng kiểm tra xem biến line có rỗng hay không, tức là trong khi file vẫn còn dữ liệu để đọc thì chúng ta thực hiện đoạn code bên trong vòng lặp.

Ruby
Java
Python

Ngoài phương thức gets có chức năng đọc từng dòng thì còn có phương thức readlines sẽ đọc tất cả các dòng trong file và lưu vào một mảng. Cũng vì thế nên bạn lưu ý đối với các file có kích thước lớn.

file = 'C:\\input'

File.readlines(file).each do |line|
    puts line
end
Ruby
Java
Python

Thư mục

Ruby có lớp Dir hỗ trợ làm việc với thư mục.

Dir.mkdir "tmp"
puts Dir.exists? "tmp"

puts Dir.pwd
Dir.chdir "tmp"
puts Dir.pwd

Dir.chdir '..'
puts Dir.pwd
Dir.rmdir "tmp"
puts Dir.exists? "tmp"

Trong ví dụ trên chúng ta làm việc với 4 phương thức của lớp Dir.

Dir.mkdir "tmp"

Phương thức mkdir sẽ tạo một thư mục mới.

puts Dir.exists? "tmp"

Phương thức exists? kiểm tra xem một thư mục có tồn tại hay không.

puts Dir.pwd

Phương thức pwd in ra đường dẫn đến thư mục hiện tại. Đây là thư mục chứa file code Ruby mà chúng ta đang viết.

Dir.chdir '..'

Phương thức chdir thay đổi thư mục hiện tại thành thư mục khác. Ở đây dấu ".." tức là lùi về thư mục cha.

Dir.rmdir "tmp"
puts Dir.exists? "tmp"

Phương thức rmdir sẽ xóa một thư mục.

true
C:/Program Files (x86)/Notepad++
C:/Program Files (x86)/Notepad++/tmp
C:/Program Files (x86)/Notepad++
false

Chuyển hướng dòng nhập xuất

Như bình thường chúng ta dùng phương thức puts, print... để in dữ liệu lên màn hình. Trong các bài trước chúng ta đã biết phương thức puts là phương thức của module Kernel, tức là gọi Kernel.puts "Ruby" sẽ tương đương với puts "Ruby". Ngoài ra Ruby còn có một số biến toàn cục tham chiếu tới các module đó nữa, biến $stdout là một ví dụ, đây là biến tham chiếu tới module Kernel, tức là bây giờ chúng ta có 3 cách dùng phương thức puts khác nhau là Kernel.puts “”, $stdout.puts "" hoặc puts "".

Chính vì biến $stdout tham chiếu tới module Kernel nên phương thức puts gọi từ biến này sẽ xuất dữ liệu lên màn hình nhưng chúng ta cũng có thể chuyển hướng để biến này xuất dữ liệu ra nơi khác.

$stdout = File.open "C:\\output.log", "a"

puts "Ruby"
puts "Java"

$stdout.close
$stdout = STDOUT

puts "Python"

Trong ví dụ trên chúng ta chuyển hướng dòng dữ liệu xuất ra từ màn hình sang file output.log.

$stdout = File.open "C:\\output.log", "a"

Như chúng ta đã biết, phương thức File.open sẽ trả về một đối tượng stream, chúng ta gán stream đó vào biến $stdout.

puts "Ruby"
puts "Java"

Khi chúng ta gọi phương thức puts, dữ liệu xuất ra sẽ được tự động ghi vào file thay vì ghi lên màn hình như trước.

$stdout = STDOUT

puts "Python"

Nếu chúng ta chuyển hướng lại vào hằng số STDOUT thì dòng dữ liệu xuất ra từ các phương thức puts, print... sẽ lại đi vào màn hình chứ không đi vào file nữa.

 

Ruby – Biểu thức chính quy Regex

Biểu thức chính quy là một công cụ hỗ trợ thực hiện tìm kiếm chuỗi hoặc các thao tác phức tạp với chuỗi, thường được tích hợp trong các công cụ soạn thảo văn bản, ngôn ngữ lập trình… và tất nhiên là Ruby cũng không ngoại lệ.

Thành phần chủ chốt của biểu thức chính quy là các chuỗi tìm kiếm (tiếng Anh là search pattern hoặc pattern không cũng được) dùng để thực hiện so sánh trên các chuỗi thật. Các chuỗi tìm kiếm này được xây dựng dựa trên các kí tự bình thường và các kí tự đặc biệt.

Đây là danh sách các kí tự đặc biệt:

. Tìm bất kì ký tự nào
* Tìm kí tự đứng trước đó 0 hoặc nhiều lần
[ ] Tìm bất kì kí tự đứng trong cặp dấu []
[^ ] Tìm bất kì kí tự nào không nằm trong cặp dấu []
^ Tìm tại điểm bắt đầu của chuỗi
$ Tìm tại điểm kết thúc của chuỗi
| Toán tử OR

Chúng ta sẽ lần lượt đi vào tìm hiểu các kí tự trên.

Ví dụ:

re = Regexp.new 'Jane'
p "Jane is a girl".match re
p "Jane is a girl" =~ /Jane/
p "Jane is a girl".match %r{Jane}

Để tìm xem chuỗi tìm kiếm có khớp với một chuỗi nào đó không thì chúng ta có 3 cách.

re = Regexp.new 'Jane'

Để tạo các chuỗi tìm kiếm thì chúng ta dùng lớp Regexp, ở dòng trên chúng ta tạo một đối tượng Regexp với chuỗi tìm kiếm là “Jane”.

p "Jane is hot".match re
p "Jane is hot" =~ /Jane/
p "Jane is hot".match %r{Jane}

Để tìm xem chuỗi tìm kiếm có khớp với một chuỗi nào đó hay không thì chúng ta có thể dùng phương thức match của lớp String hoặc toán tử =~. Tham số của phương thức match và toán tử =~ là một đối tượng Regexp hoặc một chuỗi tìm kiếm nằm trong bộ kí tự %r{}, hoặc một chuỗi tìm kiếm nằm trong cặp dấu //. Trong các ví dụ bên dưới chúng ta sẽ làm việc chủ yếu với cặp dấu //.

#<MatchData "Jane">
0
#<MatchData "Jane">

Phương thức match sẽ trả về một đối tượng MatchData nếu tìm thấy hoặc nil nếu không tìm thấy, còn toán tử =~ sẽ trả về chỉ số của chuỗi con được tìm thấy đầu tiên hoặc nil nếu không tìm thấy, ở ví dụ trên toán tử =~ trả về 0 vì chuỗi “Jane” được tìm thấy nằm ở đầu chuỗi gốc.

Tìm bất kì ký tự nào

Như đã mô tả trong bảng các kí tự đặc biệt ở trên, kí tự dấu chấm “.” sẽ tìm bất kì một kí tự nào. Ví dụ:

p "PhoCode".match /.Code/
p "Code".match /.Code/
p "MiCode".match /.Code/
p "Phode".match /.Code/

Trong đoạn code trên, chuỗi tìm kiếm là .Code, tức là khi tìm thì Ruby sẽ tìm bất kì kí tự nào theo sau bởi chuỗi “Code”. Nếu tìm thấy thì in ra chuỗi đó, không thì trả về đối tượng nil.

#<MatchData "oCode">
nil
#<MatchData "iCode">
nil

Ví dụ 2:

p "PhoCode".match /.Code/
p "Code".match /.?Code/
p "MiCode".match /.Code/
p "Phode".match /.Code/

Chúng ta có thể thêm dấu chấm hỏi “?” sau kí tự chấm “.” để báo cho Ruby biết rằng kí tự đó có thể có hoặc không có cũng được.

p "Code".match /.?Code/

Trong ví dụ trước, đoạn code trên không có dấu chấm hỏi, tức là Ruby sẽ hiểu là phải tìm xem có chuỗi “Code” nào có 1 kí tự bất kì ở phía trước không, còn trong ví dụ này có dấu chấm hỏi tức là tìm xem có chuỗi “Code” nào không và có thể có hoặc không có 1 kí tự đứng trước nó.

#<MatchData "oCode">
#<MatchData "Code">
#<MatchData "iCode">
nil

Một số biến đặc biệt

puts "Her name is Jane" =~ /name/

p $`
p $&
p $'

Khi chúng ta tìm kiếm chuỗi thì các chuỗi có liên quan đến quá trình tìm kiếm sẽ được lưu trong một số biến đặc biệt có sẵn.

puts "Her name is Jane" =~ /name/

Ở ví dụ này chúng ta tìm kiếm chuỗi “name” trong chuỗi gốc “Her name is Jane”. Như đã nói ở trên, toán tử =~ sẽ trả về vị trí đầu tiên của chuỗi được tìm thấy, ở đây là vị trí số 4.

p $`

Ngoài ra Ruby còn có biến $`, biến The $` lưu chuỗi nằm phía trước chuỗi được tìm thấy. Tức là trong chuỗi “Her name is Jane” thì chuỗi “Her “ đứng trước chuỗi “name” nên sẽ được lưu trong biến $`.

p $&

Biến $& lưu chính chuỗi được tìm thấy, ở đây là “name”.

p $'

Biến $’ ngược lại với $` là lưu chuỗi nằm phía sau chuỗi được tìm thấy. Ở đây là ” is Jane”.

4
"Her "
"name"
" is Jane"

Anchor

Anchor là các kí tự tìm kiếm tại các vị trí đặc biệt.

Ví dụ 1:

sen1 = "Programming Ruby"
sen2 = "Ruby programming language"

p sen1.match /^Ruby/ 
p sen2.match /^Ruby/ 

p sen1.match /Ruby$/ 
p sen2.match /Ruby$/ 

Kí tự ^ sẽ tìm chuỗi con tại vị trí đầu trong chuỗi gốc, trong khi kí tự $ sẽ tìm chuỗi con bắt đầu từ cuối chuỗi.

sen1 = "Programming Ruby"
sen2 = "Ruby programming language"

Trong ví dụ này chúng ta có 2 chuỗi với chuỗi con “Ruby” nằm ở cuối chuỗi sen1 và đầu chuỗi sen2.

p sen1.match /^Ruby/ 
p sen2.match /^Ruby/

^Ruby tức là tìm xem có chuỗi “Ruby” nào nằm ở đầu chuỗi gốc hay không.

p sen1.match /Ruby$/ 
p sen2.match /Ruby$/  

Ngược lại Ruby$ tức là tìm chuỗi “Ruby” ở cuối chuỗi.

nil
#<MatchData "Ruby">
#<MatchData "Ruby">
nil

Ví dụ 2:

text = "The cat also known as the domestic cat is a small, 
usually furry, domesticated, carnivorous mammal."

p text.scan /cat/

Chúng ta có một chuỗi text và chúng ta tìm chuỗi con “cat” bằng phương thức scan.

p text.scan /cat/

Phương thức scan sẽ tìm tất cả những chuỗi con có nội dung là “cat” trong chuỗi gốc, ở đây phương thức này tìm thấy 3 chuỗi “cat”, chuỗi con “cat” thứ 3 nằm trong từ “domesticated”.

["cat", "cat", "cat"]

Nhưng đôi khi chúng ta lại không muốn tìm những chuỗi con nằm lẫn trong một từ khác như “domesticated” như trên mà chúng ta chỉ muốn tìm những chuỗi con đứng một mình như 2 chuỗi “cat” đầu tiên tìm được. Lúc đó chúng ta phải dùng đến kí tự \b.

Ví dụ 3:

text = "The cat also known as the domestic cat is a small, 
usually furry, domesticated, carnivorous mammal."

p text.scan /\bcat\b/

Bằng cách thêm kí tự \b vào trước và sau chuỗi tìm kiếm cần tìm, Ruby sẽ tìm chuỗi con đứng một mình chứ không tìm chuỗi con lẫn trong các chuỗi khác lớn hơn.

["cat", "cat"]

Gom nhóm các kí tự

Chúng ta có thể gộp các kí tự cần kiểm tra lại với nhau vào bên trong cặp dấu ngoặc vuông []. Ví dụ /[ab]/ sẽ tìm bất kì kí tự a hoặc b nào, còn /ab/ sẽ tìm bất kì kí tự ab nào, tức là /ab/ phải có cả kí tự a lẫn kí tự b, còn /[ab]/ chỉ là tìm xem có kí tự a hoặc b hay không thôi.

Ví dụ 1:

words = %w/ sit MIT fit fat lot pad /

pattern = /[fs]it/

words.each do |word|
   if word.match pattern
       puts "#{word} matches" 
   else
       puts "#{word} does not match" 
   end
end

Chúng ta có mảng words chứa các chuỗi. Chúng ta sẽ duyệt qua từng chuỗi và xem có chuỗi nào khớp với chuỗi tìm kiếm hay không.

pattern = /[fs]it/

chuỗi tìm kiếm có dạng /[fs]it/ tức là khớp với chuỗi fit hoặc sit.

sit matches
MIT does not match
fit matches
fat does not match
lot does not match
pad does not match

Kết quả chúng ta có 2 chuỗi khớp.

Ví dụ 2:

p "car".match %r{[abc][a][rs]}
p "car".match /[a-r]+/
p "23af 433a 4ga".scan /\b[a-f0-9]+\b/

Chúng ta kiểm tra 3 chuỗi tìm kiếm.

p "car".match %r{[abc][a][rs]}

Đoạn chuỗi tìm kiếm ở trên khá dễ hiểu, tìm một chuỗi có 3 kí tự, kí tự đầu tiên là a hoặc b hoặc c, kí tự thứ 2 là a, kí tự thứ 3 là r hoặc s.

p "car".match /[a-r]+/

Chúng ta có thể dùng dấu gạch nối “-“ để biểu diễn một khoảng giá trị. thay vì viết [abcdefghijklmnopqrstuvwxyz] để tìm một kí tự từ a đến z, thì ở đây chúng ta chỉ cần ghi là [a-z] là Ruby sẽ hiểu. Sau đó chúng ta có thể dùng dấu + để báo rằng kí tự đứng trước dấu cộng có thể lặp lại 1 hoặc nhiều lần.

p "23af 433a 4ga".scan /\b[a-f0-9]+\b/

Nếu muốn tìm một kí tự có nhiều khoảng giá trị khác nhau thì chúng ta cứ ghi chúng ra trong cặp dấu ngoặc vuông []. Ở dòng code trên [a-f0-9]+ nghĩa là tìm một kí tự có giá trị trong khoảng a-z hoặc từ 0-9 và kí tự này có thể lặp lại nhiều lần. Ngoài ra ở đây chúng ta còn dùng thêm kí tự \b để báo cho Ruby biết rằng chúng ta không tìm chuỗi con trong chuỗi khác mà chỉ tìm các chuỗi đứng một mình.

#<MatchData "car">
#<MatchData "car">
["23af", "433a"]

Ví dụ 3:

p "ABC".match /[^a-z]{3}/
p "abc".match /[^a-z]{3}/

Chúng ta có thể thêm dấu ^ để chỉ định cho Ruby tìm những kí tự không thuộc khoảng giá trị đó. Tức là ngược với ví dụ 2.

p "ABC".match /[^a-z]{3}/

Trong đoạn code trên [^a-z] tức là tìm một kí tự mà không thuộc khoảng giá trị từ a đến z. Ngoài ra [^a-z]{3} sẽ tìm một chuỗi có đúng 3 kí tự, thay vì dùng dấu + như trước là lặp lại vô số lần.

p "abc".match /[^a-z]{3}/

Chuỗi “ABC” ở trên khớp với mẫu vì ABC là các kí tự in hoa, còn chuỗi “abc” là các kí tự thường nên bị loại bỏ.

#<MatchData "ABC">
nil

Chỉ định số lượng kí tự cần tìm

Trong các ví dụ trên chúng ta đã biết là dấu + sẽ lặp lại 1 hoặc nhiều lần, hay {3} là tìm 3 kí tự. Chúng ta sẽ tìm hiểu thêm các cách chỉ định số lượng kí tự dưới đây.

 ?     - có hoặc không có
 *     - lặp lại 0 hoặc nhiều lần
 +     - lặp lại 1 hoặc nhiều lần
 {n}   - Xuất hiện chính xác n lần
 {n,}  - Xuất hiện n lần hoặc nhiều hơn
 {,n}  - Xuất hiện ít hơn hoặc bằng n lần
 {n,m} - Xuất hiện từ n đến m lần

Chúng ta sẽ tìm hiểu thêm qua các ví dụ ở dưới.

Ví dụ 1:

p "PhoCode open source is the future".scan /\w{3}/
p "PhoCode open source is the future".scan /\b\w{3}\b/

Trong ví dụ này, \w là tìm một kí tự chữ cái, tức là tương đương với [a-zA-Z], thêm {3} vô nghĩa là tìm chuỗi có 3 kí tự chữ cái. Dòng tiếp theo chúng ta có thêm \b tức là chỉ tìm những chuỗi con có đúng 3 chữ cái.

["Pho", "Cod", "ope", "sou", "rce", "the", "fut", "ure"]
["the"]

Ví dụ 2:

p "PhoCode open source is the future".scan /\b\w{2,4}\b/

Ví dụ này cũng tương đương ví dụ trên, ở đây chúng ta dùng {2, 4} tức là tìm các chuỗi chỉ chứa các kí tự chữ cái có từ 2 đến 4 kí tự.

["open", "is", "the"]

Ví dụ 3:


p "color colour colors colours".scan /colou?rs/
p "color colour colors colours".scan /colou?rs?/
p "color colour colors colours".scan /\bcolor\b|\bcolors\b|\bcolour\b|\bcolours\b/

Kí tự dấu chấm hỏi "?" cho biết kí tự đứng trước nó có thể có hoặc không có cũng được.

p "color colour colors colours".scan /\bcolor\b|\bcolors\b|\bcolour\b|\bcolours\b/

Hoặc nếu muốn dễ nhìn hơn chúng ta có thể dùng kí hiệu “|”, kí hiệu này có chức năng giống như toán tử OR vậy, tức là chuỗi tìm kiếm ở trên sẽ tìm những chuỗi con là color, colors, colour, hoặc colours.

["colors", "colours"]
["color", "colour", "colors", "colours"]
["color", "colour", "colors", "colours"]

Phân biệt chữ HOA-thường

p "Jane".match /Jane/
p "Jane".match /jane/
p "Jane".match /JANE/

p "Jane".match /jane/i
p "Jane".match /Jane/i
p "Jane".match /JANE/i

Trong các ví dụ từ đầu bài đến giờ chúng ta tìm kiếm kí tự chữ cái có phân biệt chữ hoa và chữ thường, nếu muốn Ruby không phân biệt chữ hoa và chữ thường thì chúng ta thêm tùy chọn i vào sau chuỗi tìm kiếm.

#<MatchData "Jane">
nil
nil
#<MatchData "Jane">
#<MatchData "Jane">
#<MatchData "Jane">

Email

Trong ví dụ này chúng ta sẽ thực hiện tạo chuỗi kiểm tra email. Đây là một trong những bài toán điển hình của biểu thức chính quy.

emails = %w/ admin@example.com jane@gmail.com ioah2423^as f3444@gmail.com /
    
pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,5}$/

emails.each do |email| 

    if email.match pattern
        puts "#{email} matches"
    else
        puts "#{email} does not match"
    end
    
end

Chúng ta có một mảng emails lưu các chuỗi email mẫu để kiểm tra.

pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9]+\.[a-zA-Z.]{2,5}$/

Trên đây là chuỗi Regex mà chúng ta dùng để kiểm tra. Chúng ta sẽ lần lượt tìm hiểu từng phần của chuỗi này.

[a-zA-Z0-9._-]+@

Đoạn code trên có nghĩa là tìm một chuỗi có nhiều kí tự có giá trị từ A đến Z, hoặc từ a đến z, hoặc từ 0 đến 9, hoặc đó là kí tự dấu chấm “.”, dấu gạch ngang “_” hoặc dấu gạch nối “-“. Tiếp theo sau đó là một kí tự @. Phần này khớp với phần đầu email, ví dụ admin@…

[a-zA-Z0-9]+\.

Sau kí tự @ chúng ta lại tìm một chuỗi con có giá trị từ A đến Z, hoặc từ a đến z hoặc từ 0 đến 9. Đoạn này khớp với phần tên nhà cung cấp email như gmail, yahoo…

Sau đó là kí tự \., theo nghĩa bình thường thì kí tự chấm có nghĩa là ở đó tồn tại bất kì kí tự gì như chúng ta đã nói ở gần đầu bài, nhưng ở đây có dấu “\” phía trước, tức là ở đây chúng ta cần tìm một kí tự dấu chấm “.” thật sự chứ không phải một kí tự nào khác.

[a-zA-Z.]{2, 5}

Cuối cùng là tìm một chuỗi con có giá trị từ a đến z hoặc từ A đến Z hoặc một dấu chấm “.”, và chuỗi này có từ 2 đến 5 kí tự, phần này tương ứng với com, info, net… lý do tại sao lại có dấu chấm sau cùng là vì có một số tên miền có 2 phần như com.vn, co.uk…

admin@example.com matches
jane@gmail.com matches
ioah2423^as does not match
f3444@gmail.com matches