Kỹ Thuật Xử Lý Mẫu Với Regex: Java, C#, C++

Nội Dung Thực Hành

Bài viết tập trung vào việc áp dụng biểu thức chính quy (Regex) để giải quyết các vấn đề phổ biến như tìm kiếm chuỗi con, thay đổi nội dung dựa trên vị trí mẫu, xử lý dữ liệu động thông qua hàm callback, và phân chia đoạn văn bản. Sau đây là minh chứng cụ thể cho ba nền tảng phát triển khác nhau về cú pháp và API được cung cấp.

Giải Pháp Cho Java

Trong môi trường Java, lớp PatternMatcher thuộc thư viện java.util.regex đóng vai trò quan trọng. Dưới đây là ví dụ sử dụng phương thức thay thế nhóm và chuyển đổi dữ liệu.

import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexDemonstration {
    public static void main(String[] args) {
        String strInput = "123-4567-89,987-6543-21";
        Pattern pattern = Pattern.compile("\\d{3}-(\\d{4})-\\d{2}");
        Matcher matcher = pattern.matcher(strInput);
        
        // Kiểm tra trùng lặp và hiển thị nhóm
        int count = 0;
        while (matcher.find()) {
            if (count == 0) System.out.println("Kết quả tìm thấy:");
            for (int j = 0; j <= matcher.groupCount(); j++) {
                System.out.printf("Nhóm %d, Vị trí %d : %s%n", count, j, matcher.group(j));
            }
            count++;
        }

        // Thay thế vị trí các số với nhau
        System.out.println(strInput.replaceFirst("(\\d+)-(\\d+)-(\\d+)", "$3-$1-$2"));

        // Hàm callback giả lập đảo ngược số
        StringBuilder buffer = new StringBuilder();
        pattern = Pattern.compile("\\d+");
        matcher = pattern.matcher(strInput);
        while (matcher.find()) {
            String reversed = new StringBuilder(matcher.group(0)).reverse().toString();
            matcher.appendReplacement(buffer, reversed);
        }
        matcher.appendTail(buffer);
        System.out.println(buffer.toString());

        // Chia nhỏ chuỗi
        pattern = Pattern.compile("%(?:begin|next|end)%");
        String splitSource = "%begin%hello%next%world%end%";
        System.out.println(Arrays.asList(pattern.split(splitSource)));
    }
}
// Kết quả đầu ra mẫu:
// [Nhóm 0, Vị trí 0 : 123-4567-89]
// [Nhóm 0, Vị trí 1 : 4567]
// 89-123-4567,987-6543-21
// 321-7654-98,789-3456-12
// [, hello, world]

Triển Khai Trong C#

Ngôn ngữ C# cung cấp module System.Text.RegularExpressions. Việc xử lý được tối ưu hóa qua các câu lệnhLINQ và hàm đánh giá (evaluator).

using System;
using System.Linq;
using System.Text.RegularExpressions;

namespace TechSamples.RegexApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var data = "123-4567-89,987-6543-21";
            var rx = new Regex(@"\d{3}-(\d{4})-\d{2}");
            
            // Đếm và liệt kê kết quả
            var matches = rx.Matches(data).Cast<Match>().ToList();
            if (matches.Any()) Console.WriteLine("Có kết quả:");
            
            foreach (var item in matches.Select((m, i) => new { Index = i, Match = m }))
                foreach (var grp in item.Match.Groups.Cast<Group>().Select((g, j) => new { Idx = j, Value = g.Value }))
                    Console.WriteLine($"Group {item.Index},{grp.Idx} : {grp.Value}");

            // Đổi chỗ tham chiếu chuỗi
            var rxSwap = new Regex(@"(\d+)-(\d+)-(\d+)");
            Console.WriteLine(rxSwap.Replace(data, "$3-$1-$2"));

            // Đảo ngược ký tự số
            var rxDigit = new Regex(@"\d+");
            data = rxDigit.Replace(data, m => 
            {
                var chars = m.Value.ToCharArray();
                Array.Reverse(chars);
                return new string(chars);
            });
            Console.WriteLine(data);

            // Tách chuỗi biên
            var rxSplit = new Regex(@"%(?:begin|next|end)%");
            string splitStr = "%begin%hello%next%world%end%";
            Console.WriteLine(string.Join(",", rxSplit.Split(splitStr)));
        }
    }
}
/* Đầu ra:
Found matches:
group 0,0 : 123-4567-89
group 0,1 : 4567
89-123-4567,21-987-6543
321-7654-98,789-3456-12
,hello,world,*/

Cấu Hình C++ Với Boost Regex

Đối với C++, thư viện Boost mang lại sức mạnh biểu thức chính quy tương thích với các tính năng hiện đại của C++. Chúng ta sử dụng iterator để duyệt qua các kết quả khớp.

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <boost/regex.hpp>
#include <boost/algorithm/string/join.hpp>

using namespace std;
using boost::regex;

int main()
{
    string txt = "123-4567-89,987-6543-21";
    regex r(R"(\d{3}-(\d{4})-\d{2})");
    
    sregex_iterator iterBeg(txt.begin(), txt.end(), r);
    sregex_iterator iterEnd;
    int idx = 0;
    
    cout << "Tìm thấy:" << endl;
    for(auto it = iterBeg; it != iterEnd; ++it, ++idx)
        for(size_t k = 0; k < it->size(); ++k)
            cout << "nhóm " << idx << "," << k << " : " << (*it)[k] << endl;
    
    // Thay thế mẫu
    regex r2(R"((\d+)-(\d+)-(\d+))");
    cout << regex_replace(txt, r2, "$3-$1-$2") << endl;
    
    // Lambda function cho việc thay thế phức tạp
    regex r3(R"(\d+)");
    txt = regex_replace(txt, r3, [](const smatch& match){
        string temp = match.str();
        reverse(temp.begin(), temp.end());
        return temp;
    });
    cout << txt << endl;
    
    // Phân tách chuỗi tùy chỉnh
    regex r4("%(?:begin|next|end)%");
    vector<string> parts;
    for(auto tok = sregex_token_iterator(txt.begin(), txt.end(), r4, -1); tok != sregex_token_iterator(); ++tok)
        parts.push_back(tok->str());
        
    cout << boost::join(parts, ",") << endl;
}
// Output Expected:
// Found:
// group 0,0 : 123-4567-89
// group 0,1 : 4567
// 89-123-4567,21-987-6543
// 321-7654-98,789-3456-12
// ,hello,world

Thẻ: Java csharp cplusplus RegularExpressions BoostRegex

Đăng vào ngày 20 tháng 7 lúc 07:58