package miniredis // Translate the 'KEYS' argument ('foo*', 'f??', &c.) into a regexp. import ( "bytes" "regexp" ) // patternRE compiles a KEYS argument to a regexp. Returns nil if the given // pattern will never match anything. // The general strategy is to sandwich all non-meta characters between \Q...\E. func patternRE(k string) *regexp.Regexp { re := bytes.Buffer{} re.WriteString(`^\Q`) for i := 0; i < len(k); i++ { p := k[i] switch p { case '*': re.WriteString(`\E.*\Q`) case '?': re.WriteString(`\E.\Q`) case '[': charClass := bytes.Buffer{} i++ for ; i < len(k); i++ { if k[i] == ']' { break } if k[i] == '\\' { if i == len(k)-1 { // Ends with a '\'. U-huh. return nil } charClass.WriteByte(k[i]) i++ charClass.WriteByte(k[i]) continue } charClass.WriteByte(k[i]) } if charClass.Len() == 0 { // '[]' is valid in Redis, but matches nothing. return nil } re.WriteString(`\E[`) re.Write(charClass.Bytes()) re.WriteString(`]\Q`) case '\\': if i == len(k)-1 { // Ends with a '\'. U-huh. return nil } // Forget the \, keep the next char. i++ re.WriteByte(k[i]) continue default: re.WriteByte(p) } } re.WriteString(`\E$`) return regexp.MustCompile(re.String()) }