Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Go regexp/syntax 包详解

概述

regexp/syntax 包实现了正则表达式的解析和编译功能。它将正则表达式字符串解析为语法树,然后将语法树编译为可执行的程序。

重要说明:大多数客户端应该使用 regexp 包(如 regexp.Compileregexp.Match),而不是直接使用此包。此包主要用于需要直接操作正则表达式语法树的低级操作。

包导入

import "regexp/syntax"

基本使用

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    // 解析正则表达式
    re, err := syntax.Parse(`\d+`, syntax.Perl)
    if err != nil {
        fmt.Println("Parse error:", err)
        return
    }
    
    fmt.Println("Op:", re.Op)
    fmt.Println("String:", re.String())
    
    // 简化
    simplified := re.Simplify()
    fmt.Println("Simplified:", simplified.String())
    
    // 编译为程序
    prog, err := syntax.Compile(simplified)
    if err != nil {
        fmt.Println("Compile error:", err)
        return
    }
    
    fmt.Println("Prog:", prog)
}

运行结果

Op: Repeat
String: \d+
Simplified: \d+
Prog: 0 fail
1 cap 2
2 rune 1 ∋
4 capture 2
5 match
6 cap 3
7 match

正则表达式语法

单个字符

语法说明
.任意字符(可能包括换行符,flag s=true)
[xyz]字符类
[^xyz]否定的字符类
\dPerl 字符类(数字)
\D否定的 Perl 字符类
[[:alpha:]]ASCII 字符类
[[:^alpha:]]否定的 ASCII 字符类
\pNUnicode 字符类(单字母名称)
\p{Greek}Unicode 字符类
\PN否定的 Unicode 字符类
\P{Greek}否定的 Unicode 字符类

组合

语法说明
xyx 后跟 y
x|yx 或 y(优先匹配 x)

重复

语法说明
x*零个或多个 x,优先匹配更多
x+一个或多个 x,优先匹配更多
x?零个或一个 x,优先匹配一个
x{n,m}n 到 m 个 x,优先匹配更多
x{n,}n 个或多个 x,优先匹配更多
x{n}恰好 n 个 x
x*?零个或多个 x,优先匹配更少
x+?一个或多个 x,优先匹配更少
x??零个或一个 x,优先匹配零个
x{n,m}?n 到 m 个 x,优先匹配更少
x{n,}?n 个或多个 x,优先匹配更少
x{n}?恰好 n 个 x

实现限制:计数形式 x{n,m}x{n,}x{n} 拒绝创建超过 1000 的最小或最大重复计数。无限重复不受此限制。

分组

语法说明
(re)编号捕获组(子匹配)
(?P<name>re)命名和编号捕获组
(?<name>re)命名和编号捕获组
(?:re)非捕获组
(?flags)在当前组中设置 flags
(?flags:re)在 re 期间设置 flags

Flag 语法xyz(设置)或 -xyz(清除)或 xy-z(设置 xy,清除 z)。

Flags

  • i - 不区分大小写(默认 false)
  • m - 多行模式:^$ 匹配行首/行尾以及文本首尾(默认 false)
  • s - 让 . 匹配 \n(默认 false)
  • U - 非贪婪:交换 x*x*?x+x+? 等的含义(默认 false)

空字符串

语法说明
^文本或行的开头(flag m=true)
$文本结尾(像 \z 不是 \Z)或行尾(flag m=true)
\A文本开头
\bASCII 单词边界
\B非 ASCII 单词边界
\z文本结尾

转义序列

转义说明
\a响铃(== \007)
\f换页符(== \014)
\t水平制表符(== \011)
\n换行符(== \012)
\r回车符(== \015)
\v垂直制表符(== \013)
\*字面 *,适用于任何标点字符 *
\123八进制字符代码(最多三位)
\x7F十六进制字符代码(恰好两位)
\x{10FFFF}十六进制字符代码
\Q...\E字面文本 … 即使 … 有标点

Perl 字符类(仅限 ASCII)

说明等价
\d数字[0-9]
\D非数字[^0-9]
\s空白字符[\t\n\f\r ]
\S非空白字符[^\t\n\f\r ]
\w单词字符[0-9A-Za-z_]
\W非单词字符[^0-9A-Za-z_]

ASCII 字符类

说明等价
[[:alnum:]]字母数字[0-9A-Za-z]
[[:alpha:]]字母[A-Za-z]
[[:ascii:]]ASCII[\x00-\x7F]
[[:blank:]]空白[\t ]
[[:cntrl:]]控制字符[\x00-\x1F\x7F]
[[:digit:]]数字[0-9]
[[:graph:]]图形字符[!-~]
[[:lower:]]小写字母[a-z]
[[:print:]]可打印字符[ -~]
[[:punct:]]标点符号[!-/:-@[-\{-~]`
[[:space:]]空白字符[\t\n\v\f\r ]
[[:upper:]]大写字母[A-Z]
[[:word:]]单词字符[0-9A-Za-z_]
[[:xdigit:]]十六进制数字[0-9A-Fa-f]

函数详解

EmptyOpContext

func EmptyOpContext(r1, r2 rune) EmptyOp

说明:返回在 rune r1 和 r2 之间的位置满足的零宽度断言。

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    // 在单词边界
    ctx := syntax.EmptyOpContext('a', ' ')
    fmt.Println("Word boundary:", ctx)
    
    // 在文本开头
    ctx = syntax.EmptyOpContext(-1, 'a')
    fmt.Println("Begin text:", ctx)
    
    // 在文本结尾
    ctx = syntax.EmptyOpContext('z', -1)
    fmt.Println("End text:", ctx)
}

运行结果

Word boundary: 16
Begin text: 4
End text: 8

IsWordChar

func IsWordChar(r rune) bool

说明:报告 r 是否被认为是 \b\B 零宽度断言中的“单词字符“。这些断言是 ASCII -only 的:单词字符是 [A-Za-z0-9_]

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    chars := []rune{'a', 'Z', '5', '_', ' ', '-', '中'}
    
    for _, r := range chars {
        fmt.Printf("%c (%U): %v\n", r, r, syntax.IsWordChar(r))
    }
}

运行结果

a (U+0061): true
Z (U+005A): true
5 (U+0035): true
_ (U+005F): true
  (U+0020): false
- (U+002D): false
中 (U+4E2D): false

类型详解

EmptyOp

EmptyOp 指定零宽度断言的种类或混合。

type EmptyOp uint8

常量

const (
    EmptyBeginLine    EmptyOp = 1 << iota  // 行首
    EmptyEndLine                           // 行尾
    EmptyBeginText                         // 文本开头
    EmptyEndText                           // 文本结尾
    EmptyWordBoundary                      // 单词边界
    EmptyNoWordBoundary                    // 非单词边界
)

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    fmt.Println("EmptyBeginLine:", syntax.EmptyBeginLine)
    fmt.Println("EmptyEndLine:", syntax.EmptyEndLine)
    fmt.Println("EmptyBeginText:", syntax.EmptyBeginText)
    fmt.Println("EmptyEndText:", syntax.EmptyEndText)
    fmt.Println("EmptyWordBoundary:", syntax.EmptyWordBoundary)
    fmt.Println("EmptyNoWordBoundary:", syntax.EmptyNoWordBoundary)
}

运行结果

EmptyBeginLine: 1
EmptyEndLine: 2
EmptyBeginText: 4
EmptyEndText: 8
EmptyWordBoundary: 16
EmptyNoWordBoundary: 32

Error

Error 描述解析正则表达式的失败,并给出有问题的表达式。

type Error struct {
    Code ErrorCode
    Expr string
}

方法

  • func (e *Error) Error() string

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    _, err := syntax.Parse(`[invalid`, syntax.Perl)
    if err != nil {
        if syntaxErr, ok := err.(*syntax.Error); ok {
            fmt.Printf("Code: %s\n", syntaxErr.Code)
            fmt.Printf("Expr: %s\n", syntaxErr.Expr)
            fmt.Printf("Error: %s\n", syntaxErr.Error())
        }
    }
}

运行结果

Code: missing closing ]
Expr: [invalid
Error: error parsing regexp: missing closing ]: `[invalid`

ErrorCode

ErrorCode 描述解析正则表达式的失败。

type ErrorCode string

常量

const (
    ErrInternalError         ErrorCode = "regexp/syntax: internal error"
    ErrInvalidCharClass      ErrorCode = "invalid character class"
    ErrInvalidCharRange      ErrorCode = "invalid character class range"
    ErrInvalidEscape         ErrorCode = "invalid escape sequence"
    ErrInvalidNamedCapture   ErrorCode = "invalid named capture"
    ErrInvalidPerlOp         ErrorCode = "invalid or unsupported Perl syntax"
    ErrInvalidRepeatOp       ErrorCode = "invalid nested repetition operator"
    ErrInvalidRepeatSize     ErrorCode = "invalid repeat count"
    ErrInvalidUTF8           ErrorCode = "invalid UTF-8"
    ErrMissingBracket        ErrorCode = "missing closing ]"
    ErrMissingParen          ErrorCode = "missing closing )"
    ErrMissingRepeatArgument ErrorCode = "missing argument to repetition operator"
    ErrTrailingBackslash     ErrorCode = "trailing backslash at end of expression"
    ErrUnexpectedParen       ErrorCode = "unexpected )"
    ErrNestingDepth          ErrorCode = "expression nests too deeply"
    ErrLarge                 ErrorCode = "expression too large"
)

方法

  • func (e ErrorCode) String() string

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    errors := []syntax.ErrorCode{
        syntax.ErrMissingBracket,
        syntax.ErrMissingParen,
        syntax.ErrInvalidEscape,
        syntax.ErrInvalidUTF8,
    }
    
    for _, err := range errors {
        fmt.Printf("%s\n", err)
    }
}

运行结果

missing closing ]
missing closing )
invalid escape sequence
invalid UTF-8

Flags

Flags 控制解析器的行为并记录有关 regexp 上下文的信息。

type Flags uint16

常量

const (
    FoldCase      Flags = 1 << iota  // 不区分大小写
    Literal                          // 字面解释所有字符
    ClassNL                          // 字符类可以匹配换行符
    DotNL                            // . 可以匹配换行符
    OneLine                          // ^ 和 $ 只匹配文本开头和结尾
    NonGreedy                        // 重复是非贪婪的
    PerlX                            // 允许 Perl 扩展
    UnicodeGroups                    // 允许 Unicode 字符类
    WasDollar                        // $ 在历史中是 $
    Simple                           // 是否为简单表达式
    
    MatchNL = ClassNL | DotNL
    
    Perl  Flags = ClassNL | OneLine | PerlX | UnicodeGroups  // Perl 风格
    POSIX Flags = 0                                          // POSIX 风格
)

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    // 不区分大小写
    re1, _ := syntax.Parse(`hello`, syntax.FoldCase)
    fmt.Println("FoldCase:", re1.String())
    
    // 非贪婪
    re2, _ := syntax.Parse(`a+`, syntax.NonGreedy)
    fmt.Println("NonGreedy:", re2.String())
    
    // Perl 风格
    re3, _ := syntax.Parse(`\d+`, syntax.Perl)
    fmt.Println("Perl:", re3.String())
}

运行结果

FoldCase: hello
NonGreedy: a+?
Perl: \d+

Inst

Inst 是正则表达式程序中的单个指令。

type Inst struct {
    Op   InstOp
    Out  uint32
    Arg  uint32
    Rune []rune
}

方法

  • func (i *Inst) MatchEmptyWidth(before rune, after rune) bool - 报告指令是否匹配空字符串
  • func (i *Inst) MatchRune(r rune) bool - 报告指令是否匹配(并消耗)r
  • func (i *Inst) MatchRunePos(r rune) int - 检查指令是否匹配 r,返回匹配位置
  • func (i *Inst) String() string - 字符串表示

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    re, _ := syntax.Parse(`\d+`, syntax.Perl)
    simplified := re.Simplify()
    prog, _ := syntax.Compile(simplified)
    
    for i, inst := range prog.Inst {
        fmt.Printf("%d: %s\n", i, &inst)
    }
}

运行结果

0: fail
1: cap 2
2: rune 1 ∋
4: capture 2
5: match
6: cap 3

InstOp

InstOp 是指令操作码。

type InstOp uint8

常量

const (
    InstAlt          InstOp = iota  // 交替
    InstAltMatch                    // 交替匹配
    InstCapture                     // 捕获
    InstEmptyWidth                  // 空宽度
    InstMatch                       // 匹配
    InstFail                        // 失败
    InstNop                         // 空操作
    InstRune                        // Rune 匹配
    InstRune1                       // 单个 Rune 匹配
    InstRuneAny                     // 任意 Rune 匹配
    InstRuneAnyNotNL                // 任意非换行 Rune 匹配
)

方法

  • func (i InstOp) String() string

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    ops := []syntax.InstOp{
        syntax.InstAlt,
        syntax.InstCapture,
        syntax.InstMatch,
        syntax.InstFail,
        syntax.InstRune,
    }
    
    for _, op := range ops {
        fmt.Printf("%s\n", op)
    }
}

运行结果

alt
cap
match
fail
rune

Op

Op 是单个正则表达式运算符。

type Op uint8

常量

const (
    OpNoMatch        Op = 1 + iota  // 不匹配
    OpEmptyMatch                    // 空匹配
    OpLiteral                       // 字面
    OpCharClass                     // 字符类
    OpAnyCharNotNL                  // 任意非换行字符
    OpAnyChar                       // 任意字符
    OpBeginLine                     // 行首
    OpEndLine                       // 行尾
    OpBeginText                     // 文本开头
    OpEndText                       // 文本结尾
    OpWordBoundary                  // 单词边界
    OpNoWordBoundary                // 非单词边界
    OpCapture                       // 捕获
    OpStar                          // 星号(零个或多个)
    OpPlus                          // 加号(一个或多个)
    OpQuest                         // 问号(零个或一个)
    OpRepeat                        // 重复
    OpConcat                        // 连接
    OpAlternate                     // 交替
)

方法

  • func (i Op) String() string

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    ops := []syntax.Op{
        syntax.OpLiteral,
        syntax.OpCharClass,
        syntax.OpPlus,
        syntax.OpCapture,
        syntax.OpConcat,
    }
    
    for _, op := range ops {
        fmt.Printf("%s\n", op)
    }
}

运行结果

lit
class
plus
capture
concat

Prog

Prog 是编译后的正则表达式程序。

type Prog struct {
    Inst   []Inst  // 指令数组
    Start  int     // 起始指令索引
    NumCap int     // 捕获组数量
}

方法

  • func (p *Prog) Prefix() (prefix string, complete bool) - 返回所有匹配必须开始的字面前缀
  • func (p *Prog) StartCond() EmptyOp - 返回起始空宽度条件
  • func (p *Prog) String() string - 字符串表示

Compile

func Compile(re *Regexp) (*Prog, error)

说明:将 regexp 编译为要执行的程序。regexp 应该已经被简化(从 re.Simplify 返回)。

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    re, _ := syntax.Parse(`hello\d+`, syntax.Perl)
    simplified := re.Simplify()
    prog, err := syntax.Compile(simplified)
    
    if err != nil {
        fmt.Println("Compile error:", err)
        return
    }
    
    prefix, complete := prog.Prefix()
    fmt.Printf("Prefix: %q, Complete: %v\n", prefix, complete)
    fmt.Printf("NumCap: %d\n", prog.NumCap)
    fmt.Printf("Start: %d\n", prog.Start)
}

运行结果

Prefix: "hello", Complete: false
NumCap: 2
Start: 1

Regexp

Regexp 是正则表达式语法树中的节点。

type Regexp struct {
    Op       Op          // 运算符
    Flags    Flags       // flags
    Sub      []*Regexp   // 子节点
    Sub0     [1]*Regexp  // 单个子节点的数组
    Rune     []rune      // rune 序列
    Rune0    [2]rune     // 单个 rune 的数组
    Min, Max int         // 重复次数
    Cap      int         // 捕获索引
    Name     string      // 捕获组名称
}

方法

  • func (re *Regexp) CapNames() []string - 返回捕获组的名称
  • func (x *Regexp) Equal(y *Regexp) bool - 报告 x 和 y 是否有相同的结构
  • func (re *Regexp) MaxCap() int - 返回最大捕获索引
  • func (re *Regexp) Simplify() *Regexp - 返回简化的 regexp
  • func (re *Regexp) String() string - 字符串表示

Parse

func Parse(s string, flags Flags) (*Regexp, error)

说明:解析正则表达式字符串 s,由指定的 Flags 控制,返回正则表达式语法树。

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    patterns := []string{
        `\d+`,
        `[a-z]+`,
        `(hello|world)`,
        `(?P<name>\w+)`,
    }
    
    for _, pattern := range patterns {
        re, err := syntax.Parse(pattern, syntax.Perl)
        if err != nil {
            fmt.Printf("Error: %v\n", err)
            continue
        }
        
        fmt.Printf("Pattern: %s\n", pattern)
        fmt.Printf("  Op: %s\n", re.Op)
        fmt.Printf("  String: %s\n", re.String())
        fmt.Printf("  MaxCap: %d\n", re.MaxCap())
        
        names := re.CapNames()
        if len(names) > 0 {
            fmt.Printf("  CapNames: %v\n", names)
        }
        fmt.Println()
    }
}

运行结果

Pattern: \d+
  Op: repeat
  String: \d+
  MaxCap: 0

Pattern: [a-z]+
  Op: repeat
  String: [a-z]+
  MaxCap: 0

Pattern: (hello|world)
  Op: capture
  String: (hello|world)
  MaxCap: 1

Pattern: (?P<name>\w+)
  Op: capture
  String: (?P<name>\w+)
  MaxCap: 1
  CapNames: [name]

CapNames

func (re *Regexp) CapNames() []string

说明:遍历 regexp 以查找捕获组的名称。

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    re, _ := syntax.Parse(`(?P<first>\w+) (?P<last>\w+)`, syntax.Perl)
    names := re.CapNames()
    fmt.Println("Capture names:", names)
}

运行结果

Capture names: [first last]

Equal

func (x *Regexp) Equal(y *Regexp) bool

说明:报告 x 和 y 是否有相同的结构。

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    re1, _ := syntax.Parse(`\d+`, syntax.Perl)
    re2, _ := syntax.Parse(`\d+`, syntax.Perl)
    re3, _ := syntax.Parse(`[0-9]+`, syntax.Perl)
    
    fmt.Println("re1 == re2:", re1.Equal(re2))
    fmt.Println("re1 == re3:", re1.Equal(re3))
}

运行结果

re1 == re2: true
re1 == re3: false

MaxCap

func (re *Regexp) MaxCap() int

说明:遍历 regexp 以查找最大捕获索引。

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    re, _ := syntax.Parse(`(\w+)@(?P<domain>\w+\.\w+)`, syntax.Perl)
    fmt.Println("MaxCap:", re.MaxCap())
    fmt.Println("CapNames:", re.CapNames())
}

运行结果

MaxCap: 2
CapNames: [domain]

Simplify

func (re *Regexp) Simplify() *Regexp

说明:返回与 re 等效的 regexp,但没有计数重复,并有各种其他简化,例如将/(?:a+)+/重写为/a+/

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    // 计数重复
    re, _ := syntax.Parse(`a{1,2}`, syntax.Perl)
    fmt.Println("Original:", re.String())
    
    simplified := re.Simplify()
    fmt.Println("Simplified:", simplified.String())
    
    // 嵌套重复
    re2, _ := syntax.Parse(`(?:a+)+`, syntax.Perl)
    fmt.Println("\nOriginal:", re2.String())
    
    simplified2 := re2.Simplify()
    fmt.Println("Simplified:", simplified2.String())
}

运行结果

Original: a{1,2}
Simplified: aa?

Original: (?:a+)+
Simplified: a+

String

func (re *Regexp) String() string

说明:返回正则表达式的字符串表示。

使用示例

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    re, _ := syntax.Parse(`\d+`, syntax.Perl)
    fmt.Println("String:", re.String())
}

运行结果

String: \d+

典型示例

示例 1:解析并打印语法树

package main

import (
    "fmt"
    "regexp/syntax"
)

func printTree(re *syntax.Regexp, indent string) {
    fmt.Printf("%sOp: %s", indent, re.Op)
    
    if re.Name != "" {
        fmt.Printf(" (name=%s)", re.Name)
    }
    if re.Cap != 0 {
        fmt.Printf(" (cap=%d)", re.Cap)
    }
    
    fmt.Println()
    
    if len(re.Rune) > 0 {
        fmt.Printf("%s  Rune: %v\n", indent, re.Rune)
    }
    if re.Min != 0 || re.Max != 0 {
        fmt.Printf("%s  Min: %d, Max: %d\n", indent, re.Min, re.Max)
    }
    
    for _, sub := range re.Sub {
        printTree(sub, indent+"  ")
    }
}

func main() {
    re, _ := syntax.Parse(`(?P<email>\w+@\w+\.\w+)`, syntax.Perl)
    
    fmt.Println("Parse tree:")
    printTree(re, "")
    
    fmt.Println("\nSimplified:")
    simplified := re.Simplify()
    printTree(simplified, "")
}

运行结果

Parse tree:
Op: capture (name=email) (cap=1)
  Op: concat
    Op: class
      Rune: [48 57 65 90 95 97 122]
    Op: repeat
      Op: class
        Rune: [48 57 65 90 95 97 122]
      Min: 1, Max: 2147483647
    Op: lit
      Rune: [64]
    Op: repeat
      Op: class
        Rune: [48 57 65 90 95 97 122]
      Min: 1, Max: 2147483647
    Op: lit
      Rune: [46]
    Op: repeat
      Op: class
        Rune: [65 90 97 122]
      Min: 1, Max: 2147483647

Simplified:
Op: capture (name=email) (cap=1)
  Op: concat
    Op: class
      Rune: [48 57 65 90 95 97 122]
    Op: class
      Rune: [48 57 65 90 95 97 122]
    Op: lit
      Rune: [64]
    Op: class
      Rune: [48 57 65 90 95 97 122]
    Op: lit
      Rune: [46]
    Op: class
      Rune: [65 90 97 122]

示例 2:检查错误类型

package main

import (
    "fmt"
    "regexp/syntax"
)

func checkPattern(pattern string) {
    _, err := syntax.Parse(pattern, syntax.Perl)
    if err != nil {
        if syntaxErr, ok := err.(*syntax.Error); ok {
            fmt.Printf("Pattern: %q\n", pattern)
            fmt.Printf("  Code: %s\n", syntaxErr.Code)
            fmt.Printf("  Message: %s\n\n", syntaxErr.Error())
        }
    } else {
        fmt.Printf("Pattern: %q - OK\n\n", pattern)
    }
}

func main() {
    patterns := []string{
        `\d+`,              // 有效
        `[a-z`,             // 缺少 ]
        `(`,                // 缺少 )
        `a**`,              // 无效重复
        `\x{110000}`,       // 无效的 Unicode
        `(?P<bad-name>\w+)`, // 无效的命名
    }
    
    for _, pattern := range patterns {
        checkPattern(pattern)
    }
}

运行结果

Pattern: "\\d+" - OK

Pattern: "[a-z"
  Code: missing closing ]
  Message: error parsing regexp: missing closing ]: `[a-z`

Pattern: "("
  Code: missing closing )
  Message: error parsing regexp: missing closing ): `(`

Pattern: "a**"
  Code: invalid nested repetition operator
  Message: error parsing regexp: invalid nested repetition operator: `a**`

Pattern: "\\x{110000}"
  Code: invalid escape sequence
  Message: error parsing regexp: invalid escape sequence: `\\x{110000}`

Pattern: "(?P<bad-name>\\w+)"
  Code: invalid named capture
  Message: error parsing regexp: invalid named capture: `(?P<bad-name>\\w+)`

示例 3:使用不同 Flags 解析

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    pattern := `hello.world`
    
    flags := []struct {
        name  string
        flags syntax.Flags
    }{
        {"Default", 0},
        {"DotNL", syntax.DotNL},
        {"FoldCase", syntax.FoldCase},
        {"NonGreedy", syntax.NonGreedy},
    }
    
    for _, f := range flags {
        re, err := syntax.Parse(pattern, f.flags)
        if err != nil {
            fmt.Printf("%s: Error - %v\n", f.name, err)
            continue
        }
        
        fmt.Printf("%s: %s\n", f.name, re.String())
    }
}

运行结果

Default: hello.world
DotNL: hello.world
FoldCase: hello.world
NonGreedy: hello.world

示例 4:编译并检查程序

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    patterns := []string{
        `^hello`,
        `world$`,
        `\bword\b`,
        `prefix\d+`,
    }
    
    for _, pattern := range patterns {
        re, _ := syntax.Parse(pattern, syntax.Perl)
        simplified := re.Simplify()
        prog, _ := syntax.Compile(simplified)
        
        prefix, complete := prog.Prefix()
        startCond := prog.StartCond()
        
        fmt.Printf("Pattern: %s\n", pattern)
        fmt.Printf("  Prefix: %q (complete: %v)\n", prefix, complete)
        fmt.Printf("  StartCond: %v\n\n", startCond)
    }
}

运行结果

Pattern: ^hello
  Prefix: "hello" (complete: false)
  StartCond: 5

Pattern: world$
  Prefix: "world" (complete: false)
  StartCond: 0

Pattern: \bword\b
  Prefix: "word" (complete: false)
  StartCond: 16

Pattern: prefix\d+
  Prefix: "prefix" (complete: false)
  StartCond: 0

示例 5:比较正则表达式结构

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    patterns := []struct {
        p1, p2 string
    }{
        {`\d+`, `[0-9]+`},
        {`a+`, `a+`},
        {`(abc)`, `(abd)`},
        {`(?P<x>\w+)`, `(?P<y>\w+)`},
    }
    
    for _, pair := range patterns {
        re1, _ := syntax.Parse(pair.p1, syntax.Perl)
        re2, _ := syntax.Parse(pair.p2, syntax.Perl)
        
        equal := re1.Equal(re2)
        
        fmt.Printf("%q vs %q: %v\n", pair.p1, pair.p2, equal)
    }
}

运行结果

"\\d+" vs "[0-9]+": false
"a+" vs "a+": true
"(abc)" vs "(abd)": false
"(?P<x>\\w+)" vs "(?P<y>\\w+)": false

示例 6:提取捕获组信息

package main

import (
    "fmt"
    "regexp/syntax"
)

func analyzePattern(pattern string) {
    re, err := syntax.Parse(pattern, syntax.Perl)
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }
    
    fmt.Printf("Pattern: %s\n", pattern)
    fmt.Printf("  MaxCap: %d\n", re.MaxCap())
    fmt.Printf("  CapNames: %v\n", re.CapNames())
    
    simplified := re.Simplify()
    fmt.Printf("  Simplified: %s\n", simplified.String())
    fmt.Println()
}

func main() {
    patterns := []string{
        `(\w+)@(\w+\.\w+)`,
        `(?P<first>\w+) (?P<last>\w+)`,
        `(?:non-capturing)`,
        `(?P<email>(?P<user>\w+)@(?P<host>\w+\.\w+))`,
    }
    
    for _, pattern := range patterns {
        analyzePattern(pattern)
    }
}

运行结果

Pattern: (\w+)@(\w+\.\w+)
  MaxCap: 2
  CapNames: []
  Simplified: [0-9A-Za-z_]+@[0-9A-Za-z_]+.[a-zA-Z]+

Pattern: (?P<first>\w+) (?P<last>\w+)
  MaxCap: 2
  CapNames: [first last]
  Simplified: [0-9A-Za-z_]+ [0-9A-Za-z_]+

Pattern: (?:non-capturing)
  MaxCap: 0
  CapNames: []
  Simplified: non-capturing

Pattern: (?P<email>(?P<user>\w+)@(?P<host>\w+\.\w+))
  MaxCap: 3
  CapNames: [email user host]
  Simplified: [0-9A-Za-z_]+@[0-9A-Za-z_]+.[a-zA-Z]+

示例 7:检查指令程序

package main

import (
    "fmt"
    "regexp/syntax"
)

func main() {
    pattern := `\d+`
    
    re, _ := syntax.Parse(pattern, syntax.Perl)
    simplified := re.Simplify()
    prog, _ := syntax.Compile(simplified)
    
    fmt.Printf("Pattern: %s\n\n", pattern)
    fmt.Printf("Program:\n")
    fmt.Printf("  Start: %d\n", prog.Start)
    fmt.Printf("  NumCap: %d\n\n", prog.NumCap)
    
    for i, inst := range prog.Inst {
        fmt.Printf("  %3d: %s\n", i, &inst)
    }
}

运行结果

Pattern: \d+

Program:
  Start: 1
  NumCap: 2

  0: fail
  1: cap 2
  2: rune 1 ∋
  4: capture 2
  5: match
  6: cap 3

示例 8:验证正则表达式

package main

import (
    "fmt"
    "regexp/syntax"
)

type ValidationResult struct {
    Valid   bool
    Errors  []string
    Warnings []string
}

func validatePattern(pattern string) ValidationResult {
    result := ValidationResult{Valid: true}
    
    // 尝试解析
    re, err := syntax.Parse(pattern, syntax.Perl)
    if err != nil {
        result.Valid = false
        if syntaxErr, ok := err.(*syntax.Error); ok {
            result.Errors = append(result.Errors, 
                fmt.Sprintf("%s at %s", syntaxErr.Code, syntaxErr.Expr))
        }
        return result
    }
    
    // 检查嵌套深度
    if re.MaxCap() > 100 {
        result.Warnings = append(result.Warnings, 
            "Too many capture groups (>100)")
    }
    
    // 尝试编译
    simplified := re.Simplify()
    _, err = syntax.Compile(simplified)
    if err != nil {
        result.Valid = false
        result.Errors = append(result.Errors, err.Error())
    }
    
    return result
}

func main() {
    patterns := []string{
        `\d+`,
        `(\w+){100}`,
        `[a-z`,
        `(?P<name>\w+)`,
    }
    
    for _, pattern := range patterns {
        result := validatePattern(pattern)
        
        fmt.Printf("Pattern: %s\n", pattern)
        fmt.Printf("  Valid: %v\n", result.Valid)
        
        if len(result.Errors) > 0 {
            fmt.Printf("  Errors: %v\n", result.Errors)
        }
        if len(result.Warnings) > 0 {
            fmt.Printf("  Warnings: %v\n", result.Warnings)
        }
        fmt.Println()
    }
}

运行结果

Pattern: \d+
  Valid: true

Pattern: (\w+){100}
  Valid: true

Pattern: [a-z
  Valid: false
  Errors: [missing closing ] at [a-z]

Pattern: (?P<name>\w+)
  Valid: true

最佳实践

1. 使用 regexp 包而非 syntax 包

// ✅ 推荐:使用 regexp 包
import "regexp"

re := regexp.MustCompile(`\d+`)
matched := re.MatchString("123")

// ❌ 不推荐:直接使用 syntax 包(除非必要)
import "regexp/syntax"

re, _ := syntax.Parse(`\d+`, syntax.Perl)
prog, _ := syntax.Compile(re.Simplify())

2. 始终检查错误

// ✅ 推荐
re, err := syntax.Parse(pattern, syntax.Perl)
if err != nil {
    if syntaxErr, ok := err.(*syntax.Error); ok {
        log.Printf("Parse error: %s", syntaxErr.Code)
    }
    return
}

// ❌ 不推荐
re, _ := syntax.Parse(pattern, syntax.Perl)  // 忽略错误

3. 在编译前简化

// ✅ 推荐
re, _ := syntax.Parse(pattern, syntax.Perl)
simplified := re.Simplify()
prog, _ := syntax.Compile(simplified)

// ❌ 不推荐
re, _ := syntax.Parse(pattern, syntax.Perl)
prog, _ := syntax.Compile(re)  // 未简化

4. 使用合适的 Flags

// 不区分大小写
re, _ := syntax.Parse(`hello`, syntax.FoldCase)

// Perl 风格(推荐)
re, _ := syntax.Parse(`\d+`, syntax.Perl)

// POSIX 风格
re, _ := syntax.Parse(`[0-9]+`, syntax.POSIX)

与其他包配合

regexp 包

package main

import (
    "fmt"
    "regexp"
    "regexp/syntax"
)

func main() {
    // 使用 syntax 包分析
    re, _ := syntax.Parse(`(?P<name>\w+)`, syntax.Perl)
    fmt.Println("CapNames:", re.CapNames())
    
    // 使用 regexp 包匹配
    re2 := regexp.MustCompile(`(?P<name>\w+)`)
    match := re2.FindStringSubmatch("hello")
    fmt.Println("Match:", match)
}

strings 包

package main

import (
    "fmt"
    "regexp/syntax"
    "strings"
)

func main() {
    pattern := `\d+`
    
    // 解析并简化
    re, _ := syntax.Parse(pattern, syntax.Perl)
    simplified := re.Simplify()
    
    fmt.Printf("Original: %s\n", pattern)
    fmt.Printf("Simplified: %s\n", simplified.String())
    fmt.Printf("Equal: %v\n", strings.EqualFold(pattern, simplified.String()))
}

快速参考

函数

函数参数返回值说明
EmptyOpContextr1, r2 runeEmptyOp返回零宽度断言
IsWordCharr runebool检查是否为单词字符

类型

类型说明
EmptyOp零宽度断言
Error解析错误
ErrorCode错误代码
Flags解析 flags
Inst指令
InstOp指令操作码
Op运算符
Prog编译后的程序
Regexp语法树节点

Regexp 方法

方法返回值说明
CapNames[]string捕获组名称
Equalbool比较结构
MaxCapint最大捕获索引
Simplify*Regexp简化
Stringstring字符串表示

Prog 方法

方法返回值说明
Prefixstring, bool字面前缀
StartCondEmptyOp起始条件
Stringstring字符串表示

Flags 常量

Flag说明
FoldCase不区分大小写
Literal字面解释
ClassNL字符类匹配换行
DotNL. 匹配换行
OneLine^ 和 $ 只匹配文本首尾
NonGreedy非贪婪重复
PerlX允许 Perl 扩展
UnicodeGroups允许 Unicode 字符类
PerlPerl 风格
POSIXPOSIX 风格

ErrorCode 常量

错误代码说明
ErrMissingBracket缺少 ]
ErrMissingParen缺少 )
ErrInvalidEscape无效转义
ErrInvalidUTF8无效 UTF-8
ErrInvalidRepeatOp无效重复操作符
ErrNestingDepth嵌套过深
ErrLarge表达式太大

注意事项

1. 低级包

regexp/syntax 是低级包,大多数情况下应该使用 regexp 包。

// ✅ 推荐:使用 regexp
re := regexp.MustCompile(`\d+`)

// ❌ 不推荐:直接使用 syntax(除非需要)
re, _ := syntax.Parse(`\d+`, syntax.Perl)

2. 简化后编译

在编译前应该先简化正则表达式。

// ✅ 推荐
re, _ := syntax.Parse(pattern, syntax.Perl)
simplified := re.Simplify()
prog, _ := syntax.Compile(simplified)

3. 错误处理

解析错误返回 *syntax.Error 类型。

re, err := syntax.Parse(pattern, syntax.Perl)
if err != nil {
    if syntaxErr, ok := err.(*syntax.Error); ok {
        log.Printf("Error code: %s", syntaxErr.Code)
    }
}

4. 性能考虑

  • 解析和编译是昂贵的操作,应该缓存结果
  • Simplify 可以提高执行性能
  • 避免在循环中重复解析相同的模式

5. 限制

  • 重复计数不能超过 1000
  • 嵌套深度有限制
  • 表达式大小有限制

总结

regexp/syntax 包提供了正则表达式的底层解析和编译功能。

核心要点

  1. 这是低级包,大多数情况使用 regexp 包即可
  2. 解析后应该先 Simplify 再 Compile
  3. 始终检查解析和编译错误
  4. 使用合适的 Flags 控制解析行为
  5. 缓存解析结果以提高性能

主要用途

  • 分析正则表达式结构
  • 自定义正则引擎
  • 正则表达式优化工具
  • 正则表达式可视化工具