mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1489 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			1489 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			Go
		
	
	
	
| // Copyright 2010 The Go Authors. All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| // Package regexp implements a simple regular expression library.
 | |
| //
 | |
| // The syntax of the regular expressions accepted is:
 | |
| //
 | |
| //	regexp:
 | |
| //		concatenation { '|' concatenation }
 | |
| //	concatenation:
 | |
| //		{ closure }
 | |
| //	closure:
 | |
| //		term [ '*' | '+' | '?' ]
 | |
| //	term:
 | |
| //		'^'
 | |
| //		'$'
 | |
| //		'.'
 | |
| //		character
 | |
| //		'[' [ '^' ] { character-range } ']'
 | |
| //		'(' regexp ')'
 | |
| //	character-range:
 | |
| //		character [ '-' character ]
 | |
| //
 | |
| // All characters are UTF-8-encoded code points.  Backslashes escape special
 | |
| // characters, including inside character classes.  The standard Go character
 | |
| // escapes are also recognized: \a \b \f \n \r \t \v.
 | |
| //
 | |
| // There are 16 methods of Regexp that match a regular expression and identify
 | |
| // the matched text.  Their names are matched by this regular expression:
 | |
| //
 | |
| //	Find(All)?(String)?(Submatch)?(Index)?
 | |
| //
 | |
| // If 'All' is present, the routine matches successive non-overlapping
 | |
| // matches of the entire expression.  Empty matches abutting a preceding
 | |
| // match are ignored.  The return value is a slice containing the successive
 | |
| // return values of the corresponding non-'All' routine.  These routines take
 | |
| // an extra integer argument, n; if n >= 0, the function returns at most n
 | |
| // matches/submatches.
 | |
| //
 | |
| // If 'String' is present, the argument is a string; otherwise it is a slice
 | |
| // of bytes; return values are adjusted as appropriate.
 | |
| //
 | |
| // If 'Submatch' is present, the return value is a slice identifying the
 | |
| // successive submatches of the expression.  Submatches are matches of
 | |
| // parenthesized subexpressions within the regular expression, numbered from
 | |
| // left to right in order of opening parenthesis.  Submatch 0 is the match of
 | |
| // the entire expression, submatch 1 the match of the first parenthesized
 | |
| // subexpression, and so on.
 | |
| //
 | |
| // If 'Index' is present, matches and submatches are identified by byte index
 | |
| // pairs within the input string: result[2*n:2*n+1] identifies the indexes of
 | |
| // the nth submatch.  The pair for n==0 identifies the match of the entire
 | |
| // expression.  If 'Index' is not present, the match is identified by the
 | |
| // text of the match/submatch.  If an index is negative, it means that
 | |
| // subexpression did not match any string in the input.
 | |
| //
 | |
| // There is also a subset of the methods that can be applied to text read
 | |
| // from a RuneReader:
 | |
| //
 | |
| //	MatchReader, FindReaderIndex, FindReaderSubmatchIndex
 | |
| //
 | |
| // This set may grow.  Note that regular expression matches may need to
 | |
| // examine text beyond the text returned by a match, so the methods that
 | |
| // match text from a RuneReader may read arbitrarily far into the input
 | |
| // before returning.
 | |
| //
 | |
| // (There are a few other methods that do not match this pattern.)
 | |
| //
 | |
| package regexp
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"io"
 | |
| 	"strings"
 | |
| 	"unicode/utf8"
 | |
| )
 | |
| 
 | |
| var debug = false
 | |
| 
 | |
| // Error is the local type for a parsing error.
 | |
| type Error string
 | |
| 
 | |
| func (e Error) Error() string {
 | |
| 	return string(e)
 | |
| }
 | |
| 
 | |
| // Error codes returned by failures to parse an expression.
 | |
| var (
 | |
| 	ErrInternal            = Error("regexp: internal error")
 | |
| 	ErrUnmatchedLpar       = Error("regexp: unmatched '('")
 | |
| 	ErrUnmatchedRpar       = Error("regexp: unmatched ')'")
 | |
| 	ErrUnmatchedLbkt       = Error("regexp: unmatched '['")
 | |
| 	ErrUnmatchedRbkt       = Error("regexp: unmatched ']'")
 | |
| 	ErrBadRange            = Error("regexp: bad range in character class")
 | |
| 	ErrExtraneousBackslash = Error("regexp: extraneous backslash")
 | |
| 	ErrBadClosure          = Error("regexp: repeated closure (**, ++, etc.)")
 | |
| 	ErrBareClosure         = Error("regexp: closure applies to nothing")
 | |
| 	ErrBadBackslash        = Error("regexp: illegal backslash escape")
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	iStart     = iota // beginning of program
 | |
| 	iEnd              // end of program: success
 | |
| 	iBOT              // '^' beginning of text
 | |
| 	iEOT              // '$' end of text
 | |
| 	iChar             // 'a' regular character
 | |
| 	iCharClass        // [a-z] character class
 | |
| 	iAny              // '.' any character including newline
 | |
| 	iNotNL            // [^\n] special case: any character but newline
 | |
| 	iBra              // '(' parenthesized expression: 2*braNum for left, 2*braNum+1 for right
 | |
| 	iAlt              // '|' alternation
 | |
| 	iNop              // do nothing; makes it easy to link without patching
 | |
| )
 | |
| 
 | |
| // An instruction executed by the NFA
 | |
| type instr struct {
 | |
| 	kind  int    // the type of this instruction: iChar, iAny, etc.
 | |
| 	index int    // used only in debugging; could be eliminated
 | |
| 	next  *instr // the instruction to execute after this one
 | |
| 	// Special fields valid only for some items.
 | |
| 	char   rune       // iChar
 | |
| 	braNum int        // iBra, iEbra
 | |
| 	cclass *charClass // iCharClass
 | |
| 	left   *instr     // iAlt, other branch
 | |
| }
 | |
| 
 | |
| func (i *instr) print() {
 | |
| 	switch i.kind {
 | |
| 	case iStart:
 | |
| 		print("start")
 | |
| 	case iEnd:
 | |
| 		print("end")
 | |
| 	case iBOT:
 | |
| 		print("bot")
 | |
| 	case iEOT:
 | |
| 		print("eot")
 | |
| 	case iChar:
 | |
| 		print("char ", string(i.char))
 | |
| 	case iCharClass:
 | |
| 		i.cclass.print()
 | |
| 	case iAny:
 | |
| 		print("any")
 | |
| 	case iNotNL:
 | |
| 		print("notnl")
 | |
| 	case iBra:
 | |
| 		if i.braNum&1 == 0 {
 | |
| 			print("bra", i.braNum/2)
 | |
| 		} else {
 | |
| 			print("ebra", i.braNum/2)
 | |
| 		}
 | |
| 	case iAlt:
 | |
| 		print("alt(", i.left.index, ")")
 | |
| 	case iNop:
 | |
| 		print("nop")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Regexp is the representation of a compiled regular expression.
 | |
| // The public interface is entirely through methods.
 | |
| // A Regexp is safe for concurrent use by multiple goroutines.
 | |
| type Regexp struct {
 | |
| 	expr        string // the original expression
 | |
| 	prefix      string // initial plain text string
 | |
| 	prefixBytes []byte // initial plain text bytes
 | |
| 	inst        []*instr
 | |
| 	start       *instr // first instruction of machine
 | |
| 	prefixStart *instr // where to start if there is a prefix
 | |
| 	nbra        int    // number of brackets in expression, for subexpressions
 | |
| }
 | |
| 
 | |
| type charClass struct {
 | |
| 	negate bool // is character class negated? ([^a-z])
 | |
| 	// slice of int, stored pairwise: [a-z] is (a,z); x is (x,x):
 | |
| 	ranges     []rune
 | |
| 	cmin, cmax rune
 | |
| }
 | |
| 
 | |
| func (cclass *charClass) print() {
 | |
| 	print("charclass")
 | |
| 	if cclass.negate {
 | |
| 		print(" (negated)")
 | |
| 	}
 | |
| 	for i := 0; i < len(cclass.ranges); i += 2 {
 | |
| 		l := cclass.ranges[i]
 | |
| 		r := cclass.ranges[i+1]
 | |
| 		if l == r {
 | |
| 			print(" [", string(l), "]")
 | |
| 		} else {
 | |
| 			print(" [", string(l), "-", string(r), "]")
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (cclass *charClass) addRange(a, b rune) {
 | |
| 	// range is a through b inclusive
 | |
| 	cclass.ranges = append(cclass.ranges, a, b)
 | |
| 	if a < cclass.cmin {
 | |
| 		cclass.cmin = a
 | |
| 	}
 | |
| 	if b > cclass.cmax {
 | |
| 		cclass.cmax = b
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (cclass *charClass) matches(c rune) bool {
 | |
| 	if c < cclass.cmin || c > cclass.cmax {
 | |
| 		return cclass.negate
 | |
| 	}
 | |
| 	ranges := cclass.ranges
 | |
| 	for i := 0; i < len(ranges); i = i + 2 {
 | |
| 		if ranges[i] <= c && c <= ranges[i+1] {
 | |
| 			return !cclass.negate
 | |
| 		}
 | |
| 	}
 | |
| 	return cclass.negate
 | |
| }
 | |
| 
 | |
| func newCharClass() *instr {
 | |
| 	i := &instr{kind: iCharClass}
 | |
| 	i.cclass = new(charClass)
 | |
| 	i.cclass.ranges = make([]rune, 0, 4)
 | |
| 	i.cclass.cmin = 0x10FFFF + 1 // MaxRune + 1
 | |
| 	i.cclass.cmax = -1
 | |
| 	return i
 | |
| }
 | |
| 
 | |
| func (re *Regexp) add(i *instr) *instr {
 | |
| 	i.index = len(re.inst)
 | |
| 	re.inst = append(re.inst, i)
 | |
| 	return i
 | |
| }
 | |
| 
 | |
| type parser struct {
 | |
| 	re    *Regexp
 | |
| 	nlpar int // number of unclosed lpars
 | |
| 	pos   int
 | |
| 	ch    rune
 | |
| }
 | |
| 
 | |
| func (p *parser) error(err Error) {
 | |
| 	panic(err)
 | |
| }
 | |
| 
 | |
| const endOfText = -1
 | |
| 
 | |
| func (p *parser) c() rune { return p.ch }
 | |
| 
 | |
| func (p *parser) nextc() rune {
 | |
| 	if p.pos >= len(p.re.expr) {
 | |
| 		p.ch = endOfText
 | |
| 	} else {
 | |
| 		c, w := utf8.DecodeRuneInString(p.re.expr[p.pos:])
 | |
| 		p.ch = c
 | |
| 		p.pos += w
 | |
| 	}
 | |
| 	return p.ch
 | |
| }
 | |
| 
 | |
| func newParser(re *Regexp) *parser {
 | |
| 	p := new(parser)
 | |
| 	p.re = re
 | |
| 	p.nextc() // load p.ch
 | |
| 	return p
 | |
| }
 | |
| 
 | |
| func special(c rune) bool {
 | |
| 	for _, r := range `\.+*?()|[]^$` {
 | |
| 		if c == r {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func ispunct(c rune) bool {
 | |
| 	for _, r := range "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" {
 | |
| 		if c == r {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| var escapes = []byte("abfnrtv")
 | |
| var escaped = []byte("\a\b\f\n\r\t\v")
 | |
| 
 | |
| func escape(c rune) int {
 | |
| 	for i, b := range escapes {
 | |
| 		if rune(b) == c {
 | |
| 			return i
 | |
| 		}
 | |
| 	}
 | |
| 	return -1
 | |
| }
 | |
| 
 | |
| func (p *parser) checkBackslash() rune {
 | |
| 	c := p.c()
 | |
| 	if c == '\\' {
 | |
| 		c = p.nextc()
 | |
| 		switch {
 | |
| 		case c == endOfText:
 | |
| 			p.error(ErrExtraneousBackslash)
 | |
| 		case ispunct(c):
 | |
| 			// c is as delivered
 | |
| 		case escape(c) >= 0:
 | |
| 			c = rune(escaped[escape(c)])
 | |
| 		default:
 | |
| 			p.error(ErrBadBackslash)
 | |
| 		}
 | |
| 	}
 | |
| 	return c
 | |
| }
 | |
| 
 | |
| func (p *parser) charClass() *instr {
 | |
| 	i := newCharClass()
 | |
| 	cc := i.cclass
 | |
| 	if p.c() == '^' {
 | |
| 		cc.negate = true
 | |
| 		p.nextc()
 | |
| 	}
 | |
| 	left := rune(-1)
 | |
| 	for {
 | |
| 		switch c := p.c(); c {
 | |
| 		case ']', endOfText:
 | |
| 			if left >= 0 {
 | |
| 				p.error(ErrBadRange)
 | |
| 			}
 | |
| 			// Is it [^\n]?
 | |
| 			if cc.negate && len(cc.ranges) == 2 &&
 | |
| 				cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
 | |
| 				nl := &instr{kind: iNotNL}
 | |
| 				p.re.add(nl)
 | |
| 				return nl
 | |
| 			}
 | |
| 			// Special common case: "[a]" -> "a"
 | |
| 			if !cc.negate && len(cc.ranges) == 2 && cc.ranges[0] == cc.ranges[1] {
 | |
| 				c := &instr{kind: iChar, char: cc.ranges[0]}
 | |
| 				p.re.add(c)
 | |
| 				return c
 | |
| 			}
 | |
| 			p.re.add(i)
 | |
| 			return i
 | |
| 		case '-': // do this before backslash processing
 | |
| 			p.error(ErrBadRange)
 | |
| 		default:
 | |
| 			c = p.checkBackslash()
 | |
| 			p.nextc()
 | |
| 			switch {
 | |
| 			case left < 0: // first of pair
 | |
| 				if p.c() == '-' { // range
 | |
| 					p.nextc()
 | |
| 					left = c
 | |
| 				} else { // single char
 | |
| 					cc.addRange(c, c)
 | |
| 				}
 | |
| 			case left <= c: // second of pair
 | |
| 				cc.addRange(left, c)
 | |
| 				left = -1
 | |
| 			default:
 | |
| 				p.error(ErrBadRange)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	panic("unreachable")
 | |
| }
 | |
| 
 | |
| func (p *parser) term() (start, end *instr) {
 | |
| 	switch c := p.c(); c {
 | |
| 	case '|', endOfText:
 | |
| 		return nil, nil
 | |
| 	case '*', '+', '?':
 | |
| 		p.error(ErrBareClosure)
 | |
| 	case ')':
 | |
| 		if p.nlpar == 0 {
 | |
| 			p.error(ErrUnmatchedRpar)
 | |
| 		}
 | |
| 		return nil, nil
 | |
| 	case ']':
 | |
| 		p.error(ErrUnmatchedRbkt)
 | |
| 	case '^':
 | |
| 		p.nextc()
 | |
| 		start = p.re.add(&instr{kind: iBOT})
 | |
| 		return start, start
 | |
| 	case '$':
 | |
| 		p.nextc()
 | |
| 		start = p.re.add(&instr{kind: iEOT})
 | |
| 		return start, start
 | |
| 	case '.':
 | |
| 		p.nextc()
 | |
| 		start = p.re.add(&instr{kind: iAny})
 | |
| 		return start, start
 | |
| 	case '[':
 | |
| 		p.nextc()
 | |
| 		start = p.charClass()
 | |
| 		if p.c() != ']' {
 | |
| 			p.error(ErrUnmatchedLbkt)
 | |
| 		}
 | |
| 		p.nextc()
 | |
| 		return start, start
 | |
| 	case '(':
 | |
| 		p.nextc()
 | |
| 		p.nlpar++
 | |
| 		p.re.nbra++ // increment first so first subexpr is \1
 | |
| 		nbra := p.re.nbra
 | |
| 		start, end = p.regexp()
 | |
| 		if p.c() != ')' {
 | |
| 			p.error(ErrUnmatchedLpar)
 | |
| 		}
 | |
| 		p.nlpar--
 | |
| 		p.nextc()
 | |
| 		bra := &instr{kind: iBra, braNum: 2 * nbra}
 | |
| 		p.re.add(bra)
 | |
| 		ebra := &instr{kind: iBra, braNum: 2*nbra + 1}
 | |
| 		p.re.add(ebra)
 | |
| 		if start == nil {
 | |
| 			if end == nil {
 | |
| 				p.error(ErrInternal)
 | |
| 				return
 | |
| 			}
 | |
| 			start = ebra
 | |
| 		} else {
 | |
| 			end.next = ebra
 | |
| 		}
 | |
| 		bra.next = start
 | |
| 		return bra, ebra
 | |
| 	default:
 | |
| 		c = p.checkBackslash()
 | |
| 		p.nextc()
 | |
| 		start = &instr{kind: iChar, char: c}
 | |
| 		p.re.add(start)
 | |
| 		return start, start
 | |
| 	}
 | |
| 	panic("unreachable")
 | |
| }
 | |
| 
 | |
| func (p *parser) closure() (start, end *instr) {
 | |
| 	start, end = p.term()
 | |
| 	if start == nil {
 | |
| 		return
 | |
| 	}
 | |
| 	switch p.c() {
 | |
| 	case '*':
 | |
| 		// (start,end)*:
 | |
| 		alt := &instr{kind: iAlt}
 | |
| 		p.re.add(alt)
 | |
| 		end.next = alt   // after end, do alt
 | |
| 		alt.left = start // alternate brach: return to start
 | |
| 		start = alt      // alt becomes new (start, end)
 | |
| 		end = alt
 | |
| 	case '+':
 | |
| 		// (start,end)+:
 | |
| 		alt := &instr{kind: iAlt}
 | |
| 		p.re.add(alt)
 | |
| 		end.next = alt   // after end, do alt
 | |
| 		alt.left = start // alternate brach: return to start
 | |
| 		end = alt        // start is unchanged; end is alt
 | |
| 	case '?':
 | |
| 		// (start,end)?:
 | |
| 		alt := &instr{kind: iAlt}
 | |
| 		p.re.add(alt)
 | |
| 		nop := &instr{kind: iNop}
 | |
| 		p.re.add(nop)
 | |
| 		alt.left = start // alternate branch is start
 | |
| 		alt.next = nop   // follow on to nop
 | |
| 		end.next = nop   // after end, go to nop
 | |
| 		start = alt      // start is now alt
 | |
| 		end = nop        // end is nop pointed to by both branches
 | |
| 	default:
 | |
| 		return
 | |
| 	}
 | |
| 	switch p.nextc() {
 | |
| 	case '*', '+', '?':
 | |
| 		p.error(ErrBadClosure)
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (p *parser) concatenation() (start, end *instr) {
 | |
| 	for {
 | |
| 		nstart, nend := p.closure()
 | |
| 		switch {
 | |
| 		case nstart == nil: // end of this concatenation
 | |
| 			if start == nil { // this is the empty string
 | |
| 				nop := p.re.add(&instr{kind: iNop})
 | |
| 				return nop, nop
 | |
| 			}
 | |
| 			return
 | |
| 		case start == nil: // this is first element of concatenation
 | |
| 			start, end = nstart, nend
 | |
| 		default:
 | |
| 			end.next = nstart
 | |
| 			end = nend
 | |
| 		}
 | |
| 	}
 | |
| 	panic("unreachable")
 | |
| }
 | |
| 
 | |
| func (p *parser) regexp() (start, end *instr) {
 | |
| 	start, end = p.concatenation()
 | |
| 	for {
 | |
| 		switch p.c() {
 | |
| 		default:
 | |
| 			return
 | |
| 		case '|':
 | |
| 			p.nextc()
 | |
| 			nstart, nend := p.concatenation()
 | |
| 			alt := &instr{kind: iAlt}
 | |
| 			p.re.add(alt)
 | |
| 			alt.left = start
 | |
| 			alt.next = nstart
 | |
| 			nop := &instr{kind: iNop}
 | |
| 			p.re.add(nop)
 | |
| 			end.next = nop
 | |
| 			nend.next = nop
 | |
| 			start, end = alt, nop
 | |
| 		}
 | |
| 	}
 | |
| 	panic("unreachable")
 | |
| }
 | |
| 
 | |
| func unNop(i *instr) *instr {
 | |
| 	for i.kind == iNop {
 | |
| 		i = i.next
 | |
| 	}
 | |
| 	return i
 | |
| }
 | |
| 
 | |
| func (re *Regexp) eliminateNops() {
 | |
| 	for _, inst := range re.inst {
 | |
| 		if inst.kind == iEnd {
 | |
| 			continue
 | |
| 		}
 | |
| 		inst.next = unNop(inst.next)
 | |
| 		if inst.kind == iAlt {
 | |
| 			inst.left = unNop(inst.left)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (re *Regexp) dump() {
 | |
| 	print("prefix <", re.prefix, ">\n")
 | |
| 	for _, inst := range re.inst {
 | |
| 		print(inst.index, ": ")
 | |
| 		inst.print()
 | |
| 		if inst.kind != iEnd {
 | |
| 			print(" -> ", inst.next.index)
 | |
| 		}
 | |
| 		print("\n")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (re *Regexp) doParse() {
 | |
| 	p := newParser(re)
 | |
| 	start := &instr{kind: iStart}
 | |
| 	re.add(start)
 | |
| 	s, e := p.regexp()
 | |
| 	start.next = s
 | |
| 	re.start = start
 | |
| 	e.next = re.add(&instr{kind: iEnd})
 | |
| 
 | |
| 	if debug {
 | |
| 		re.dump()
 | |
| 		println()
 | |
| 	}
 | |
| 
 | |
| 	re.eliminateNops()
 | |
| 	if debug {
 | |
| 		re.dump()
 | |
| 		println()
 | |
| 	}
 | |
| 	re.setPrefix()
 | |
| 	if debug {
 | |
| 		re.dump()
 | |
| 		println()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Extract regular text from the beginning of the pattern,
 | |
| // possibly after a leading iBOT.
 | |
| // That text can be used by doExecute to speed up matching.
 | |
| func (re *Regexp) setPrefix() {
 | |
| 	var b []byte
 | |
| 	var utf = make([]byte, utf8.UTFMax)
 | |
| 	var inst *instr
 | |
| 	// First instruction is start; skip that.  Also skip any initial iBOT.
 | |
| 	inst = re.inst[0].next
 | |
| 	for inst.kind == iBOT {
 | |
| 		inst = inst.next
 | |
| 	}
 | |
| Loop:
 | |
| 	for ; inst.kind != iEnd; inst = inst.next {
 | |
| 		// stop if this is not a char
 | |
| 		if inst.kind != iChar {
 | |
| 			break
 | |
| 		}
 | |
| 		// stop if this char can be followed by a match for an empty string,
 | |
| 		// which includes closures, ^, and $.
 | |
| 		switch inst.next.kind {
 | |
| 		case iBOT, iEOT, iAlt:
 | |
| 			break Loop
 | |
| 		}
 | |
| 		n := utf8.EncodeRune(utf, inst.char)
 | |
| 		b = append(b, utf[0:n]...)
 | |
| 	}
 | |
| 	// point prefixStart instruction to first non-CHAR after prefix
 | |
| 	re.prefixStart = inst
 | |
| 	re.prefixBytes = b
 | |
| 	re.prefix = string(b)
 | |
| }
 | |
| 
 | |
| // String returns the source text used to compile the regular expression.
 | |
| func (re *Regexp) String() string {
 | |
| 	return re.expr
 | |
| }
 | |
| 
 | |
| // Compile parses a regular expression and returns, if successful, a Regexp
 | |
| // object that can be used to match against text.
 | |
| func Compile(str string) (regexp *Regexp, error error) {
 | |
| 	regexp = new(Regexp)
 | |
| 	// doParse will panic if there is a parse error.
 | |
| 	defer func() {
 | |
| 		if e := recover(); e != nil {
 | |
| 			regexp = nil
 | |
| 			error = e.(Error) // Will re-panic if error was not an Error, e.g. nil-pointer exception
 | |
| 		}
 | |
| 	}()
 | |
| 	regexp.expr = str
 | |
| 	regexp.inst = make([]*instr, 0, 10)
 | |
| 	regexp.doParse()
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // MustCompile is like Compile but panics if the expression cannot be parsed.
 | |
| // It simplifies safe initialization of global variables holding compiled regular
 | |
| // expressions.
 | |
| func MustCompile(str string) *Regexp {
 | |
| 	regexp, error := Compile(str)
 | |
| 	if error != nil {
 | |
| 		panic(`regexp: compiling "` + str + `": ` + error.Error())
 | |
| 	}
 | |
| 	return regexp
 | |
| }
 | |
| 
 | |
| // NumSubexp returns the number of parenthesized subexpressions in this Regexp.
 | |
| func (re *Regexp) NumSubexp() int { return re.nbra }
 | |
| 
 | |
| // The match arena allows us to reduce the garbage generated by tossing
 | |
| // match vectors away as we execute.  Matches are ref counted and returned
 | |
| // to a free list when no longer active.  Increases a simple benchmark by 22X.
 | |
| type matchArena struct {
 | |
| 	head  *matchVec
 | |
| 	len   int // length of match vector
 | |
| 	pos   int
 | |
| 	atBOT bool // whether we're at beginning of text
 | |
| 	atEOT bool // whether we're at end of text
 | |
| }
 | |
| 
 | |
| type matchVec struct {
 | |
| 	m    []int // pairs of bracketing submatches. 0th is start,end
 | |
| 	ref  int
 | |
| 	next *matchVec
 | |
| }
 | |
| 
 | |
| func (a *matchArena) new() *matchVec {
 | |
| 	if a.head == nil {
 | |
| 		const N = 10
 | |
| 		block := make([]matchVec, N)
 | |
| 		for i := 0; i < N; i++ {
 | |
| 			b := &block[i]
 | |
| 			b.next = a.head
 | |
| 			a.head = b
 | |
| 		}
 | |
| 	}
 | |
| 	m := a.head
 | |
| 	a.head = m.next
 | |
| 	m.ref = 0
 | |
| 	if m.m == nil {
 | |
| 		m.m = make([]int, a.len)
 | |
| 	}
 | |
| 	return m
 | |
| }
 | |
| 
 | |
| func (a *matchArena) free(m *matchVec) {
 | |
| 	m.ref--
 | |
| 	if m.ref == 0 {
 | |
| 		m.next = a.head
 | |
| 		a.head = m
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (a *matchArena) copy(m *matchVec) *matchVec {
 | |
| 	m1 := a.new()
 | |
| 	copy(m1.m, m.m)
 | |
| 	return m1
 | |
| }
 | |
| 
 | |
| func (a *matchArena) noMatch() *matchVec {
 | |
| 	m := a.new()
 | |
| 	for i := range m.m {
 | |
| 		m.m[i] = -1 // no match seen; catches cases like "a(b)?c" on "ac"
 | |
| 	}
 | |
| 	m.ref = 1
 | |
| 	return m
 | |
| }
 | |
| 
 | |
| type state struct {
 | |
| 	inst     *instr // next instruction to execute
 | |
| 	prefixed bool   // this match began with a fixed prefix
 | |
| 	match    *matchVec
 | |
| }
 | |
| 
 | |
| // Append new state to to-do list.  Leftmost-longest wins so avoid
 | |
| // adding a state that's already active.  The matchVec will be inc-ref'ed
 | |
| // if it is assigned to a state.
 | |
| func (a *matchArena) addState(s []state, inst *instr, prefixed bool, match *matchVec) []state {
 | |
| 	switch inst.kind {
 | |
| 	case iBOT:
 | |
| 		if a.atBOT {
 | |
| 			s = a.addState(s, inst.next, prefixed, match)
 | |
| 		}
 | |
| 		return s
 | |
| 	case iEOT:
 | |
| 		if a.atEOT {
 | |
| 			s = a.addState(s, inst.next, prefixed, match)
 | |
| 		}
 | |
| 		return s
 | |
| 	case iBra:
 | |
| 		match.m[inst.braNum] = a.pos
 | |
| 		s = a.addState(s, inst.next, prefixed, match)
 | |
| 		return s
 | |
| 	}
 | |
| 	l := len(s)
 | |
| 	// States are inserted in order so it's sufficient to see if we have the same
 | |
| 	// instruction; no need to see if existing match is earlier (it is).
 | |
| 	for i := 0; i < l; i++ {
 | |
| 		if s[i].inst == inst {
 | |
| 			return s
 | |
| 		}
 | |
| 	}
 | |
| 	s = append(s, state{inst, prefixed, match})
 | |
| 	match.ref++
 | |
| 	if inst.kind == iAlt {
 | |
| 		s = a.addState(s, inst.left, prefixed, a.copy(match))
 | |
| 		// give other branch a copy of this match vector
 | |
| 		s = a.addState(s, inst.next, prefixed, a.copy(match))
 | |
| 	}
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| // input abstracts different representations of the input text. It provides
 | |
| // one-character lookahead.
 | |
| type input interface {
 | |
| 	step(pos int) (r rune, width int) // advance one rune
 | |
| 	canCheckPrefix() bool             // can we look ahead without losing info?
 | |
| 	hasPrefix(re *Regexp) bool
 | |
| 	index(re *Regexp, pos int) int
 | |
| }
 | |
| 
 | |
| // inputString scans a string.
 | |
| type inputString struct {
 | |
| 	str string
 | |
| }
 | |
| 
 | |
| func newInputString(str string) *inputString {
 | |
| 	return &inputString{str: str}
 | |
| }
 | |
| 
 | |
| func (i *inputString) step(pos int) (rune, int) {
 | |
| 	if pos < len(i.str) {
 | |
| 		return utf8.DecodeRuneInString(i.str[pos:len(i.str)])
 | |
| 	}
 | |
| 	return endOfText, 0
 | |
| }
 | |
| 
 | |
| func (i *inputString) canCheckPrefix() bool {
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| func (i *inputString) hasPrefix(re *Regexp) bool {
 | |
| 	return strings.HasPrefix(i.str, re.prefix)
 | |
| }
 | |
| 
 | |
| func (i *inputString) index(re *Regexp, pos int) int {
 | |
| 	return strings.Index(i.str[pos:], re.prefix)
 | |
| }
 | |
| 
 | |
| // inputBytes scans a byte slice.
 | |
| type inputBytes struct {
 | |
| 	str []byte
 | |
| }
 | |
| 
 | |
| func newInputBytes(str []byte) *inputBytes {
 | |
| 	return &inputBytes{str: str}
 | |
| }
 | |
| 
 | |
| func (i *inputBytes) step(pos int) (rune, int) {
 | |
| 	if pos < len(i.str) {
 | |
| 		return utf8.DecodeRune(i.str[pos:len(i.str)])
 | |
| 	}
 | |
| 	return endOfText, 0
 | |
| }
 | |
| 
 | |
| func (i *inputBytes) canCheckPrefix() bool {
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| func (i *inputBytes) hasPrefix(re *Regexp) bool {
 | |
| 	return bytes.HasPrefix(i.str, re.prefixBytes)
 | |
| }
 | |
| 
 | |
| func (i *inputBytes) index(re *Regexp, pos int) int {
 | |
| 	return bytes.Index(i.str[pos:], re.prefixBytes)
 | |
| }
 | |
| 
 | |
| // inputReader scans a RuneReader.
 | |
| type inputReader struct {
 | |
| 	r     io.RuneReader
 | |
| 	atEOT bool
 | |
| 	pos   int
 | |
| }
 | |
| 
 | |
| func newInputReader(r io.RuneReader) *inputReader {
 | |
| 	return &inputReader{r: r}
 | |
| }
 | |
| 
 | |
| func (i *inputReader) step(pos int) (rune, int) {
 | |
| 	if !i.atEOT && pos != i.pos {
 | |
| 		return endOfText, 0
 | |
| 
 | |
| 	}
 | |
| 	r, w, err := i.r.ReadRune()
 | |
| 	if err != nil {
 | |
| 		i.atEOT = true
 | |
| 		return endOfText, 0
 | |
| 	}
 | |
| 	i.pos += w
 | |
| 	return r, w
 | |
| }
 | |
| 
 | |
| func (i *inputReader) canCheckPrefix() bool {
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func (i *inputReader) hasPrefix(re *Regexp) bool {
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func (i *inputReader) index(re *Regexp, pos int) int {
 | |
| 	return -1
 | |
| }
 | |
| 
 | |
| // Search match starting from pos bytes into the input.
 | |
| func (re *Regexp) doExecute(i input, pos int) []int {
 | |
| 	var s [2][]state
 | |
| 	s[0] = make([]state, 0, 10)
 | |
| 	s[1] = make([]state, 0, 10)
 | |
| 	in, out := 0, 1
 | |
| 	var final state
 | |
| 	found := false
 | |
| 	anchored := re.inst[0].next.kind == iBOT
 | |
| 	if anchored && pos > 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	// fast check for initial plain substring
 | |
| 	if i.canCheckPrefix() && re.prefix != "" {
 | |
| 		advance := 0
 | |
| 		if anchored {
 | |
| 			if !i.hasPrefix(re) {
 | |
| 				return nil
 | |
| 			}
 | |
| 		} else {
 | |
| 			advance = i.index(re, pos)
 | |
| 			if advance == -1 {
 | |
| 				return nil
 | |
| 			}
 | |
| 		}
 | |
| 		pos += advance
 | |
| 	}
 | |
| 	// We look one character ahead so we can match $, which checks whether
 | |
| 	// we are at EOT.
 | |
| 	nextChar, nextWidth := i.step(pos)
 | |
| 	arena := &matchArena{
 | |
| 		len:   2 * (re.nbra + 1),
 | |
| 		pos:   pos,
 | |
| 		atBOT: pos == 0,
 | |
| 		atEOT: nextChar == endOfText,
 | |
| 	}
 | |
| 	for c, startPos := rune(0), pos; c != endOfText; {
 | |
| 		if !found && (pos == startPos || !anchored) {
 | |
| 			// prime the pump if we haven't seen a match yet
 | |
| 			match := arena.noMatch()
 | |
| 			match.m[0] = pos
 | |
| 			s[out] = arena.addState(s[out], re.start.next, false, match)
 | |
| 			arena.free(match) // if addState saved it, ref was incremented
 | |
| 		} else if len(s[out]) == 0 {
 | |
| 			// machine has completed
 | |
| 			break
 | |
| 		}
 | |
| 		in, out = out, in // old out state is new in state
 | |
| 		// clear out old state
 | |
| 		old := s[out]
 | |
| 		for _, state := range old {
 | |
| 			arena.free(state.match)
 | |
| 		}
 | |
| 		s[out] = old[0:0] // truncate state vector
 | |
| 		c = nextChar
 | |
| 		thisPos := pos
 | |
| 		pos += nextWidth
 | |
| 		nextChar, nextWidth = i.step(pos)
 | |
| 		arena.atEOT = nextChar == endOfText
 | |
| 		arena.atBOT = false
 | |
| 		arena.pos = pos
 | |
| 		for _, st := range s[in] {
 | |
| 			switch st.inst.kind {
 | |
| 			case iBOT:
 | |
| 			case iEOT:
 | |
| 			case iChar:
 | |
| 				if c == st.inst.char {
 | |
| 					s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
 | |
| 				}
 | |
| 			case iCharClass:
 | |
| 				if st.inst.cclass.matches(c) {
 | |
| 					s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
 | |
| 				}
 | |
| 			case iAny:
 | |
| 				if c != endOfText {
 | |
| 					s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
 | |
| 				}
 | |
| 			case iNotNL:
 | |
| 				if c != endOfText && c != '\n' {
 | |
| 					s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
 | |
| 				}
 | |
| 			case iBra:
 | |
| 			case iAlt:
 | |
| 			case iEnd:
 | |
| 				// choose leftmost longest
 | |
| 				if !found || // first
 | |
| 					st.match.m[0] < final.match.m[0] || // leftmost
 | |
| 					(st.match.m[0] == final.match.m[0] && thisPos > final.match.m[1]) { // longest
 | |
| 					if final.match != nil {
 | |
| 						arena.free(final.match)
 | |
| 					}
 | |
| 					final = st
 | |
| 					final.match.ref++
 | |
| 					final.match.m[1] = thisPos
 | |
| 				}
 | |
| 				found = true
 | |
| 			default:
 | |
| 				st.inst.print()
 | |
| 				panic("unknown instruction in execute")
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	if final.match == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	// if match found, back up start of match by width of prefix.
 | |
| 	if final.prefixed && len(final.match.m) > 0 {
 | |
| 		final.match.m[0] -= len(re.prefix)
 | |
| 	}
 | |
| 	return final.match.m
 | |
| }
 | |
| 
 | |
| // LiteralPrefix returns a literal string that must begin any match
 | |
| // of the regular expression re.  It returns the boolean true if the
 | |
| // literal string comprises the entire regular expression.
 | |
| func (re *Regexp) LiteralPrefix() (prefix string, complete bool) {
 | |
| 	c := make([]rune, len(re.inst)-2) // minus start and end.
 | |
| 	// First instruction is start; skip that.
 | |
| 	i := 0
 | |
| 	for inst := re.inst[0].next; inst.kind != iEnd; inst = inst.next {
 | |
| 		// stop if this is not a char
 | |
| 		if inst.kind != iChar {
 | |
| 			return string(c[:i]), false
 | |
| 		}
 | |
| 		c[i] = inst.char
 | |
| 		i++
 | |
| 	}
 | |
| 	return string(c[:i]), true
 | |
| }
 | |
| 
 | |
| // MatchReader returns whether the Regexp matches the text read by the
 | |
| // RuneReader.  The return value is a boolean: true for match, false for no
 | |
| // match.
 | |
| func (re *Regexp) MatchReader(r io.RuneReader) bool {
 | |
| 	return len(re.doExecute(newInputReader(r), 0)) > 0
 | |
| }
 | |
| 
 | |
| // MatchString returns whether the Regexp matches the string s.
 | |
| // The return value is a boolean: true for match, false for no match.
 | |
| func (re *Regexp) MatchString(s string) bool { return len(re.doExecute(newInputString(s), 0)) > 0 }
 | |
| 
 | |
| // Match returns whether the Regexp matches the byte slice b.
 | |
| // The return value is a boolean: true for match, false for no match.
 | |
| func (re *Regexp) Match(b []byte) bool { return len(re.doExecute(newInputBytes(b), 0)) > 0 }
 | |
| 
 | |
| // MatchReader checks whether a textual regular expression matches the text
 | |
| // read by the RuneReader.  More complicated queries need to use Compile and
 | |
| // the full Regexp interface.
 | |
| func MatchReader(pattern string, r io.RuneReader) (matched bool, error error) {
 | |
| 	re, err := Compile(pattern)
 | |
| 	if err != nil {
 | |
| 		return false, err
 | |
| 	}
 | |
| 	return re.MatchReader(r), nil
 | |
| }
 | |
| 
 | |
| // MatchString checks whether a textual regular expression
 | |
| // matches a string.  More complicated queries need
 | |
| // to use Compile and the full Regexp interface.
 | |
| func MatchString(pattern string, s string) (matched bool, error error) {
 | |
| 	re, err := Compile(pattern)
 | |
| 	if err != nil {
 | |
| 		return false, err
 | |
| 	}
 | |
| 	return re.MatchString(s), nil
 | |
| }
 | |
| 
 | |
| // Match checks whether a textual regular expression
 | |
| // matches a byte slice.  More complicated queries need
 | |
| // to use Compile and the full Regexp interface.
 | |
| func Match(pattern string, b []byte) (matched bool, error error) {
 | |
| 	re, err := Compile(pattern)
 | |
| 	if err != nil {
 | |
| 		return false, err
 | |
| 	}
 | |
| 	return re.Match(b), nil
 | |
| }
 | |
| 
 | |
| // ReplaceAllString returns a copy of src in which all matches for the Regexp
 | |
| // have been replaced by repl.  No support is provided for expressions
 | |
| // (e.g. \1 or $1) in the replacement string.
 | |
| func (re *Regexp) ReplaceAllString(src, repl string) string {
 | |
| 	return re.ReplaceAllStringFunc(src, func(string) string { return repl })
 | |
| }
 | |
| 
 | |
| // ReplaceAllStringFunc returns a copy of src in which all matches for the
 | |
| // Regexp have been replaced by the return value of of function repl (whose
 | |
| // first argument is the matched string).  No support is provided for
 | |
| // expressions (e.g. \1 or $1) in the replacement string.
 | |
| func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string {
 | |
| 	lastMatchEnd := 0 // end position of the most recent match
 | |
| 	searchPos := 0    // position where we next look for a match
 | |
| 	buf := new(bytes.Buffer)
 | |
| 	for searchPos <= len(src) {
 | |
| 		a := re.doExecute(newInputString(src), searchPos)
 | |
| 		if len(a) == 0 {
 | |
| 			break // no more matches
 | |
| 		}
 | |
| 
 | |
| 		// Copy the unmatched characters before this match.
 | |
| 		io.WriteString(buf, src[lastMatchEnd:a[0]])
 | |
| 
 | |
| 		// Now insert a copy of the replacement string, but not for a
 | |
| 		// match of the empty string immediately after another match.
 | |
| 		// (Otherwise, we get double replacement for patterns that
 | |
| 		// match both empty and nonempty strings.)
 | |
| 		if a[1] > lastMatchEnd || a[0] == 0 {
 | |
| 			io.WriteString(buf, repl(src[a[0]:a[1]]))
 | |
| 		}
 | |
| 		lastMatchEnd = a[1]
 | |
| 
 | |
| 		// Advance past this match; always advance at least one character.
 | |
| 		_, width := utf8.DecodeRuneInString(src[searchPos:])
 | |
| 		if searchPos+width > a[1] {
 | |
| 			searchPos += width
 | |
| 		} else if searchPos+1 > a[1] {
 | |
| 			// This clause is only needed at the end of the input
 | |
| 			// string.  In that case, DecodeRuneInString returns width=0.
 | |
| 			searchPos++
 | |
| 		} else {
 | |
| 			searchPos = a[1]
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Copy the unmatched characters after the last match.
 | |
| 	io.WriteString(buf, src[lastMatchEnd:])
 | |
| 
 | |
| 	return buf.String()
 | |
| }
 | |
| 
 | |
| // ReplaceAll returns a copy of src in which all matches for the Regexp
 | |
| // have been replaced by repl.  No support is provided for expressions
 | |
| // (e.g. \1 or $1) in the replacement text.
 | |
| func (re *Regexp) ReplaceAll(src, repl []byte) []byte {
 | |
| 	return re.ReplaceAllFunc(src, func([]byte) []byte { return repl })
 | |
| }
 | |
| 
 | |
| // ReplaceAllFunc returns a copy of src in which all matches for the
 | |
| // Regexp have been replaced by the return value of of function repl (whose
 | |
| // first argument is the matched []byte).  No support is provided for
 | |
| // expressions (e.g. \1 or $1) in the replacement string.
 | |
| func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
 | |
| 	lastMatchEnd := 0 // end position of the most recent match
 | |
| 	searchPos := 0    // position where we next look for a match
 | |
| 	buf := new(bytes.Buffer)
 | |
| 	for searchPos <= len(src) {
 | |
| 		a := re.doExecute(newInputBytes(src), searchPos)
 | |
| 		if len(a) == 0 {
 | |
| 			break // no more matches
 | |
| 		}
 | |
| 
 | |
| 		// Copy the unmatched characters before this match.
 | |
| 		buf.Write(src[lastMatchEnd:a[0]])
 | |
| 
 | |
| 		// Now insert a copy of the replacement string, but not for a
 | |
| 		// match of the empty string immediately after another match.
 | |
| 		// (Otherwise, we get double replacement for patterns that
 | |
| 		// match both empty and nonempty strings.)
 | |
| 		if a[1] > lastMatchEnd || a[0] == 0 {
 | |
| 			buf.Write(repl(src[a[0]:a[1]]))
 | |
| 		}
 | |
| 		lastMatchEnd = a[1]
 | |
| 
 | |
| 		// Advance past this match; always advance at least one character.
 | |
| 		_, width := utf8.DecodeRune(src[searchPos:])
 | |
| 		if searchPos+width > a[1] {
 | |
| 			searchPos += width
 | |
| 		} else if searchPos+1 > a[1] {
 | |
| 			// This clause is only needed at the end of the input
 | |
| 			// string.  In that case, DecodeRuneInString returns width=0.
 | |
| 			searchPos++
 | |
| 		} else {
 | |
| 			searchPos = a[1]
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Copy the unmatched characters after the last match.
 | |
| 	buf.Write(src[lastMatchEnd:])
 | |
| 
 | |
| 	return buf.Bytes()
 | |
| }
 | |
| 
 | |
| // QuoteMeta returns a string that quotes all regular expression metacharacters
 | |
| // inside the argument text; the returned string is a regular expression matching
 | |
| // the literal text.  For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
 | |
| func QuoteMeta(s string) string {
 | |
| 	b := make([]byte, 2*len(s))
 | |
| 
 | |
| 	// A byte loop is correct because all metacharacters are ASCII.
 | |
| 	j := 0
 | |
| 	for i := 0; i < len(s); i++ {
 | |
| 		if special(rune(s[i])) {
 | |
| 			b[j] = '\\'
 | |
| 			j++
 | |
| 		}
 | |
| 		b[j] = s[i]
 | |
| 		j++
 | |
| 	}
 | |
| 	return string(b[0:j])
 | |
| }
 | |
| 
 | |
| // Find matches in slice b if b is non-nil, otherwise find matches in string s.
 | |
| func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
 | |
| 	var end int
 | |
| 	if b == nil {
 | |
| 		end = len(s)
 | |
| 	} else {
 | |
| 		end = len(b)
 | |
| 	}
 | |
| 
 | |
| 	for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; {
 | |
| 		var in input
 | |
| 		if b == nil {
 | |
| 			in = newInputString(s)
 | |
| 		} else {
 | |
| 			in = newInputBytes(b)
 | |
| 		}
 | |
| 		matches := re.doExecute(in, pos)
 | |
| 		if len(matches) == 0 {
 | |
| 			break
 | |
| 		}
 | |
| 
 | |
| 		accept := true
 | |
| 		if matches[1] == pos {
 | |
| 			// We've found an empty match.
 | |
| 			if matches[0] == prevMatchEnd {
 | |
| 				// We don't allow an empty match right
 | |
| 				// after a previous match, so ignore it.
 | |
| 				accept = false
 | |
| 			}
 | |
| 			var width int
 | |
| 			// TODO: use step()
 | |
| 			if b == nil {
 | |
| 				_, width = utf8.DecodeRuneInString(s[pos:end])
 | |
| 			} else {
 | |
| 				_, width = utf8.DecodeRune(b[pos:end])
 | |
| 			}
 | |
| 			if width > 0 {
 | |
| 				pos += width
 | |
| 			} else {
 | |
| 				pos = end + 1
 | |
| 			}
 | |
| 		} else {
 | |
| 			pos = matches[1]
 | |
| 		}
 | |
| 		prevMatchEnd = matches[1]
 | |
| 
 | |
| 		if accept {
 | |
| 			deliver(matches)
 | |
| 			i++
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Find returns a slice holding the text of the leftmost match in b of the regular expression.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) Find(b []byte) []byte {
 | |
| 	a := re.doExecute(newInputBytes(b), 0)
 | |
| 	if a == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return b[a[0]:a[1]]
 | |
| }
 | |
| 
 | |
| // FindIndex returns a two-element slice of integers defining the location of
 | |
| // the leftmost match in b of the regular expression.  The match itself is at
 | |
| // b[loc[0]:loc[1]].
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindIndex(b []byte) (loc []int) {
 | |
| 	a := re.doExecute(newInputBytes(b), 0)
 | |
| 	if a == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return a[0:2]
 | |
| }
 | |
| 
 | |
| // FindString returns a string holding the text of the leftmost match in s of the regular
 | |
| // expression.  If there is no match, the return value is an empty string,
 | |
| // but it will also be empty if the regular expression successfully matches
 | |
| // an empty string.  Use FindStringIndex or FindStringSubmatch if it is
 | |
| // necessary to distinguish these cases.
 | |
| func (re *Regexp) FindString(s string) string {
 | |
| 	a := re.doExecute(newInputString(s), 0)
 | |
| 	if a == nil {
 | |
| 		return ""
 | |
| 	}
 | |
| 	return s[a[0]:a[1]]
 | |
| }
 | |
| 
 | |
| // FindStringIndex returns a two-element slice of integers defining the
 | |
| // location of the leftmost match in s of the regular expression.  The match
 | |
| // itself is at s[loc[0]:loc[1]].
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindStringIndex(s string) []int {
 | |
| 	a := re.doExecute(newInputString(s), 0)
 | |
| 	if a == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return a[0:2]
 | |
| }
 | |
| 
 | |
| // FindReaderIndex returns a two-element slice of integers defining the
 | |
| // location of the leftmost match of the regular expression in text read from
 | |
| // the RuneReader.  The match itself is at s[loc[0]:loc[1]].  A return
 | |
| // value of nil indicates no match.
 | |
| func (re *Regexp) FindReaderIndex(r io.RuneReader) []int {
 | |
| 	a := re.doExecute(newInputReader(r), 0)
 | |
| 	if a == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return a[0:2]
 | |
| }
 | |
| 
 | |
| // FindSubmatch returns a slice of slices holding the text of the leftmost
 | |
| // match of the regular expression in b and the matches, if any, of its
 | |
| // subexpressions, as defined by the 'Submatch' descriptions in the package
 | |
| // comment.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindSubmatch(b []byte) [][]byte {
 | |
| 	a := re.doExecute(newInputBytes(b), 0)
 | |
| 	if a == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	ret := make([][]byte, len(a)/2)
 | |
| 	for i := range ret {
 | |
| 		if a[2*i] >= 0 {
 | |
| 			ret[i] = b[a[2*i]:a[2*i+1]]
 | |
| 		}
 | |
| 	}
 | |
| 	return ret
 | |
| }
 | |
| 
 | |
| // FindSubmatchIndex returns a slice holding the index pairs identifying the
 | |
| // leftmost match of the regular expression in b and the matches, if any, of
 | |
| // its subexpressions, as defined by the 'Submatch' and 'Index' descriptions
 | |
| // in the package comment.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindSubmatchIndex(b []byte) []int {
 | |
| 	return re.doExecute(newInputBytes(b), 0)
 | |
| }
 | |
| 
 | |
| // FindStringSubmatch returns a slice of strings holding the text of the
 | |
| // leftmost match of the regular expression in s and the matches, if any, of
 | |
| // its subexpressions, as defined by the 'Submatch' description in the
 | |
| // package comment.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindStringSubmatch(s string) []string {
 | |
| 	a := re.doExecute(newInputString(s), 0)
 | |
| 	if a == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	ret := make([]string, len(a)/2)
 | |
| 	for i := range ret {
 | |
| 		if a[2*i] >= 0 {
 | |
| 			ret[i] = s[a[2*i]:a[2*i+1]]
 | |
| 		}
 | |
| 	}
 | |
| 	return ret
 | |
| }
 | |
| 
 | |
| // FindStringSubmatchIndex returns a slice holding the index pairs
 | |
| // identifying the leftmost match of the regular expression in s and the
 | |
| // matches, if any, of its subexpressions, as defined by the 'Submatch' and
 | |
| // 'Index' descriptions in the package comment.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindStringSubmatchIndex(s string) []int {
 | |
| 	return re.doExecute(newInputString(s), 0)
 | |
| }
 | |
| 
 | |
| // FindReaderSubmatchIndex returns a slice holding the index pairs
 | |
| // identifying the leftmost match of the regular expression of text read by
 | |
| // the RuneReader, and the matches, if any, of its subexpressions, as defined
 | |
| // by the 'Submatch' and 'Index' descriptions in the package comment.  A
 | |
| // return value of nil indicates no match.
 | |
| func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int {
 | |
| 	return re.doExecute(newInputReader(r), 0)
 | |
| }
 | |
| 
 | |
| const startSize = 10 // The size at which to start a slice in the 'All' routines.
 | |
| 
 | |
| // FindAll is the 'All' version of Find; it returns a slice of all successive
 | |
| // matches of the expression, as defined by the 'All' description in the
 | |
| // package comment.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindAll(b []byte, n int) [][]byte {
 | |
| 	if n < 0 {
 | |
| 		n = len(b) + 1
 | |
| 	}
 | |
| 	result := make([][]byte, 0, startSize)
 | |
| 	re.allMatches("", b, n, func(match []int) {
 | |
| 		result = append(result, b[match[0]:match[1]])
 | |
| 	})
 | |
| 	if len(result) == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // FindAllIndex is the 'All' version of FindIndex; it returns a slice of all
 | |
| // successive matches of the expression, as defined by the 'All' description
 | |
| // in the package comment.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindAllIndex(b []byte, n int) [][]int {
 | |
| 	if n < 0 {
 | |
| 		n = len(b) + 1
 | |
| 	}
 | |
| 	result := make([][]int, 0, startSize)
 | |
| 	re.allMatches("", b, n, func(match []int) {
 | |
| 		result = append(result, match[0:2])
 | |
| 	})
 | |
| 	if len(result) == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // FindAllString is the 'All' version of FindString; it returns a slice of all
 | |
| // successive matches of the expression, as defined by the 'All' description
 | |
| // in the package comment.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindAllString(s string, n int) []string {
 | |
| 	if n < 0 {
 | |
| 		n = len(s) + 1
 | |
| 	}
 | |
| 	result := make([]string, 0, startSize)
 | |
| 	re.allMatches(s, nil, n, func(match []int) {
 | |
| 		result = append(result, s[match[0]:match[1]])
 | |
| 	})
 | |
| 	if len(result) == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // FindAllStringIndex is the 'All' version of FindStringIndex; it returns a
 | |
| // slice of all successive matches of the expression, as defined by the 'All'
 | |
| // description in the package comment.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindAllStringIndex(s string, n int) [][]int {
 | |
| 	if n < 0 {
 | |
| 		n = len(s) + 1
 | |
| 	}
 | |
| 	result := make([][]int, 0, startSize)
 | |
| 	re.allMatches(s, nil, n, func(match []int) {
 | |
| 		result = append(result, match[0:2])
 | |
| 	})
 | |
| 	if len(result) == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // FindAllSubmatch is the 'All' version of FindSubmatch; it returns a slice
 | |
| // of all successive matches of the expression, as defined by the 'All'
 | |
| // description in the package comment.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte {
 | |
| 	if n < 0 {
 | |
| 		n = len(b) + 1
 | |
| 	}
 | |
| 	result := make([][][]byte, 0, startSize)
 | |
| 	re.allMatches("", b, n, func(match []int) {
 | |
| 		slice := make([][]byte, len(match)/2)
 | |
| 		for j := range slice {
 | |
| 			if match[2*j] >= 0 {
 | |
| 				slice[j] = b[match[2*j]:match[2*j+1]]
 | |
| 			}
 | |
| 		}
 | |
| 		result = append(result, slice)
 | |
| 	})
 | |
| 	if len(result) == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // FindAllSubmatchIndex is the 'All' version of FindSubmatchIndex; it returns
 | |
| // a slice of all successive matches of the expression, as defined by the
 | |
| // 'All' description in the package comment.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int {
 | |
| 	if n < 0 {
 | |
| 		n = len(b) + 1
 | |
| 	}
 | |
| 	result := make([][]int, 0, startSize)
 | |
| 	re.allMatches("", b, n, func(match []int) {
 | |
| 		result = append(result, match)
 | |
| 	})
 | |
| 	if len(result) == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // FindAllStringSubmatch is the 'All' version of FindStringSubmatch; it
 | |
| // returns a slice of all successive matches of the expression, as defined by
 | |
| // the 'All' description in the package comment.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string {
 | |
| 	if n < 0 {
 | |
| 		n = len(s) + 1
 | |
| 	}
 | |
| 	result := make([][]string, 0, startSize)
 | |
| 	re.allMatches(s, nil, n, func(match []int) {
 | |
| 		slice := make([]string, len(match)/2)
 | |
| 		for j := range slice {
 | |
| 			if match[2*j] >= 0 {
 | |
| 				slice[j] = s[match[2*j]:match[2*j+1]]
 | |
| 			}
 | |
| 		}
 | |
| 		result = append(result, slice)
 | |
| 	})
 | |
| 	if len(result) == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // FindAllStringSubmatchIndex is the 'All' version of
 | |
| // FindStringSubmatchIndex; it returns a slice of all successive matches of
 | |
| // the expression, as defined by the 'All' description in the package
 | |
| // comment.
 | |
| // A return value of nil indicates no match.
 | |
| func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int {
 | |
| 	if n < 0 {
 | |
| 		n = len(s) + 1
 | |
| 	}
 | |
| 	result := make([][]int, 0, startSize)
 | |
| 	re.allMatches(s, nil, n, func(match []int) {
 | |
| 		result = append(result, match)
 | |
| 	})
 | |
| 	if len(result) == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return result
 | |
| }
 |