概述
问号是regex中的可选操作符。这意味着它可以选择匹配问号前的字符
例如。
abcd?
这将同时匹配**"abc "和 "abcd"。**
程序
让我们看一个同样的例子。
package main
import (
"fmt"
"regexp"
)
func main() {
sampleRegexp := regexp.MustCompile("abcd?")
match := sampleRegexp.Match([]byte("abc"))
fmt.Printf("For abc: %t\n", match)
match = sampleRegexp.Match([]byte("abcd"))
fmt.Printf("For abcd: %t\n", match)
}
输出
For abc: true
For abcd: true
一些字符也可以通过用小括号将其封闭,然后将问号放在其后面,使其成为可选项。例子
abc(de)?
package main
import (
"fmt"
"regexp"
)
func main() {
sampleRegexp := regexp.MustCompile("abc(de)?")
match := sampleRegexp.Match([]byte("abc"))
fmt.Printf("For abc: %t\n", match)
match = sampleRegexp.Match([]byte("abcde"))
fmt.Printf("For abcde: %t\n", match)
match = sampleRegexp.Match([]byte("abcd"))
fmt.Printf("For abcd: %t\n", match)
}
输出
For abc: true
For abcde: true
For abcd: true
它匹配**"abc**"和 "abcde"。
它还匹配了**"abcd"。你一定想知道为什么它匹配"abcd"。**
如果给定的字符串或文本包含作为子串的反义词,那么它也会给出一个匹配。这就是为什么它给出了一个匹配,因为**"abcd "包含 "abc"这个子串**,这是一个匹配的反义词。如果我们想做完整的字符串匹配,那么我们需要在regex的开头和结尾使用锚点字符。 锚点字符将被用在开头,Dollar锚点字符将被用在结尾。
让我们看一个同样的例子。
package main
import (
"fmt"
"regexp"
)
func main() {
sampleRegexp := regexp.MustCompile("^abc(de)?$")
match := sampleRegexp.Match([]byte("abc"))
fmt.Printf("For abc: %t\n", match)
match = sampleRegexp.Match([]byte("abcde"))
fmt.Printf("For abcde: %t\n", match)
match = sampleRegexp.Match([]byte("abcd"))
fmt.Printf("For abcd: %t\n", match)
}
输出
For abc: true
For abcde: true
For abcd: false
问号操作符是非疲劳的
问号运算符是非懒惰或贪婪的。这意味着它将首先匹配可选的模式。
在正则表达式的世界里,非懒惰(有时也称为贪婪)意味着要尽可能多地匹配。而懒惰(有时也称为非贪婪)意味着只匹配需要的内容。
例如,对于给定的regex
https?
如果你试图匹配下面的输入字符串
Better is https
那么有两个选项
-
匹配http
-
匹配https
那么它将总是匹配https而不是http。原因是,它是无懈可击的。 即使它匹配了http,它也不会停止,并试图匹配可选的字符。如果可选字符匹配,它就会返回https,否则就会返回http。
让我们看一个同样的例子
package main
import (
"fmt"
"regexp"
)
func main() {
sampleRegexp := regexp.MustCompile("https?")
match := sampleRegexp.Find([]byte("Better is https"))
fmt.Printf("Match: %s\n", match)
}
输出
Match: https
在上面的程序中,我们使用了Find函数,它返回与regex匹配的实际子串。你可以注意到,在输出中,它匹配的是**"https",而不是**"http**",因为** 问号操作符是不透明的。
关于双问号运算符
它是懒惰的。 一旦它找到了第一个匹配,它就不会再尝试进一步匹配。因此,对于上述文本,它总是给出**"http "而** 不是 "https "的结果**。**
让我们看一个例子
package main
import (
"fmt"
"regexp"
)
func main() {
sampleRegexp := regexp.MustCompile("https??")
match := sampleRegexp.Find([]byte("Better is https"))
fmt.Printf("Match: %s\n", match)
}
输出
Match: http
量词后的问号
量词后面的问号'?'是懒惰的或非贪婪的。量词可以是
-
加号'+' - 一个或多个
-
**星号'*' -**零或更多
见下面的例子
package main
import (
"fmt"
"regexp"
)
func main() {
sampleRegexp := regexp.MustCompile("http(s+?)")
match := sampleRegexp.Find([]byte("Better is httpsss"))
fmt.Printf("Match: %s\n", match)
sampleRegexp = regexp.MustCompile("http(s*?)")
match = sampleRegexp.Find([]byte("Better is httpsss"))
fmt.Printf("Match: %s\n", match)
}
输出
Match: https
Match: http
在上述程序中,我们有两种情况
-
加号运算符后的问号
-
星号运算符后的问号
在这两种情况下,输入的字符串都是
Better is httpsss
在第一种情况下,我们在重合词中的加号运算符后使用了一个问号
"http(s+?)"
它给出的匹配结果是**"https",而**不是 "httpsss",因为在加号运算符后使用问号是不可取的。
在第二种情况下,我们在重码中的星号后使用了问号
"http(s*?)"
当在星号运算符之后使用问号时,它给出的匹配结果是**"http",而**不是 "httpsss",因为问号是非贪婪的。
让我们看看另一个例子
package main
import (
"fmt"
"regexp"
)
func main() {
sampleRegexp := regexp.MustCompile("(a+?)(a*)")
match := sampleRegexp.FindStringSubmatch("aaaaaaa")
fmt.Printf("Match: %s Length: %d\n", match, len(match))
sampleRegexp = regexp.MustCompile("(a*?)(a*)")
match = sampleRegexp.FindStringSubmatch("aaaaaaa")
fmt.Printf("Match: %s Length: %d\n", match, len(match))
}
输出
Match: [aaaaaaa a aaaaaa] Length: 3
Match: [aaaaaaa aaaaaaa] Length: 3
在上面的程序中,我们同样有两种情况
-
在加号运算符后有一个问号
-
星号运算符后的问号
在第一种情况下,我们有两个捕获组的词条
(a+?)(a*)
第一个捕获组给出了**'a'的单一匹配,而第二个捕获组给出了其余的匹配。这表明在加号**运算符之后使用的问号运算符是非贪婪或懒惰的。
在第二种情况下,我们又有两个捕获组的词条
(a*?)(a*)
第一个捕获组给出了一个零匹配的**'a',而第二个捕获组给出了其余的。这表明在Asterisk**运算符之后使用的问号运算符是非贪婪的或懒惰的。
以上是关于Go中的问号运算符的全部内容。希望你喜欢这篇文章。请在评论中分享反馈。
另外,请查看我们的Golang高级教程系列------。 Golang高级教程
The postGolang Regex:正则表达式中的可选操作符或问号(?)首次出现在Welcome To Golang By Example上。