Skip to content
Snippets Groups Projects
regexp.go 38.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		}
    		i++
    	}
    
    	// Parse number.
    	num = 0
    	for i := 0; i < len(name); i++ {
    		if name[i] < '0' || '9' < name[i] || num >= 1e8 {
    			num = -1
    			break
    		}
    		num = num*10 + int(name[i]) - '0'
    	}
    	// Disallow leading zeros.
    	if name[0] == '0' && len(name) > 1 {
    		num = -1
    	}
    
    	rest = str[i:]
    	ok = true
    	return
    }
    
    
    // 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.pad(re.doExecute(nil, b, "", 0, re.prog.NumCap, nil))
    
    }
    
    // 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 {
    
    	var dstCap [4]int
    	a := re.doExecute(nil, nil, s, 0, re.prog.NumCap, dstCap[:0])
    
    	if a == nil {
    		return nil
    	}
    
    	ret := make([]string, 1+re.numSubexp)
    
    	for i := range ret {
    
    		if 2*i < len(a) && 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.pad(re.doExecute(nil, nil, s, 0, re.prog.NumCap, nil))
    
    }
    
    // FindReaderSubmatchIndex returns a slice holding the index pairs
    // identifying the leftmost match of the regular expression of text read by
    
    // the [io.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.pad(re.doExecute(r, nil, "", 0, re.prog.NumCap, nil))
    
    const startSize = 10 // The size at which to start a slice in the 'All' routines.
    
    // FindAll is the 'All' version of [Regexp.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
    	}
    
    	re.allMatches("", b, n, func(match []int) {
    
    		if result == nil {
    			result = make([][]byte, 0, startSize)
    		}
    
    		result = append(result, b[match[0]:match[1]:match[1]])
    
    Russ Cox's avatar
    Russ Cox committed
    	return result
    
    // FindAllIndex is the 'All' version of [Regexp.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
    	}
    
    	re.allMatches("", b, n, func(match []int) {
    
    		if result == nil {
    			result = make([][]int, 0, startSize)
    		}
    
    Russ Cox's avatar
    Russ Cox committed
    		result = append(result, match[0:2])
    
    Russ Cox's avatar
    Russ Cox committed
    	return result
    
    // FindAllString is the 'All' version of [Regexp.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
    	}
    
    	re.allMatches(s, nil, n, func(match []int) {
    
    		if result == nil {
    			result = make([]string, 0, startSize)
    		}
    
    Russ Cox's avatar
    Russ Cox committed
    		result = append(result, s[match[0]:match[1]])
    
    Russ Cox's avatar
    Russ Cox committed
    	return result
    
    // FindAllStringIndex is the 'All' version of [Regexp.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
    	}
    
    	re.allMatches(s, nil, n, func(match []int) {
    
    		if result == nil {
    			result = make([][]int, 0, startSize)
    		}
    
    Russ Cox's avatar
    Russ Cox committed
    		result = append(result, match[0:2])
    
    Russ Cox's avatar
    Russ Cox committed
    	return result
    
    // FindAllSubmatch is the 'All' version of [Regexp.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
    	}
    
    	re.allMatches("", b, n, func(match []int) {
    
    		if result == nil {
    			result = make([][][]byte, 0, startSize)
    		}
    
    		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]:match[2*j+1]]
    
    Russ Cox's avatar
    Russ Cox committed
    		result = append(result, slice)
    
    Russ Cox's avatar
    Russ Cox committed
    	return result
    
    // FindAllSubmatchIndex is the 'All' version of [Regexp.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
    	}
    
    	re.allMatches("", b, n, func(match []int) {
    
    		if result == nil {
    			result = make([][]int, 0, startSize)
    		}
    
    Russ Cox's avatar
    Russ Cox committed
    		result = append(result, match)
    
    Russ Cox's avatar
    Russ Cox committed
    	return result
    
    // FindAllStringSubmatch is the 'All' version of [Regexp.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
    	}
    
    	re.allMatches(s, nil, n, func(match []int) {
    
    		if result == nil {
    			result = make([][]string, 0, startSize)
    		}
    
    		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]]
    			}
    		}
    
    Russ Cox's avatar
    Russ Cox committed
    		result = append(result, slice)
    
    Russ Cox's avatar
    Russ Cox committed
    	return result
    
    }
    
    // FindAllStringSubmatchIndex is the 'All' version of
    
    // [Regexp.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
    	}
    
    	re.allMatches(s, nil, n, func(match []int) {
    
    		if result == nil {
    			result = make([][]int, 0, startSize)
    		}
    
    Russ Cox's avatar
    Russ Cox committed
    		result = append(result, match)
    
    Russ Cox's avatar
    Russ Cox committed
    	return result
    
    Rick Arnold's avatar
    Rick Arnold committed
    
    // Split slices s into substrings separated by the expression and returns a slice of
    // the substrings between those expression matches.
    //
    // The slice returned by this method consists of all the substrings of s
    
    // not contained in the slice returned by [Regexp.FindAllString]. When called on an expression
    // that contains no metacharacters, it is equivalent to [strings.SplitN].
    
    Rick Arnold's avatar
    Rick Arnold committed
    //
    // Example:
    
    Russ Cox's avatar
    Russ Cox committed
    //
    //	s := regexp.MustCompile("a*").Split("abaabaccadaaae", 5)
    //	// s: ["", "b", "b", "c", "cadaaae"]
    
    Rick Arnold's avatar
    Rick Arnold committed
    //
    // The count determines the number of substrings to return:
    
    //   - n > 0: at most n substrings; the last substring will be the unsplit remainder;
    //   - n == 0: the result is nil (zero substrings);
    //   - n < 0: all substrings.
    
    Rick Arnold's avatar
    Rick Arnold committed
    func (re *Regexp) Split(s string, n int) []string {
    
    	if n == 0 {
    		return nil
    	}
    
    	if len(re.expr) > 0 && len(s) == 0 {
    		return []string{""}
    	}
    
    	matches := re.FindAllStringIndex(s, n)
    	strings := make([]string, 0, len(matches))
    
    	beg := 0
    	end := 0
    	for _, match := range matches {
    		if n > 0 && len(strings) >= n-1 {
    			break
    		}
    
    		end = match[0]
    		if match[1] != 0 {
    			strings = append(strings, s[beg:end])
    		}
    		beg = match[1]
    	}
    
    	if end != len(s) {
    		strings = append(strings, s[beg:])
    	}
    
    	return strings
    }
    
    // AppendText implements [encoding.TextAppender]. The output
    
    // matches that of calling the [Regexp.String] method.
    //
    // Note that the output is lossy in some cases: This method does not indicate
    
    // POSIX regular expressions (i.e. those compiled by calling [CompilePOSIX]), or
    
    // those for which the [Regexp.Longest] method has been called.
    
    func (re *Regexp) AppendText(b []byte) ([]byte, error) {
    	return append(b, re.String()...), nil
    }
    
    // MarshalText implements [encoding.TextMarshaler]. The output
    // matches that of calling the [Regexp.AppendText] method.
    //
    // See [Regexp.AppendText] for more information.
    
    func (re *Regexp) MarshalText() ([]byte, error) {
    
    // UnmarshalText implements [encoding.TextUnmarshaler] by calling
    // [Compile] on the encoded value.
    
    func (re *Regexp) UnmarshalText(text []byte) error {
    	newRE, err := Compile(string(text))
    	if err != nil {
    		return err
    	}
    	*re = *newRE
    	return nil
    }