TOC

This article is currently in the process of being translated into Vietnamese (~42% done).

Regular Expressions (Regex):

Searching with the Regex Class

Như đã nói trong bài trước, Regular Expressions cho phép bạn định nghĩa mẫu tìm kiếm khi làm việc với chuỗi. Để xử lý mẫu tìm kiếm này thì framwork .NET cung cấp lớp Regex. Trong bài này, chúng ta sẽ định nghĩa một vài mẫu tìm hiếm và dùng chúng với lớp Regex, nhưng nhớ rằng cú pháp của Regular Expression có thể khá phức tạp mà trong bài giảng này là về C# chứ không phải về Regex. Nếu bạn muốn biết thêm về Regular Expression thì tham khảo ở đây Regular Expression Tutorial.

The IsMatch() Method

Trong ví dụ đầu tiên này, tôi sẽ dùng một trong những phương thức cơ bản nhất của lớp Regex là IsMatch. Nó chỉ đơn giản trả về true hay false, dựa trên liệu có một hai vài dữ liệu trùng lặp trong chuỗi kiểm tra không:

string testString = "John Doe, 42 years";
Regex regex = new Regex("[0-9]+");
if (regex.IsMatch(testString))
    Console.WriteLine("String contains numbers!");
else
    Console.WriteLine("String does NOT contain numbers!");

Chúng ta định nghĩa một chuỗi kiểm tra và sau đó tạo ra một thể hiện của lớp Regex. Chúng ta truyền Regular Expression hiện tại như một chuỗi – trong trường hợp này, regex xác định rằng chúng ta tìm một số có chiều dài bất kỳ. Sau đó chúng ta xuất ra dòng chữ phụ thuộc vào liệu regex có tìm thấy trong chuỗi kiểm tra hay không. Rất tuyệt nhưng trong các tình huống tìm kiếm trùng lặp thì dùng lớp Match.

The Match Class & Method

In this next example, we'll capture the number found in the test string and present it to the user, instead of just verifying that it's there:

string testString = "John Doe, 42 years";
Regex regex = new Regex("[0-9]+");
Match match = regex.Match(testString);
if (match.Success)
    Console.WriteLine("Number found: " + match.Value);

Chúng ta dùng cùng regex và chuỗi kiểm tra như trên. Tôi gọi phương thức Match() trả về một thể hiện của lớp Match – nó sẽ trả về giống hay không. Để đảm bảo rằng việc giống nhau đã được thấy thì tôi kiểm tra thuộc tính Success. Một khi tôi đảm bảo rằng có sự giống nhau thì tôi dùng thuộc tính Value để lấy nó.

Lớp Match chứa nhiều thông tin hữu ích hơn chỉ là tìm chuỗi trùng nhau – ví dụ, bạn có thể dễ dạng tìm ra vị trí, độ dài và hơn nữa:

string testString = "John Doe, 42 years";
Regex regex = new Regex("[0-9]+");
Match match = regex.Match(testString);
if (match.Success)
    Console.WriteLine("Match found at index " + match.Index + ". Length: " + match.Length);

Thuộc tính IndexLength được dùng để hiển thị thông tin về vị trí và độ dài.

Capture Groups

Trong một vài ví dụ đầu tiên, chúng ta chỉ tìm một giá trị đơn trong chuỗi tìm kiếm nhưng Regular Expression có thể làm nhiều hơn thế ! Ví dụ, chúng ta có thể tìm cả tên và tuổi trong chuỗi kiểm tra, trong khi sắp xếp theo những yếu tố khác như đặt hàng và năm. Đó là một phần của Regular Expression nhưng nếu bạn không quen với cú pháp thì nó có thể rất phức tạp, hãy xem ví dụ :

string testString = "John Doe, 42 years";
Regex regex = new Regex(@"^([^,]+),\s([0-9]+)");
Match match = regex.Match(testString);
if (match.Success)
    Console.WriteLine("Name: " + match.Groups[1].Value + ". Age: " + match.Groups[2].Value);

I have modified the regex so that it looks for anything that is NOT a comma - this value is placed in the first capture group, thanks to the surrounding parentheses. Then it looks for the separating comma and after that, a number, which is placed in the second capture group (again, thanks to the surrounding parentheses). In the last line, I use the Groups property to access the matched groups. I use index 1 for the name and 2 for the age since it follows the order in which the match groups were defined in the regex string (index 0 contains the entire match).

Named Capture Groups

As soon as the regex becomes more advanced/longer than the one we just used, numbered capture groups might become unmanageable because you constantly have to remember the order and index of them. Fortunately for us, Regular Expressions and the .NET framework supports named capture groups, which will allow you to give each group a name in the regex and then reference it in the Groups property. Check out this re-written example, where we use named groups instead of numbered:

string testString = "John Doe, 42 years";
Regex regex = new Regex(@"^(?<name>[^,]+),\s(?<age>[0-9]+)");
Match match = regex.Match(testString);
if (match.Success)
    Console.WriteLine("Name: " + match.Groups["name"].Value + ". Age: " + match.Groups["age"].Value);

It works exactly as it does before, but you can now use logical names to lookup the matched values instead of having to remember the correct index. This might not be a big difference in our simple example, but as mentioned you will definitely appreciate it when your Regular Expressions grows in complexity and length.

The MatchCollection Class

The Match class is the way to go if you only want to work with a single match (remember that a match can contain multiple values, as we saw in the previous examples), but sometimes you want to work with several matches at once. For this, we have the Matches() method which will return a MatchCollection class. It will contain all matched values, in the order in which they were found. Let's have a look at how it can be used:

string testString = "123-456-789-0";
Regex regex = new Regex(@"([0-9]+)");
MatchCollection matchCollection = regex.Matches(testString);
foreach (Match match in matchCollection)
    Console.WriteLine("Number found at index " + match.Index + ": " + match.Value);

I have changed the regex and the test string, compared to the previous examples. We now have a test string which contains several numbers and a regex which specifically looks for strings consisting of one or more numbers. We use the Matches() method to get a MatchCollection from our regex, which contains the matches found in the string. In this case, there are four matches, which we output one after another with a foreach loop. The result will look something like this:

Number found at index 0: 123
Number found at index 4: 456
Number found at index 8: 789
Number found at index 12: 0

If no matches were found, an empty MatchCollection would have been returned.

Summary

With help from the Regex class, along with the Match and MatchCollection classes, we can easily do very advanced string matching. The Regular Expression syntax might seem very complex, but once you learn it, you will have a very strong tool. Even if you don't want to invest the time in learning the regex syntax, you can often find expressions for specific needs, created by other programmers, with a simple Google search. As soon as you have written or borrowed the regex string, you can use it for your own purpose with the techniques and classes demonstrated in this article.

But searching is only a part of the fun - you can also do some very cool search/replace operations with Regular Expressions. We will look into this in one of the next articles.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!