Golang regexp.CompilePOSIX
最后修改于 2025 年 4 月 20 日
本教程解释了如何在 Go 中使用 regexp.CompilePOSIX 函数。我们将介绍 POSIX 正则表达式基础知识并提供实际示例。
一个 POSIX 正则表达式 是一个标准化的模式匹配语法。它在某些匹配行为和功能上与 Perl 风格的正则表达式不同。
regexp.CompilePOSIX 函数用于编译 POSIX 正则表达式。它保证最左最长匹配,不像 regexp.Compile。
基本的 regexp.CompilePOSIX 示例
这个简单的例子演示了 POSIX 正则表达式的基本模式匹配。这里显示了最左最长的匹配行为。
package main
import (
"fmt"
"regexp"
)
func main() {
re, err := regexp.CompilePOSIX(`a+`)
if err != nil {
panic(err)
}
// Shows leftmost-longest match behavior
fmt.Println(re.FindString("aa aaaa a")) // "aa"
}
该模式匹配一个或多个 'a' 字符。POSIX 正则表达式查找最左然后最长的匹配,不像 Perl 风格是贪婪的。
POSIX 与 Perl 风格匹配
这个例子对比了 POSIX 和 Perl 风格的正则表达式匹配行为。这里演示了选择分支处理的差异。
package main
import (
"fmt"
"regexp"
)
func main() {
text := "abc def ghi"
perlRe := regexp.MustCompile(`abc|abcdef`)
posixRe := regexp.MustCompilePOSIX(`abc|abcdef`)
fmt.Println("Perl-style:", perlRe.FindString(text)) // "abc"
fmt.Println("POSIX:", posixRe.FindString(text)) // "abc"
// With different input showing the difference
text2 := "abcdef"
fmt.Println("Perl-style:", perlRe.FindString(text2)) // "abc"
fmt.Println("POSIX:", posixRe.FindString(text2)) // "abcdef"
}
当替代项从同一位置开始时,POSIX 正则表达式会优先选择更长的匹配。Perl 风格则选择第一个匹配的替代项。
匹配电话号码
POSIX 正则表达式可以使用特定模式验证电话号码。此示例显示了北美号码格式的匹配。
package main
import (
"fmt"
"regexp"
)
func main() {
pattern := `^\(?[0-9]{3}\)?[-. ]?[0-9]{3}[-. ]?[0-9]{4}$`
re, err := regexp.CompilePOSIX(pattern)
if err != nil {
panic(err)
}
phones := []string{
"123-456-7890",
"(123) 456-7890",
"123.456.7890",
"1234567890",
"invalid",
}
for _, phone := range phones {
if re.MatchString(phone) {
fmt.Printf("%s is valid\n", phone)
} else {
fmt.Printf("%s is invalid\n", phone)
}
}
}
该模式匹配各种电话号码格式。POSIX 确保了不同实现之间一致的匹配行为。
使用 POSIX 提取单词
此示例使用 POSIX 单词边界从文本中提取单词。它演示了 POSIX 字符类语法。
package main
import (
"fmt"
"regexp"
)
func main() {
re := regexp.MustCompilePOSIX(`[[:alpha:]]+`)
text := "The quick brown fox jumps over 42 lazy dogs."
words := re.FindAllString(text, -1)
for _, word := range words {
fmt.Println(word)
}
}
[[:alpha:]] POSIX 字符类匹配字母字符。与 \w 相比,它在不同的正则表达式引擎之间具有更好的可移植性。
POSIX 字符类
POSIX 定义了更标准化的特定字符类。此示例演示了几个重要的 POSIX 类。
package main
import (
"fmt"
"regexp"
)
func main() {
text := "Sample123 Text456 With789 Numbers0"
// Match alphabetic characters only
alphaRe := regexp.MustCompilePOSIX(`[[:alpha:]]+`)
// Match alphanumeric characters
alnumRe := regexp.MustCompilePOSIX(`[[:alnum:]]+`)
// Match digits only
digitRe := regexp.MustCompilePOSIX(`[[:digit:]]+`)
fmt.Println("Alpha:", alphaRe.FindAllString(text, -1))
fmt.Println("Alnum:", alnumRe.FindAllString(text, -1))
fmt.Println("Digit:", digitRe.FindAllString(text, -1))
}
像 [[:alpha:]] 这样的 POSIX 字符类比 \w 或 \d 这样的简写类更易读且可移植。
POSIX 电子邮件验证
使用 POSIX 正则表达式进行电子邮件验证显示了标准化的方法。此模式使用 POSIX 字符类以提高可移植性。
package main
import (
"fmt"
"regexp"
)
func main() {
pattern := `^[[:alnum:]._%+-]+@[[:alnum:].-]+\.[[:alpha:]]{2,}$`
re, err := regexp.CompilePOSIX(pattern)
if err != nil {
panic(err)
}
emails := []string{
"user@example.com",
"first.last@domain.co.uk",
"invalid@.com",
"missing@tld.",
}
for _, email := range emails {
if re.MatchString(email) {
fmt.Printf("%s is valid\n", email)
} else {
fmt.Printf("%s is invalid\n", email)
}
}
}
该模式使用 POSIX 字符类而不是 Perl 风格的快捷方式。这使得模式更具可读性且符合标准。
性能比较
POSIX 正则表达式编译可能具有不同的性能特征。此示例比较了 Compile 和 CompilePOSIX 的执行时间。
package main
import (
"fmt"
"regexp"
"time"
)
func main() {
pattern := `([[:alnum:]]+)@([[:alnum:]]+)\.([[:alpha:]]{2,})`
text := "user@example.com"
start := time.Now()
for i := 0; i < 1000; i++ {
re, _ := regexp.Compile(pattern)
re.MatchString(text)
}
fmt.Println("Perl-style compile:", time.Since(start))
start = time.Now()
for i := 0; i < 1000; i++ {
re, _ := regexp.CompilePOSIX(pattern)
re.MatchString(text)
}
fmt.Println("POSIX compile:", time.Since(start))
}
由于其不同的匹配算法,POSIX 正则表达式编译可能稍慢一些。对于大多数用例,差异通常可以忽略不计。
来源
本教程通过 POSIX 正则表达式用法和行为的示例,涵盖了 Go 中的 regexp.CompilePOSIX 函数。