func (m *Match) Groups() []Group {
	m.populateOtherGroups()
	g := make([]Group, len(m.otherGroups)+1)
	g[0] = m.Group
	copy(g[1:], m.otherGroups)
	return g
}
Groups returns all the capture groups, starting with group 0 (the full match)
package regexp2
import (
	"bytes"
	"fmt"
)
type Match struct {
	Group  
	regex       *Regexp
	otherGroups []Group
	textpos   int
	textstart int
	capcount   int
	caps       []int
	sparseCaps map[int]int
	matches    [][]int
	matchcount []int
	balancing bool
}
type Group struct {
	Capture  
	Name     string     
	Captures []Capture  
}
type Capture struct {
	text []rune
	Index int
	Length int
}
func (c *Capture) String() string {
	return string(c.text[c.Index : c.Index+c.Length])
}
func (c *Capture) Runes() []rune {
	return c.text[c.Index : c.Index+c.Length]
}
func newMatch(regex *Regexp, capcount int, text []rune, startpos int) *Match {
	m := Match{
		regex:      regex,
		matchcount: make([]int, capcount),
		matches:    make([][]int, capcount),
		textstart:  startpos,
		balancing:  false,
	}
	m.Name = "0"
	m.text = text
	m.matches[0] = make([]int, 2)
	return &m
}
func newMatchSparse(regex *Regexp, caps map[int]int, capcount int, text []rune, startpos int) *Match {
	m := newMatch(regex, capcount, text, startpos)
	m.sparseCaps = caps
	return m
}
func (m *Match) reset(text []rune, textstart int) {
	m.text = text
	m.textstart = textstart
	for i := 0; i < len(m.matchcount); i++ {
		m.matchcount[i] = 0
	}
	m.balancing = false
}
func (m *Match) tidy(textpos int) {
	interval := m.matches[0]
	m.Index = interval[0]
	m.Length = interval[1]
	m.textpos = textpos
	m.capcount = m.matchcount[0]
	m.Group.Captures = []Capture{m.Group.Capture}
	if m.balancing {
		for cap := 0; cap < len(m.matchcount); cap++ {
			limit := m.matchcount[cap] * 2
			matcharray := m.matches[cap]
			var i, j int
			for i = 0; i < limit; i++ {
				if matcharray[i] < 0 {
					break
				}
			}
			for j = i; i < limit; i++ {
				if matcharray[i] < 0 {
					j--
				} else {
					if i != j {
						matcharray[j] = matcharray[i]
					}
					j++
				}
			}
			m.matchcount[cap] = j / 2
		}
		m.balancing = false
	}
}
func (m *Match) isMatched(cap int) bool {
	return cap < len(m.matchcount) && m.matchcount[cap] > 0 && m.matches[cap][m.matchcount[cap]*2-1] != (-3+1)
}
func (m *Match) matchIndex(cap int) int {
	i := m.matches[cap][m.matchcount[cap]*2-2]
	if i >= 0 {
		return i
	}
	return m.matches[cap][-3-i]
}
func (m *Match) matchLength(cap int) int {
	i := m.matches[cap][m.matchcount[cap]*2-1]
	if i >= 0 {
		return i
	}
	return m.matches[cap][-3-i]
}
func (m *Match) addMatch(c, start, l int) {
	if m.matches[c] == nil {
		m.matches[c] = make([]int, 2)
	}
	capcount := m.matchcount[c]
	if capcount*2+2 > len(m.matches[c]) {
		oldmatches := m.matches[c]
		newmatches := make([]int, capcount*8)
		copy(newmatches, oldmatches[:capcount*2])
		m.matches[c] = newmatches
	}
	m.matches[c][capcount*2] = start
	m.matches[c][capcount*2+1] = l
	m.matchcount[c] = capcount + 1
}
func (m *Match) balanceMatch(c int) {
	m.balancing = true
	capcount := m.matchcount[c]
	target := capcount*2 - 2
	if m.matches[c][target] < 0 {
		target = -3 - m.matches[c][target]
	}
	target -= 2
	if target >= 0 && m.matches[c][target] < 0 {
		m.addMatch(c, m.matches[c][target], m.matches[c][target+1])
	} else {
		m.addMatch(c, -3-target, -4-target  )
	}
}
func (m *Match) removeMatch(c int) {
	m.matchcount[c]--
}
func (m *Match) GroupCount() int {
	return len(m.matchcount)
}
func (m *Match) GroupByName(name string) *Group {
	num := m.regex.GroupNumberFromName(name)
	if num < 0 {
		return nil
	}
	return m.GroupByNumber(num)
}
func (m *Match) GroupByNumber(num int) *Group {
	if m.sparseCaps != nil {
		if newNum, ok := m.sparseCaps[num]; ok {
			num = newNum
		}
	}
	if num >= len(m.matchcount) || num < 0 {
		return nil
	}
	if num == 0 {
		return &m.Group
	}
	m.populateOtherGroups()
	return &m.otherGroups[num-1]
}