最近处理json数据,json中数据下划线形式,找了半天没有找到能把下划线处理成驼峰式的代码~ 自己动手!
功能:把例如 "the_red_apple":"very_nice" 转化为 "TheRedApple":"very_nice" 这种。
代码:https://github.com/SkyingzZ/camel_json_keys
//下划线写法转为驼峰写法 like "sample_test_name_balabala" to "SampleTestNameBalabala"
func CamelName(name string) string {
name = strings.Replace(name, "_", " ", -1)
name = strings.Title(name)
return strings.Replace(name, " ", "", -1)
}
func CamelJsonKey(json_data []byte) []byte{
str := string(json_data)
var is_quot_first bool = true //在双引号中为 false | the value in the double quotes is false
var first_index int = 0 //左引号的索引 | the left quote index
var second_index int = 0 //右引号的索引 | the right quote index
var res_str string
var the_key_index int
for i, value := range str{
if !is_quot_first && str[i] == '"'{ //右引号 | if meet the right quote
second_index = i
is_quot_first = !is_quot_first
}else if is_quot_first && str[i] == '"'{ //左引号 | if meet the left quote
first_index = i
the_key_index = len(res_str)
is_quot_first= !is_quot_first
}else if is_quot_first && str[i] == ':'{
tmp_str := camelName(str[first_index+1: second_index])
res_str = res_str[:the_key_index]+"\""+tmp_str+"\""
}else{}
res_str += string(value)
}
return []byte(res_str)
}
效果:
原来 ==> 后来
本来觉得上面这个一个for循环的代码虽然有很多数组的copy以及字符串的处理,但应该已经足够处理问题了。可终于在一个特殊的情况,遇到了一个6M大小的json字符串,此处理函数处理了10分钟。
于是对代码进行了改进,并换了一个使用map来处理的思路。下面这个代码,暂时业务中没遇到过超过ms级的情况。
同时,也得到了一点启迪,即在可以使用系统提供的底层情况下,尽量不要自己去写底层。因为不要觉得自己代码效率会超过大师。
//下划线写法转为驼峰写法,并且将'/'字符转换为'' like "sample_test_name_balabala/dilidili" to "SampleTestNameBalabalaDilidili"
//同时也会去掉左侧的全部数字 like "361_sport" to "Sport"
func camelName(name string) string {
name = strings.Replace(name, "_", " ", -1)
name = strings.Replace(name, "/", " ", -1)
name = strings.Title(name)
name = strings.Replace(name, " ", "", -1)
return strings.TrimLeft(name, "0123456789")
}
func camelVecKey(my_vec []interface{}) ([]interface{}, error){
if !strings.HasPrefix(reflect.TypeOf(my_vec).String(), "[]"){
return nil, errors.New("decode to vector failed")
}
rtn_vec := my_vec[0:0]
for _, node := range my_vec{
if reflect.TypeOf(node) == nil{
continue
}
if strings.HasPrefix(reflect.TypeOf(node).String(),"map"){
res_node, err := camelMapKey(node.(map[string]interface{}))
if err != nil{
return nil, err
}
rtn_vec = append(rtn_vec, res_node)
}else if strings.HasPrefix(reflect.TypeOf(node).String(),"[]"){
res_node, err := camelVecKey(node.([]interface{}))
if err != nil{
return nil, err
}
rtn_vec = append(rtn_vec, res_node)
}else{
rtn_vec = append(rtn_vec, node)
}
}
return rtn_vec, nil
}
func camelMapKey(my_map map[string]interface{}) (map[string]interface{}, error){
if !strings.HasPrefix(reflect.TypeOf(my_map).String(), "map"){
return nil, errors.New("decode to map failed")
}
rtn_map := make(map[string]interface{})
for k,v := range my_map{
if reflect.TypeOf(v) == nil{
rtn_map[camelName(k)] = nil
continue
}
if strings.HasPrefix(reflect.TypeOf(v).String(),"map"){
res_map, err := camelMapKey(v.(map[string]interface{}))
if err != nil{
return nil, err
}
rtn_map[camelName(k)] = res_map
} else if strings.HasPrefix(reflect.TypeOf(v).String(), "[]"){
res_node, err := camelVecKey(v.([]interface{}))
if err != nil{
return nil, err
}
rtn_map[camelName(k)] = res_node
} else {
rtn_map[camelName(k)] = v
}
}
return rtn_map, nil
}
func CamelJsonKey(json_data []byte, is_vec bool) ([]byte, error){
var my_map_vec []interface{}
var my_map map[string]interface{}
if is_vec {
err := json.Unmarshal(json_data, &my_map_vec)
if err != nil{
return []byte{}, errors.New("Unmarshal json to vector failed")
}
my_map_vec, err = camelVecKey(my_map_vec)
if err != nil{
return []byte{}, err
}
my_json,err :=json.Marshal(my_map_vec)
if err != nil{
return []byte{}, err
}
return my_json, err
} else {
my_map = make(map[string]interface{})
err := json.Unmarshal(json_data, &my_map)
if err != nil{
return []byte{}, errors.New("Unmarshal json to map failed")
}
my_map, err = camelMapKey(my_map)
if err != nil{
return []byte{}, err
}
my_json,err :=json.Marshal(my_map)
if err != nil{
return []byte{}, err
}
return my_json, err
}
}