github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/logql/log/pattern/pattern.go (about)

     1  package pattern
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  )
     7  
     8  var (
     9  	ErrNoCapture   = errors.New("at least one capture is required")
    10  	ErrInvalidExpr = errors.New("invalid expression")
    11  )
    12  
    13  type Matcher interface {
    14  	Matches(in []byte) [][]byte
    15  	Names() []string
    16  }
    17  
    18  type matcher struct {
    19  	e expr
    20  
    21  	captures [][]byte
    22  	names    []string
    23  }
    24  
    25  func New(in string) (Matcher, error) {
    26  	e, err := parseExpr(in)
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  	if err := e.validate(); err != nil {
    31  		return nil, err
    32  	}
    33  	return &matcher{
    34  		e:        e,
    35  		captures: make([][]byte, 0, e.captureCount()),
    36  		names:    e.captures(),
    37  	}, nil
    38  }
    39  
    40  // Matches matches the given line with the provided pattern.
    41  // Matches invalidates the previous returned captures array.
    42  func (m *matcher) Matches(in []byte) [][]byte {
    43  	if len(in) == 0 {
    44  		return nil
    45  	}
    46  	if len(m.e) == 0 {
    47  		return nil
    48  	}
    49  	captures := m.captures[:0]
    50  	expr := m.e
    51  	if ls, ok := expr[0].(literals); ok {
    52  		i := bytes.Index(in, ls)
    53  		if i != 0 {
    54  			return nil
    55  		}
    56  		in = in[len(ls):]
    57  		expr = expr[1:]
    58  	}
    59  	if len(expr) == 0 {
    60  		return nil
    61  	}
    62  	// from now we have capture - literals - capture ... (literals)?
    63  	for len(expr) != 0 {
    64  		if len(expr) == 1 { // we're ending on a capture.
    65  			if !(expr[0].(capture)).isUnamed() {
    66  				captures = append(captures, in)
    67  			}
    68  			return captures
    69  		}
    70  		cap := expr[0].(capture)
    71  		ls := expr[1].(literals)
    72  		expr = expr[2:]
    73  		i := bytes.Index(in, ls)
    74  		if i == -1 {
    75  			// if a capture is missed we return up to the end as the capture.
    76  			if !cap.isUnamed() {
    77  				captures = append(captures, in)
    78  			}
    79  			return captures
    80  		}
    81  
    82  		if cap.isUnamed() {
    83  			in = in[len(ls)+i:]
    84  			continue
    85  		}
    86  		captures = append(captures, in[:i])
    87  		in = in[len(ls)+i:]
    88  	}
    89  
    90  	return captures
    91  }
    92  
    93  func (m *matcher) Names() []string {
    94  	return m.names
    95  }