Regular Expressions trong Golang (Regex)



  • 🎗 Chia sẽ 1 chút ít về regex - hay gọi là biểu thức chính quy (dịch qua tiếng việt).
    "OK, mở bài":

    Khi bạn nhâp 1 chuỗi bất kỳ vào và bạn muốn chuỗi đó phải đáp ứng một quy tắc nào đó, đơn giản thực tế dễ hiểu là username (không nhập chữ hoa + không có khoảng trắng + không có ký tự đặc biệt, etc...).
    => Lúc này bạn bắt đầu suy nghĩ cách làm tối ưu và regex bay tới và giúp các bạn. 😎
    Trong Golang cũng như các ngôn ngữ khác, cũng có 1 package để giúp bạn xử lý tốt các vấn đề trên, chính là: regexp
    ✍ ✍ ✍ Note: Regex trong Golang sử dụng chuẩn RE2 (more: link)

    Tới đây có bạn thắc mắc là trong golang cũng có 1 thư viện là strings để thao tác với chuỗi (như: split, replace...) thì tại sao lại cần tới #regex. Thực tế khi thao tác với chuỗi đơn giản là split string hay là replace string thì strings package process nhanh hơn cả regex. Tuy nhiên trường hợp như tìm 1 chuỗi không phân biệt chữ hoa, chữ thường thì nếu dùng strings bắt đầu rối não 😱
    OK, chấp nhận là xài regex và đi "sâu" vào em nó 1 xíu 😇 😇 😇 .

    • MATCH (Đây là hàm kiểm tra xem chuỗi có giống với pattern định nghĩa hay không).
      => Hàm này return về true/false : true nếu matched và ngược lại là false
    //Input: slice kiểu byte
    func Match(pattern string, b []byte) (matched bool, error error){ //code }
    
    //Input: RuneReader
    func MatchReader(pattern string, r io.RuneReader) (matched bool, error error){//code}
    
    //Input: string
    func MatchString(pattern string, s string) (matched bool, error error) {//code}
    

    *** Để ý thì cả 3 hàm trên đều trả về kết quả giống nhau và chỉ khác input.
    Ví dụ cho nó đơn giản xíu đi nào:

    //Kiểm tra giá trị nhập vào có phải là số nguyên và số đó có ít nhất 3 chữ số hay không (tức là 2245 hay 1a2 là false) ?
    func IsLowerCase(text string) bool{
    	patternString := "^[0-9]{1,3}$"
    	if matched, _ := regexp.MatchString(patternString, text); !matched{
    		return false
    	}
    
    	return true
    }
    // Đương nhiên là hàm trên nếu regex lỗi thì sẽ dzăng dzách ngay. Mình dùng  _ để bỏ qua if else lỗi.
    

    p/s: Mình demo ví dụ đơn giản vì phức tạp sợ bug 😄 Các bạn có thể định nghĩa các pattern theo link syntax ở trên.

    • FILTER (Dùng để trích xuất, lọc hoặc là collect data...).
      Ví dụ luôn cho nóng, hôm nay đi nghe hội thảo mới biết "CÀO DATA" là gì 😄
    package main
    
    import (
    	"fmt"
    	"io/ioutil"
    	"net/http"
    	"regexp"
    	"strings"
    )
    
    func main(){
    	resp, err := http.Get("https://github.com/marketplace/travis-ci")
    	if err != nil {
    		fmt.Println("HTTP GET ERROR")
    	}
    
    	//Hàm đảm bảo là resp luôn close khi  function chạy xong
    	defer resp.Body.Close()
    	body, err := ioutil.ReadAll(resp.Body)
    	if err != nil {
    		fmt.Println("Cannot Read Body!")
    		return
    	}
    
    	// Remove STYLE.
    	reg, _ := regexp.Compile("\\<title[\\S\\s]+?\\</title\\>")
    	result := reg.ReplaceAllString(string(body), "")
    
    	fmt.Println(strings.TrimSpace(result))
    }
    
    

    => Giải thích xíu về code trên: Request tới 1 link bất kỳ và lấy nội dung html content từ page đó. Sau đó lọc và chỉ lấy title của page đó.

    ✍ ✍ ✍ Để ý là trong ví dụ trên mình dùng hàm compile để kiểm tra tính hợp lệ của string truyền vào.
    Một số functions compile bạn có thể sử dụng:

    func Compile(expr string) (*Regexp, error){}   //1
    func CompilePOSIX(expr string) (*Regexp, error){} //2
    func MustCompile(str string) *Regexp{}  //3
    func MustCompilePOSIX(str string) *Regexp{}  //4
    

    => Mình cũng mới tìm hiểu sơ qua về Go nên kiến thức hơi hạn chế, giải thích sơ qua về sự khác nhau của các hàm trên như sau:
    *** Hàm (1) khác với (2): Hàm (1) trả về giá trị đúng đầu tiên của chuỗi tính từ bên trái qua, đối chiếu với regex. Hàm 2 trả về giá trị dài nhất của chuỗi đối chiếu với regex. (ví dụ: "gotoschool", regex [a-z]{1,2} thì fun (1) => "o", còn fun (2) => "oo" .

    *** Hàm (3), (4) tương tự như trên nhưng nếu có Must thì chương trình sẽ pannic khi regex lỗi, còn trường hợp khác sẽ return về error.

    *Ngoài ra, còn rất nhiều functions trong regex bạn có thể tìm hiểu trên trang chủ Golang.

    func (re *Regexp) Find(b []byte) []byte{}
    func (re *Regexp) FindAll(b []byte, n int) [][]byte{}
    func (re *Regexp) FindAllIndex(b []byte, n int) [][]int{}
    func (re *Regexp) FindAllString(s string, n int) []string{}
    func (re *Regexp) FindAllStringIndex(s string, n int) [][]int{}
    func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string{}
    func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int{}
    func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte{}
    func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int{}
    func (re *Regexp) FindIndex(b []byte) (loc []int){}
    func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int){}
    func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int{}
    func (re *Regexp) FindString(s string) string{}
    func (re *Regexp) FindStringIndex(s string) (loc []int){}
    func (re *Regexp) FindStringSubmatch(s string) []string{}
    func (re *Regexp) FindStringSubmatchIndex(s string) []int{}
    func (re *Regexp) FindSubmatch(b []byte) [][]byte{}
    func (re *Regexp) FindSubmatchIndex(b []byte) []int{}
    

    Các bạn có thể làm nhiều ví dụ khác để hiểu về regexp trong Golang hơn.

    Cảm ơn,
    P/s: Nguồn online và viết theo cách hiểu và kiến thức cơ bản của mình, ghạch đá xin nhận hết ạ. 😄


  • Trùm cuối

    Bài hay và chi tiết quá bác 😍


  • Giám sát viên

    Bài viết hay qué 🙂


Hãy đăng nhập để trả lời
 

Có thể bạn cũng quan tâm

.
DMCA.com Protection Status