ZetCode

Golang regexp.CompilePOSIX

最后修改于 2025 年 4 月 20 日

本教程解释了如何在 Go 中使用 regexp.CompilePOSIX 函数。我们将介绍 POSIX 正则表达式基础知识并提供实际示例。

一个 POSIX 正则表达式 是一个标准化的模式匹配语法。它在某些匹配行为和功能上与 Perl 风格的正则表达式不同。

regexp.CompilePOSIX 函数用于编译 POSIX 正则表达式。它保证最左最长匹配,不像 regexp.Compile

基本的 regexp.CompilePOSIX 示例

这个简单的例子演示了 POSIX 正则表达式的基本模式匹配。这里显示了最左最长的匹配行为。

basic_posix.go
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 风格的正则表达式匹配行为。这里演示了选择分支处理的差异。

posix_vs_perl.go
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 正则表达式可以使用特定模式验证电话号码。此示例显示了北美号码格式的匹配。

phone_posix.go
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 字符类语法。

extract_words.go
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 类。

posix_classes.go
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 字符类以提高可移植性。

posix_email.go
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 的执行时间。

posix_performance.go
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 正则表达式编译可能稍慢一些。对于大多数用例,差异通常可以忽略不计。

来源

Go regexp 包文档

本教程通过 POSIX 正则表达式用法和行为的示例,涵盖了 Go 中的 regexp.CompilePOSIX 函数。

作者

我叫 Jan Bodnar,我是一名充满激情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在教学编程方面拥有十多年的经验。

列出所有 Go 教程