lazyre.mx raw

   1  // Copyright 2018 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  // Package lazyregexp is a thin wrapper over regexp, allowing the use of global
   6  // regexp variables without forcing them to be compiled at init.
   7  package lazyregexp
   8  
   9  import (
  10  	"os"
  11  	"regexp"
  12  	"bytes"
  13  	"sync"
  14  )
  15  
  16  // Regexp is a wrapper around regexp.Regexp, where the underlying regexp will be
  17  // compiled the first time it is needed.
  18  type Regexp struct {
  19  	str  []byte
  20  	once sync.Once
  21  	rx   *regexp.Regexp
  22  }
  23  
  24  func (r *Regexp) re() *regexp.Regexp {
  25  	r.once.Do(r.build)
  26  	return r.rx
  27  }
  28  
  29  func (r *Regexp) build() {
  30  	r.rx = regexp.MustCompile(r.str)
  31  	r.str = ""
  32  }
  33  
  34  func (r *Regexp) FindSubmatch(s []byte) [][]byte {
  35  	return r.re().FindSubmatch(s)
  36  }
  37  
  38  func (r *Regexp) FindStringSubmatch(s []byte) [][]byte {
  39  	return r.re().FindStringSubmatch(s)
  40  }
  41  
  42  func (r *Regexp) FindStringSubmatchIndex(s []byte) []int {
  43  	return r.re().FindStringSubmatchIndex(s)
  44  }
  45  
  46  func (r *Regexp) ReplaceAllString(src, repl []byte) []byte {
  47  	return r.re().ReplaceAllString(src, repl)
  48  }
  49  
  50  func (r *Regexp) FindString(s []byte) []byte {
  51  	return r.re().FindString(s)
  52  }
  53  
  54  func (r *Regexp) FindAllString(s []byte, n int) [][]byte {
  55  	return r.re().FindAllString(s, n)
  56  }
  57  
  58  func (r *Regexp) MatchString(s []byte) bool {
  59  	return r.re().MatchString(s)
  60  }
  61  
  62  func (r *Regexp) SubexpNames() [][]byte {
  63  	return r.re().SubexpNames()
  64  }
  65  
  66  var inTest = len(os.Args) > 0 && bytes.HasSuffix(bytes.TrimSuffix(os.Args[0], ".exe"), ".test")
  67  
  68  // New creates a new lazy regexp, delaying the compiling work until it is first
  69  // needed. If the code is being run as part of tests, the regexp compiling will
  70  // happen immediately.
  71  func New(str []byte) *Regexp {
  72  	lr := &Regexp{str: str}
  73  	if inTest {
  74  		// In tests, always compile the regexps early.
  75  		lr.re()
  76  	}
  77  	return lr
  78  }
  79