diff --git a/gjson.go b/gjson.go index e6cc523..478bf8f 100644 --- a/gjson.go +++ b/gjson.go @@ -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 +} +*/ diff --git a/gjson_test.go b/gjson_test.go index 401a43f..b5739b7 100644 --- a/gjson_test.go +++ b/gjson_test.go @@ -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'}))