基础

Simple Matching

如果字符串跟正则表达式相匹配,则MatchString函数返回true.

r, err := regexp.Compile(`Hello`)
if err != nil {
    fmt.Printf("There is a problem with you regexp.\n")
        return
}
if r.MatchString("Hello Regular Expression.") == true {
    fmt.Println("Match")
} else {
    fmt.Println("No match")
}
//Match

Compile是regexp package的核心。每一个正则表达式都必须通过Compile函数或者MustCompile()函数事先编译。 MustCompile()函数的行为跟Compile类似,但有一点不如,如果正常表达式不能编译,则会发生运行时异常panic. 而不是像Compile那样,返回一个error. 这样我们在使用MustCompile时,可以使用链式调用(但要避免重复的编译正则表达,导致性能问题)

 if regexp.MustCompile(`Hello`)
    .MatchString("Hello Regular Expression.") == true {
        fmt.Printf("Match ") // Will print 'Match' again
    } else {
        fmt.Printf("No match ")
    }

以下是非法的正常表达式

var myre = regexp.MustCompile(`\d(+`)

Output

panic: regexp: Compile(`\d(+`): error parsing regexp: missing argument to repetition operator: `+`

goroutine 1 [running]:
regexp.MustCompile(0x4de620, 0x4, 0x4148e8)
    go/src/pkg/regexp/regexp.go:207 +0x13f

CompilePOSIX/MustCompilePOSIX

CompilePOSIX and MustCompilePOSIX 运行的是不同的正则表达式引擎。遵循的是POSIX ERE(extended regular expression)的规则。这根Go 标准的re2-engine不同,比如POSIX支持不支持\A. 如下所示

s := "ABCDEEEEE"
rr := regexp.MustCompile(`\AABCDE{2}|ABCDE{4}`)
rp := regexp.MustCompilePOSIX(`\AABCDE{2}|ABCDE{4}`)
fmt.Println(rr.FindAllString(s, 2))
fmt.Println(rp.FindAllString(s, 2))

regexp.MustCompilePOSIX()编译失败,因为\A存在于POSIX ERE.

此外POSIX引擎更喜欢leftmost-longest匹配。 它不会在第一次找到匹配后返回。它会找出最长的匹配。

s := "ABCDEEEEE"
rr := regexp.MustCompile(`ABCDE{2}|ABCDE{4}`)
rp := regexp.MustCompilePOSIX(`ABCDE{2}|ABCDE{4}`)
fmt.Println(rr.FindAllString(s, 2)) //[ABCDEE]
fmt.Println(rp.FindAllString(s, 2)) //[ABCDEEEE]

字符类

字符类'\w' 表示[A-Za-z0-9_]中的一个字符

r, err := regexp.Compile(`H\wllo`)
// Will print 'true'. 
fmt.Printf("%v", r.MatchString("Hello Regular Expression."))

字符类'\d'表示任意的数字

r, err := regexp.Compile(`\d`)
// Will print 'true':
fmt.Printf("%v", r.MatchString("Seven times seven is 49."))
// Will print 'false':
fmt.Printf("%v", r.MatchString("Seven times seven is forty-nine."))

字符类'\s'表示TAB, SPACE, CR, LF. [\t\n\f\r]等空白字符。

r, err := regexp.Compile(`\s`)
// Will print 'true':
fmt.Printf("%v", r.MatchString("/home/bill/My Documents"))

字符类也可以取反,比如'\D', '\S', '\W'等。 '\D'表示非数字

r, err := regexp.Compile(`\S`) // Not a whitespace
// Will print 'true', 很明显这里有很多非空格的字母
fmt.Printf("%v", r.MatchString("/home/bill/My Documents"))
r, err := regexp.Compile(`\W`) // Not a \w character.
fmt.Printf("%v", r.MatchString("555-shoe")) // true: has a non-word char: The hyphen
fmt.Printf("%v", r.MatchString("555shoe")) // false: has no non-word char.

查找字符串

FindString()用于查找一个字符串,如果直接使用一个字符串常量作为正则表达式,则返回的结果是自身。

r, err := regexp.Compile(`Hello`)
// Will print 'Hello'
fmt.Printf(r.FindString("Hello Regular Expression. Hullo again."))

当FindString没有找到匹配的字符串时,它会返回一个空的字符串。但需要注意的是,空的字符串可能是一个有效匹配(不一定是没有找到).

r, err := regexp.Compile(`Hxllo`)
// Will print nothing (=the empty string)
fmt.Printf(r.FindString("Hello Regular Expression."))

FindString 在第一次找到后返回,如果你想返回所有的匹配,则需要使用到FindAllString().

特殊字符

'.' 匹配任意的字符

// Will print 'cat'.
r, err := regexp.Compile(`.at`)
fmt.Printf(r.FindString("The cat sat on the mat."))
// more dot.
s:= "Nobody expects the Spanish inquisition."
//          -- --     --
r, err := regexp.Compile(`e.`)
res := r.FindAllString(s, -1) // negative: all matches
// Prints [ex ec e ]. The last item is 'e' and a space.
fmt.Printf("%v", res)
res = r.FindAllString(s, 2) // find 2 or less matches
// Prints [ex ec]. 
fmt.Printf("%v", res)

特殊字符的正常使用

对于反斜线'\'. 这里必须转义两次,一次是regex中,一次是字符串中。

r, err := regexp.Compile("C:\\\\")
if r.MatchString("Working on drive C:\\") == true {
    fmt.Printf("Matches.") // <---
} else {
    fmt.Printf("No match.")
}

查找"."字符:

r, err := regexp.Compile(`\.`)
if r.MatchString("Short.") == true {
    fmt.Printf("Has a dot.") // <---
} else {
    fmt.Printf("Has no dot.")
}

正则表达式中其它物殊字符: .+*?()|[]{}^$

r, err := regexp.Compile(`\$`)
if len(r.FindString("He paid $150 for that software.")) != 0 {
    fmt.Printf("Found $-symbol.") // <-
} else {
    fmt.Printf("No $$$.")
}

简单的重复

FindAllString()函数返回一个数组,包含所有匹配的字符串。 FindAllString()接收两个参数。一个字符串, 一个是int,表明最大返回匹配个数。-1表示返回所有值。

'+' 表示1个或者多个

s := "Eenie meenie miny moe."
r, err := regexp.Compile(`\w+`)
res := r.FindAllString(s, -1)
// Prints [Eenie meenie miny moe]
fmt.Printf("%v", res)

'*' 表示0个或者多个

s := "Firstname Lastname"
r, err := regexp.Compile(`\w+\s\w+`)
res := r.FindString(s)
// Prints Firstname Lastname
fmt.Printf("%v", res)

但如是用户输入的,则Firstname和lastName会有两个空格

s := "Firstname  Lastname"
r, err := regexp.Compile(`\w+\s\w+`)
res := r.FindString(s)
// 不会打印任何字符(the empty string=no match)
fmt.Printf("%v", res)

我们可以使用'\s+'则表示至少一个空格

s := "Firstname  Lastname"
r, err := regexp.Compile(`\w+\s+\w+`)
res := r.FindString(s)
// Prints Firstname  Lastname
fmt.Printf("%v", res)

如果你使用的是INI-style配置文件。你必须允许在=或左右有空格的出现

s := "Key = Value"
r, err := regexp.Compile(`\w+\s*=\s*\w+`)
res := r.FindAllString(s, -1)
fmt.Printf("%v", res)

锚和边界

^表示一行的开始

s := "Never say never."
r, err1 := regexp.Compile(`^N`)        // Do we have an 'N' at the beginning?
fmt.Printf("%v ", r.MatchString(s)) // true
t, err2 := regexp.Compile(`^n`)        // Do we have an 'n' at the beginning?
fmt.Printf("%v ", t.MatchString(s)) // false

$表示一行的结尾

s := "All is well that ends well"
r, err := regexp.Compile(`well$`)
fmt.Printf("%v ", r.MatchString(s)) // true

r, err = regexp.Compile(`well`)
fmt.Printf("%v ", r.MatchString(s))
// true, but matches with first
// occurrence of 'well'
r, err = regexp.Compile(`ends$`)
fmt.Printf("%v ", r.MatchString(s))
// false, not at end of line.

让我们在看看一个indexs的例子,FindStringIndex返回一个数组,它包含两个项,第一个项是整个匹配项的开始位置(当然从0开始)。 第二个项是整个匹配项的结束位置

s := "All is well that ends well"
//    012345678901234567890123456
//              1         2
r, err := regexp.Compile(`well$`)
fmt.Printf("%v", r.FindStringIndex(s)) // Prints [22 26]

r, err = regexp.Compile(`well`)
fmt.Printf("%v ", r.MatchString(s)) // true, but matches with first
                        // occurrence of 'well'
fmt.Printf("%v", r.FindStringIndex(s)) // Prints [7 11], the match starts at 7 and end before 11.

r, err = regexp.Compile(`ends$`)
fmt.Printf("%v ", r.MatchString(s)) // false, not at end of line.

'\b'表示单词边界. FindAllStringIndex()函数将捕获所有的配置项的位置

s := "How much wood would a woodchuck chuck in Hollywood?"
//    012345678901234567890123456789012345678901234567890
//              10        20        30        40        50
//             -1--         -2--                    -3--
// Find words that *start* with wood
r, err := regexp.Compile(`\bwood`)              //    1      2
fmt.Printf("%v", r.FindAllStringIndex(s, -1)) // [[9 13] [22 26]]

// Find words that *end* with wood
r, err = regexp.Compile(`wood\b`)               //   1      3 
fmt.Printf("%v", r.FindAllStringIndex(s, -1)) // [[9 13] [46 50]]

// Find words that *start* and *end* with wood
r, err = regexp.Compile(`\bwood\b`)             //   1
fmt.Printf("%v", r.FindAllStringIndex(s, -1)) // [[9 13]]

字符类

你也可以使用字符集或者字符类,比如以下这个例子[uio]。 则可以匹配"Hullo", "Hillo" 和 "Hollo".

r, err := regexp.Compile(`H[uio]llo`)
// Will print 'Hullo'.
fmt.Printf(r.FindString("Hello Regular Expression. Hullo again."))

[]中如果有^, 则是对字符集进行取反。 如以下这个例子将匹配"H.llo", 但.不表示'0', 'i', 'u'. 所以不能匹配"Hullo", "Hillo", "Hollo".但可以匹配"Hallo", "H9llo".

r, err := regexp.Compile(`H[^uio]llo`)
fmt.Printf("%v ", r.MatchString("Hillo")) // false
fmt.Printf("%v ", r.MatchString("Hallo")) // true
fmt.Printf("%v ", r.MatchString("H9llo")) // true

POSIX character classes

Golang regexp库实现了POSIX字符类。它们都是对常用的字符类取了一个可读性的别名. 详细请参考 RE2 regular expression syntax reference

[:alnum:]   alphanumeric (≡ [0-9A-Za-z])
[:alpha:]   alphabetic (≡ [A-Za-z])
[:ascii:]   ASCII (≡ [\x00-\x7F])
[:blank:]   blank (≡ [\t ])
[:cntrl:]   control (≡ [\x00-\x1F\x7F])
[:digit:]   digits (≡ [0-9])
[:graph:]   graphical (≡ [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~])
[:lower:]   lower case (≡ [a-z])
[:print:]   printable (≡ [ -~] == [ [:graph:]])
[:punct:]   punctuation (≡ [!-/:-@[-`{-~])
[:space:]   whitespace (≡ [\t\n\v\f\r ])
[:upper:]   upper case (≡ [A-Z])
[:word:]    word characters (≡ [0-9A-Za-z_])
[:xdigit:]  hex digit (≡ [0-9A-Fa-f])

Example: 查找小字母,标点符号,空格,数字

r, err := regexp.Compile(`[[:lower:]][[:punct:]][[:blank:]][[:digit:]]`)
if r.MatchString("Fred: 12345769") == true {
                     ----
    fmt.Printf("Match ") // 
} else {
    fmt.Printf("No match ")
}

Unicode Classes

Unicode是按block进行组织的[from, to]表示某一种语言或者主题。在这里我们只给出的部分例子,因为没有必须给出所有的语言(也没有什么实际帮助). 更多可参考complete unicode list of the re2 engine.

Example: Greek

r, err := regexp.Compile(`\p{Greek}`)

if r.MatchString("This is all Γςεεκ to me.") == true {
    fmt.Printf("Match ") // Will print 'Match'
} else {
    fmt.Printf("No match ")
}

可选

你可以通过'|', 提供一个可选项。 它允许有两个或者多个不同的匹配。 如果你只想在正则表达式的局部使用可选,你可以使用()对它们组合.

r, err1 := regexp.Compile(`Jim|Tim`)
fmt.Printf("%v", r.MatchString("Dickie, Tom and Tim")) // true
fmt.Printf("%v", r.MatchString("Jimmy, John and Jim")) // true

t, err2 := regexp.Compile(`Santa Clara|Santa Barbara`)
s := "Clara was from Santa Barbara and Barbara was from Santa Clara"
//                   -------------                      -----------
fmt.Printf("%v", t.FindAllStringIndex(s, -1))
// [[15 28] [50 61]]

u, err3 := regexp.Compile(`Santa (Clara|Barbara)`) // Equivalent
v := "Clara was from Santa Barbara and Barbara was from Santa Clara"
//                   -------------                      -----------
fmt.Printf("%v", u.FindAllStringIndex(v, -1))
// [[15 28] [50 61]]