Source File
regexp.go
Belonging Package
regexp/syntax
package syntax
import (
)
type Regexp struct {
Op Op // operator
Flags Flags
Sub []*Regexp // subexpressions, if any
Sub0 [1]*Regexp // storage for short Sub
Rune []rune // matched runes, for OpLiteral, OpCharClass
Rune0 [2]rune // storage for short Rune
Min, Max int // min, max for OpRepeat
Cap int // capturing index, for OpCapture
Name string // capturing name, for OpCapture
}
const (
OpNoMatch Op = 1 + iota // matches no strings
OpEmptyMatch // matches empty string
OpLiteral // matches Runes sequence
OpCharClass // matches Runes interpreted as range pair list
OpAnyCharNotNL // matches any character except newline
OpAnyChar // matches any character
OpBeginLine // matches empty string at beginning of line
OpEndLine // matches empty string at end of line
OpBeginText // matches empty string at beginning of text
OpEndText // matches empty string at end of text
OpWordBoundary // matches word boundary `\b`
OpNoWordBoundary // matches word non-boundary `\B`
OpCapture // capturing subexpression with index Cap, optional name Name
OpStar // matches Sub[0] zero or more times
OpPlus // matches Sub[0] one or more times
OpQuest // matches Sub[0] zero or one times
OpRepeat // matches Sub[0] at least Min times, at most Max (Max == -1 is no limit)
OpConcat // matches concatenation of Subs
OpAlternate // matches alternation of Subs
)
const opPseudo Op = 128 // where pseudo-ops start
if .Flags&WasDollar != .Flags&WasDollar {
return false
}
case OpLiteral, OpCharClass:
if len(.Rune) != len(.Rune) {
return false
}
for , := range .Rune {
if != .Rune[] {
return false
}
}
case OpAlternate, OpConcat:
if len(.Sub) != len(.Sub) {
return false
}
for , := range .Sub {
if !.(.Sub[]) {
return false
}
}
case OpStar, OpPlus, OpQuest:
if .Flags&NonGreedy != .Flags&NonGreedy || !.Sub[0].(.Sub[0]) {
return false
}
case OpRepeat:
if .Flags&NonGreedy != .Flags&NonGreedy || .Min != .Min || .Max != .Max || !.Sub[0].(.Sub[0]) {
return false
}
case OpCapture:
if .Cap != .Cap || .Name != .Name || !.Sub[0].(.Sub[0]) {
return false
}
}
return true
}
func ( *strings.Builder, *Regexp) {
switch .Op {
default:
.WriteString("<invalid op" + strconv.Itoa(int(.Op)) + ">")
case OpNoMatch:
.WriteString(`[^\x00-\x{10FFFF}]`)
case OpEmptyMatch:
.WriteString(`(?:)`)
case OpLiteral:
if .Flags&FoldCase != 0 {
.WriteString(`(?i:`)
}
for , := range .Rune {
escape(, , false)
}
if .Flags&FoldCase != 0 {
.WriteString(`)`)
}
case OpCharClass:
if len(.Rune)%2 != 0 {
.WriteString(`[invalid char class]`)
break
}
.WriteRune('[')
if len(.Rune) == 0 {
.WriteString(`^\x00-\x{10FFFF}`)
.WriteRune('^')
for := 1; < len(.Rune)-1; += 2 {
, := .Rune[]+1, .Rune[+1]-1
escape(, , == '-')
if != {
.WriteRune('-')
escape(, , == '-')
}
}
} else {
for := 0; < len(.Rune); += 2 {
, := .Rune[], .Rune[+1]
escape(, , == '-')
if != {
.WriteRune('-')
escape(, , == '-')
}
}
}
.WriteRune(']')
case OpAnyCharNotNL:
.WriteString(`(?-s:.)`)
case OpAnyChar:
.WriteString(`(?s:.)`)
case OpBeginLine:
.WriteString(`(?m:^)`)
case OpEndLine:
.WriteString(`(?m:$)`)
case OpBeginText:
.WriteString(`\A`)
case OpEndText:
if .Flags&WasDollar != 0 {
.WriteString(`(?-m:$)`)
} else {
.WriteString(`\z`)
}
case OpWordBoundary:
.WriteString(`\b`)
case OpNoWordBoundary:
.WriteString(`\B`)
case OpCapture:
if .Name != "" {
.WriteString(`(?P<`)
.WriteString(.Name)
.WriteRune('>')
} else {
.WriteRune('(')
}
if .Sub[0].Op != OpEmptyMatch {
(, .Sub[0])
}
.WriteRune(')')
case OpStar, OpPlus, OpQuest, OpRepeat:
if := .Sub[0]; .Op > OpCapture || .Op == OpLiteral && len(.Rune) > 1 {
.WriteString(`(?:`)
(, )
.WriteString(`)`)
} else {
(, )
}
switch .Op {
case OpStar:
.WriteRune('*')
case OpPlus:
.WriteRune('+')
case OpQuest:
.WriteRune('?')
case OpRepeat:
.WriteRune('{')
.WriteString(strconv.Itoa(.Min))
if .Max != .Min {
.WriteRune(',')
if .Max >= 0 {
.WriteString(strconv.Itoa(.Max))
}
}
.WriteRune('}')
}
if .Flags&NonGreedy != 0 {
.WriteRune('?')
}
case OpConcat:
for , := range .Sub {
if .Op == OpAlternate {
.WriteString(`(?:`)
(, )
.WriteString(`)`)
} else {
(, )
}
}
case OpAlternate:
for , := range .Sub {
if > 0 {
.WriteRune('|')
}
(, )
}
}
}
func ( *Regexp) () string {
var strings.Builder
writeRegexp(&, )
return .String()
}
const meta = `\.+*?()|[]{}^$`
func ( *strings.Builder, rune, bool) {
if unicode.IsPrint() {
if strings.ContainsRune(meta, ) || {
.WriteRune('\\')
}
.WriteRune()
return
}
switch {
case '\a':
.WriteString(`\a`)
case '\f':
.WriteString(`\f`)
case '\n':
.WriteString(`\n`)
case '\r':
.WriteString(`\r`)
case '\t':
.WriteString(`\t`)
case '\v':
.WriteString(`\v`)
default:
if < 0x100 {
.WriteString(`\x`)
:= strconv.FormatInt(int64(), 16)
if len() == 1 {
.WriteRune('0')
}
.WriteString()
break
}
.WriteString(`\x{`)
.WriteString(strconv.FormatInt(int64(), 16))
.WriteString(`}`)
}
}
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |