基础
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]]