2015-05-27 12 views
18

Tôi đang chuyển một thư viện từ Ruby sang Go và vừa phát hiện ra rằng các biểu thức chính quy trong Ruby không tương thích với Go (google RE2). Tôi chú ý rằng Ruby & Java (cộng với các ngôn ngữ khác sử dụng biểu thức thông thường PCRE (tương thích perl, hỗ trợ chụp nhóm)), vì vậy tôi cần phải viết lại các biểu thức để biên dịch ok trong Go.Cách nhận chức năng nhóm trong các biểu thức chính quy của Golang?

Ví dụ, tôi có regex sau:

`(?<Year>\d{4})-(?<Month>\d{2})-(?<Day>\d{2})` 

này nên chấp nhận đầu vào như:

2001-01-20 

Các nhóm chụp cho phép năm, tháng và ngày để được chụp vào các biến. Để có được giá trị của mỗi nhóm, nó rất dễ dàng; bạn chỉ cần chỉ mục vào dữ liệu phù hợp được trả lại với tên nhóm và bạn nhận được giá trị trở lại. Vì vậy, ví dụ để có được năm, một cái gì đó giống như mã giả này:

m=expression.Match("2001-01-20") 
year = m["Year"] 

Đây là một mẫu tôi sử dụng rất nhiều trong biểu thức của tôi, vì vậy tôi có rất nhiều viết lại để làm.

Vì vậy, có cách nào để có được loại chức năng này trong Go regexp hay không; làm thế nào tôi nên viết lại những biểu thức này?

Trả lời

29

Tôi nên viết lại các biểu thức này như thế nào?

Thêm một số Ps, theo quy định here:

(?P<Year>\d{4})-(?P<Month>\d{2})-(?P<Day>\d{2}) 

Chữ thập tên nhóm chụp tài liệu tham khảo với re.SubexpNames().

Và sử dụng as follows:

package main 

import (
    "fmt" 
    "regexp" 
) 

func main() { 
    r := regexp.MustCompile(`(?P<Year>\d{4})-(?P<Month>\d{2})-(?P<Day>\d{2})`) 
    fmt.Printf("%#v\n", r.FindStringSubmatch(`2015-05-27`)) 
    fmt.Printf("%#v\n", r.SubexpNames()) 
} 
+0

Ok tuyệt vời mà trông đáng khích lệ , nhưng làm cách nào để tôi có quyền truy cập vào các giá trị, năm, tháng và ngày riêng lẻ? – Zephilim

+0

Quên nhận xét cuối cùng, tôi chỉ tìm thấy câu trả lời đó. Tất cả của nó trong? P, như bạn nói :) – Zephilim

+0

Tôi vẫn còn bối rối bởi điều này; Tôi không chắc họ có thể định địa chỉ theo Năm, Tháng, v.v.Tôi lấy lại một mảng với bốn giá trị và có thể lập chỉ mục vào nó, nhưng đó là nó. –

1

Nếu bạn cần phải thay thế dựa trên một hàm trong khi chụp nhóm bạn có thể sử dụng này:

import "regexp" 

func ReplaceAllGroupFunc(re *regexp.Regexp, str string, repl func([]string) string) string { 
    result := "" 
    lastIndex := 0 

    for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) { 
     groups := []string{} 
     for i := 0; i < len(v); i += 2 { 
      groups = append(groups, str[v[i]:v[i+1]]) 
     } 

     result += str[lastIndex:v[0]] + repl(groups) 
     lastIndex = v[1] 
    } 

    return result + str[lastIndex:] 
} 

Ví dụ:

str := "abc foo:bar def baz:qux ghi" 
re := regexp.MustCompile("([a-z]+):([a-z]+)") 
result := ReplaceAllGroupFunc(re, str, func(groups []string) string { 
    return groups[1] + "." + groups[2] 
}) 
fmt.Printf("'%s'\n", result) 

https://gist.github.com/elliotchance/d419395aa776d632d897

7

Tôi đã tạo một hàm để xử lý các biểu thức url nhưng nó cũng phù hợp với nhu cầu của bạn. Bạn có thể kiểm tra đoạn this nhưng nó chỉ đơn giản là làm việc như thế này:

/** 
* Parses url with the given regular expression and returns the 
* group values defined in the expression. 
* 
*/ 
func getParams(regEx, url string) (paramsMap map[string]string) { 

    var compRegEx = regexp.MustCompile(regEx) 
    match := compRegEx.FindStringSubmatch(url) 

    paramsMap = make(map[string]string) 
    for i, name := range compRegEx.SubexpNames() { 
     if i > 0 && i <= len(match) { 
      paramsMap[name] = match[i] 
     } 
    } 
    return 
} 

Bạn có thể sử dụng chức năng này như:

params := getParams(`(?P<Year>\d{4})-(?P<Month>\d{2})-(?P<Day>\d{2})`, `2015-05-27`) 
fmt.Println(params) 

và đầu ra sẽ là:

map[Year:2015 Month:05 Day:27] 
Các vấn đề liên quan