github.com/Comcast/plax@v0.8.32/dsl/regexp.go (about)

     1  package dsl
     2  
     3  import (
     4  	"fmt"
     5  	"regexp"
     6  	"strings"
     7  	"unicode"
     8  
     9  	"github.com/Comcast/sheens/match"
    10  )
    11  
    12  // RegexpMatch compiles the given pattern (as Go regular expression,
    13  // matches the target against that pattern, and returns the results as
    14  // a list of match.Bindings.
    15  //
    16  // A matched named group becomes a binding. If the name starts with an
    17  // uppercase rune, then the binding variable starts with '?'.
    18  // Otherwise, the variable starts with '?*'
    19  func RegexpMatch(pat string, target interface{}) ([]match.Bindings, error) {
    20  	pat = strings.TrimRight(pat, "\n\r")
    21  
    22  	r, err := regexp.Compile(pat)
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  
    27  	s, is := target.(string)
    28  	if !is {
    29  		return nil, fmt.Errorf("RegexpMatch wants a %T target, not a %T", s, target)
    30  	}
    31  
    32  	ss := r.FindStringSubmatch(s)
    33  
    34  	if ss == nil {
    35  		return nil, nil
    36  	}
    37  
    38  	bss := make([]match.Bindings, 1)
    39  	bs := make(match.Bindings)
    40  	bss[0] = bs
    41  	for i, name := range r.SubexpNames() {
    42  		if i == 0 {
    43  			continue
    44  		}
    45  		if name == "" {
    46  			// Unnamed group
    47  			continue
    48  		}
    49  
    50  		val := ss[i]
    51  
    52  		sym := "?"
    53  		if first, has := FirstRune(name); has {
    54  			if unicode.IsLower(first) {
    55  				sym += "*"
    56  			}
    57  		}
    58  		sym += name
    59  
    60  		bs[sym] = val
    61  	}
    62  
    63  	return bss, nil
    64  }
    65  
    66  // FirstRune returns the first rune or false (if the string has zero
    67  // length).
    68  func FirstRune(s string) (rune, bool) {
    69  	for _, r := range s {
    70  		return r, true
    71  	}
    72  	return ' ', false
    73  }