Match 比对


Go 的regexp包提供的规则表达式的支持,至于可使用的规则表达式,在regexp/syntax有说明。

在 Go 中要编写规则表达式,使用反引号(`)是比较方便的做法,这样就不用转译\

诠译字符在规则表达式中有特殊意义,例如$ ^ * ( ) + = { } [ ] | \ : . ?等,若要比对这些字符,则必须加上转义(Escape)符号,即使 Python 有原始字符串表示,自己处理这些事也还是麻烦,这时可以使用regexpQuoteMeta函数来代劳:

func QuoteMeta(s string) string

例如:

fmt.Println(regexp.QuoteMeta(`main.exe`)) // main\.exe

regexp包中提供其他函数,主要就是比对来源中,是否有符合规则表达式的部份,来源可以是[]byteio.RuneReader或者是string,比对结果会是布尔值,若是规则表达式有误,错误就不会是nil

func Match(pattern string, b []byte) (matched bool, err error)
func MatchReader(pattern string, r io.RuneReader) (matched bool, err error)
func MatchString(pattern string, s string) (matched bool, err error)

例如:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    matched, err := regexp.MatchString(`\d{3}`, "Kaohsiung 803, Road 12")
    fmt.Println(matched, err)
    matched, err = regexp.MatchString(`\d{4}-\d{6}`, "0970-168168")
    fmt.Println(matched, err)
    matched, err = regexp.MatchString(`\d{4}-\d{6}`, "Phone: 0970-168168")
    fmt.Println(matched, err)
}

可以在规则表达式中使用嵌入标志表示法(Embedded Flag Expression)。例如(?i)dog,表示不区分大小写,若想对特定分组嵌入标志,可以使用(?i:dog)这样的语法。

至于 Go 中可用的 POSIX 字符类:

  • [[:alnum:]]:字母与数字(等于 [0-9A-Za-z])
  • [[:alpha:]]:字母(等于 [A-Za-z])
  • [[:ascii:]]:ASCII(等于 [\x00-\x7F])
  • [[:blank:]]:空白或 Tab(等于 [\t ])
  • [[:cntrl:]]:控制字符(等于 [\x00-\x1F\x7F])
  • [[:digit:]]:数字(等于 [0-9])
  • [[:graph:]]:可见字符(等于 [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_{|}~]`)
  • [[:lower:]]:小写字母(等于 [a-z])
  • [[:print:]]:可打印字符(等于 [ -~]、[ [:graph:]])
  • [[:punct:]]:标点符号(等于 [!-/:-@[-{-~]`)
  • [[:space:]]:全部的空白(等于 [\t\n\v\f\r ])
  • [[:upper:]]:大写(等于 [A-Z])
  • [[:word:]]:单字字符(等于 [0-9A-Za-z_])
  • [[:xdigit:]]:十六进制数字(等于 [0-9A-Fa-f])

Unicode 特性的支持上,使用\p\P的方式,表示具有或不具有指定的特性,\pN\PNN是单一字母,若要多个字母组合,可以使用\p{...}\P{...}

例如〈一般分类特性〉,\pL表示字母(Letter),\pN表示数字(Number)等,若要进一步指定子特性,例如\p{Lu}表示大写字母、\p{Ll}表示小写字母:

fmt.Println(regexp.MatchString(`\p{Ll}`, "a")) // true <nil>
fmt.Println(regexp.MatchString(`\p{Lu}`, "a")) // false <nil>

来个有趣的比对吧!𝟏𝟐𝟑𝟜𝟝𝟞𝟩𝟪𝟫𝟬𝟭𝟮𝟯𝟺𝟻𝟼都是十进制数字:

fmt.Println(regexp.MatchString(`\p{Nd}`, "𝟏𝟐𝟑𝟜𝟝𝟞𝟩𝟪𝟫𝟬𝟭𝟮𝟯𝟺𝟻𝟼")) // true <nil>

数字呢?²³¹¼½¾𝟏𝟐𝟑𝟜𝟝𝟞𝟩𝟪𝟫𝟬𝟭𝟮𝟯𝟺𝟻𝟼㉛㉜㉝ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿ都是:

fmt.Println(regexp.MatchString(`\p{N}`, "²³¹¼½¾𝟏𝟐𝟑𝟜𝟝𝟞𝟩𝟪𝟫𝟬𝟭𝟮𝟯𝟺𝟻𝟼㉛㉜㉝ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿ")) // true <nil>

有的语言可能会使用多种文本来书写,例如日语就包含了汉字、平假名、片假名等文本,有的语言只使用一种文本,例如泰文。Unicode 将码群组为文本(script)特性上,测试时只要写上文本特性名称就可以了,例如测试汉字、希腊文:

fmt.Println(regexp.MatchString(`\p{Han}`, "林"))  // true <nil>
fmt.Println(regexp.MatchString(`\p{Greek}`, "α")) // true <nil>




展开阅读全文