unicode patterns

This commit is contained in:
Josh Baker 2016-08-24 13:26:44 -07:00
parent 67e38154bd
commit 4fceff029c
2 changed files with 148 additions and 6 deletions

View File

@ -485,6 +485,7 @@ func Get(json string, path string) Result {
var alogok bool
var alogkey string
var alog []int
var uc bool
// parse the path into multiple parts.
for i := 0; i < len(path); i++ {
@ -521,6 +522,10 @@ func Get(json string, path string) Result {
}
continue
}
if path[i] > 0x7f {
uc = true
continue
}
if path[i] == '\\' {
// go into escape mode. this is a slower path that
// strips off the escape character from the part.
@ -530,6 +535,10 @@ func Get(json string, path string) Result {
epart = append(epart, path[i])
i++
for ; i < len(path); i++ {
if path[i] > 0x7f {
uc = true
continue
}
if path[i] == '\\' {
i++
if i < len(path) {
@ -682,7 +691,7 @@ read_key:
if parts[depth-1].wild {
// the path part contains a wildcard character. we must do a wildcard
// match to determine if it truly matches.
matched = wildcardMatch(f.key, parts[depth-1].key)
matched = wildcardMatch(f.key, parts[depth-1].key, uc)
} else {
// just a straight up equality check
matched = parts[depth-1].key == f.key
@ -1093,12 +1102,24 @@ func stringLessInsensitive(a, b string) bool {
// wilcardMatch returns true if str matches pattern. This is a very
// simple wildcard match where '*' matches on any number characters
// and '?' matches on any one character.
func wildcardMatch(str, pattern string) bool {
func wildcardMatch(str, pattern string, uc bool) bool {
if pattern == "*" {
return true
}
return deepMatch(str, pattern)
if !uc {
return deepMatch(str, pattern)
}
rstr := make([]rune, 0, len(str))
rpattern := make([]rune, 0, len(pattern))
for _, r := range str {
rstr = append(rstr, r)
}
for _, r := range pattern {
rpattern = append(rpattern, r)
}
return deepMatchRune(rstr, rpattern)
}
func deepMatch(str, pattern string) bool {
for len(pattern) > 0 {
switch pattern[0] {
@ -1111,11 +1132,68 @@ func deepMatch(str, pattern string) bool {
return false
}
case '*':
return wildcardMatch(str, pattern[1:]) ||
(len(str) > 0 && wildcardMatch(str[1:], pattern))
return deepMatch(str, pattern[1:]) ||
(len(str) > 0 && deepMatch(str[1:], pattern))
}
str = str[1:]
pattern = pattern[1:]
}
return len(str) == 0 && len(pattern) == 0
}
func deepMatchRune(str, pattern []rune) bool {
for len(pattern) > 0 {
switch pattern[0] {
default:
if len(str) == 0 || str[0] != pattern[0] {
return false
}
case '?':
if len(str) == 0 {
return false
}
case '*':
return deepMatchRune(str, pattern[1:]) ||
(len(str) > 0 && deepMatchRune(str[1:], pattern))
}
str = str[1:]
pattern = pattern[1:]
}
return len(str) == 0 && len(pattern) == 0
}
/*
func wildcardMatch(str, pattern string) bool {
if pattern == "*" {
return true
}
rstr := make([]rune, 0, len(str))
rpattern := make([]rune, 0, len(pattern))
for _, r := range str {
rstr = append(rstr, r)
}
for _, r := range pattern {
rpattern = append(rpattern, r)
}
return deepMatch(rstr, rpattern)
}
func deepMatch(str, pattern []rune) bool {
for len(pattern) > 0 {
switch pattern[0] {
default:
if len(str) == 0 || str[0] != pattern[0] {
return false
}
case '?':
if len(str) == 0 {
return false
}
case '*':
return deepMatch(str, pattern[1:]) ||
(len(str) > 0 && deepMatch(str[1:], pattern))
}
str = str[1:]
pattern = pattern[1:]
}
return len(str) == 0 && len(pattern) == 0
}
*/

View File

@ -248,7 +248,71 @@ func TestBasic(t *testing.T) {
t.Fatalf("expecting %v, got %v", "Jason", fn)
}
}
func TestMatch(t *testing.T) {
if !wildcardMatch("hello world", "hello world", false) {
t.Fatal("fail")
}
if wildcardMatch("hello world", "jello world", false) {
t.Fatal("fail")
}
if !wildcardMatch("hello world", "hello*", false) {
t.Fatal("fail")
}
if wildcardMatch("hello world", "jello*", false) {
t.Fatal("fail")
}
if !wildcardMatch("hello world", "hello?world", false) {
t.Fatal("fail")
}
if wildcardMatch("hello world", "jello?world", false) {
t.Fatal("fail")
}
if !wildcardMatch("hello world", "he*o?world", false) {
t.Fatal("fail")
}
if !wildcardMatch("hello world", "he*o?wor*", false) {
t.Fatal("fail")
}
if !wildcardMatch("hello world", "he*o?*r*", false) {
t.Fatal("fail")
}
if !wildcardMatch("的情况下解析一个", "*", true) {
t.Fatal("fail")
}
if !wildcardMatch("的情况下解析一个", "*况下*", true) {
t.Fatal("fail")
}
if !wildcardMatch("的情况下解析一个", "*况?*", true) {
t.Fatal("fail")
}
if !wildcardMatch("的情况下解析一个", "的情况?解析一个", true) {
t.Fatal("fail")
}
}
func TestUnicode(t *testing.T) {
var json = `{"key":0,"的情况下解":{"key":1,"的情况":2}}`
if Get(json, "的情况下解.key").Num != 1 {
t.Fatal("fail")
}
if Get(json, "的情况下解.的情况").Num != 2 {
t.Fatal("fail")
}
if Get(json, "的情况下解.的?况").Num != 2 {
t.Fatal("fail")
}
if Get(json, "的情况下解.的?*").Num != 2 {
t.Fatal("fail")
}
if Get(json, "的情况下解.*?况").Num != 2 {
t.Fatal("fail")
}
if Get(json, "的情?下解.*?况").Num != 2 {
t.Fatal("fail")
}
if Get(json, "的情下解.*?况").Num != 0 {
t.Fatal("fail")
}
}
func TestUnescape(t *testing.T) {
unescape(string([]byte{'\\', '\\', 0}))
unescape(string([]byte{'\\', '/', '\\', 'b', '\\', 'f'}))