zoukankan      html  css  js  c++  java
  • Go语言json编码驼峰转下划线、下划线转驼峰

    一、需求

    golang默认的结构体json转码出来,都是根据字段名生成的大写驼峰格式,但是一般我们最常用的json格式是小写驼峰或者小写下划线,因此,我们非常需要一个统一的方法去转换,而不想挨个写json标签,例如

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    func main() {
    	type Person struct {
    		HelloWold       string
    		LightWeightBaby string
    	}
    	var a = Person{HelloWold: "chenqionghe", LightWeightBaby: "muscle"}
    	res, _ := json.Marshal(a)
    	fmt.Printf("%s", res)
    }
    

    运行结果

    {"HelloWold":"chenqionghe","LightWeightBaby":"muscle"}
    

    输出来的json结构是大写驼峰的,肯定非常别扭,当然 ,我们通过设定json标签来设定输出的json字段名,例如

    type Person struct {
    	HelloWold       string `json:"hello_wold"`
    	LightWeightBaby string `json:"light_weight_baby"`
    }
    

    但是如果字段特别多,需要挨个设置也太麻烦了。

    二、实现

    Golang 的标准 Json 在处理各种数据类型是都是调用其类型接口UnmarshalJSON解码和MarshalJSON编码进行转换的,所以我们可以封装一个统一转换下划线的json结构体或统一转换驼峰的json结构体,并实现MarshalJSON方法,就可以达到目的。
    实现如下

    package jsonconv
    
    import (
    	"bytes"
    	"encoding/json"
    	"log"
    	"regexp"
    	"strconv"
    	"strings"
    	"unicode"
    )
    
    /*************************************** 下划线json ***************************************/
    type JsonSnakeCase struct {
    	Value interface{}
    }
    
    func (c JsonSnakeCase) MarshalJSON() ([]byte, error) {
    	// Regexp definitions
    	var keyMatchRegex = regexp.MustCompile(`"(w+)":`)
    	var wordBarrierRegex = regexp.MustCompile(`(w)([A-Z])`)
    	marshalled, err := json.Marshal(c.Value)
    	converted := keyMatchRegex.ReplaceAllFunc(
    		marshalled,
    		func(match []byte) []byte {
    			return bytes.ToLower(wordBarrierRegex.ReplaceAll(
    				match,
    				[]byte(`${1}_${2}`),
    			))
    		},
    	)
    	return converted, err
    }
    
    /*************************************** 驼峰json ***************************************/
    type JsonCamelCase struct {
    	Value interface{}
    }
    
    func (c JsonCamelCase) MarshalJSON() ([]byte, error) {
    	var keyMatchRegex = regexp.MustCompile(`"(w+)":`)
    	marshalled, err := json.Marshal(c.Value)
    	converted := keyMatchRegex.ReplaceAllFunc(
    		marshalled,
    		func(match []byte) []byte {
    			matchStr := string(match)
    			key := matchStr[1 : len(matchStr)-2]
    			resKey := Lcfirst(Case2Camel(key))
    			return []byte(`"` + resKey + `":`)
    		},
    	)
    	return converted, err
    }
    
    /*************************************** 其他方法 ***************************************/
    // 驼峰式写法转为下划线写法
    func Camel2Case(name string) string {
    	buffer := NewBuffer()
    	for i, r := range name {
    		if unicode.IsUpper(r) {
    			if i != 0 {
    				buffer.Append('_')
    			}
    			buffer.Append(unicode.ToLower(r))
    		} else {
    			buffer.Append(r)
    		}
    	}
    	return buffer.String()
    }
    
    // 下划线写法转为驼峰写法
    func Case2Camel(name string) string {
    	name = strings.Replace(name, "_", " ", -1)
    	name = strings.Title(name)
    	return strings.Replace(name, " ", "", -1)
    }
    
    // 首字母大写
    func Ucfirst(str string) string {
    	for i, v := range str {
    		return string(unicode.ToUpper(v)) + str[i+1:]
    	}
    	return ""
    }
    
    // 首字母小写
    func Lcfirst(str string) string {
    	for i, v := range str {
    		return string(unicode.ToLower(v)) + str[i+1:]
    	}
    	return ""
    }
    
    // 内嵌bytes.Buffer,支持连写
    type Buffer struct {
    	*bytes.Buffer
    }
    
    func NewBuffer() *Buffer {
    	return &Buffer{Buffer: new(bytes.Buffer)}
    }
    
    func (b *Buffer) Append(i interface{}) *Buffer {
    	switch val := i.(type) {
    	case int:
    		b.append(strconv.Itoa(val))
    	case int64:
    		b.append(strconv.FormatInt(val, 10))
    	case uint:
    		b.append(strconv.FormatUint(uint64(val), 10))
    	case uint64:
    		b.append(strconv.FormatUint(val, 10))
    	case string:
    		b.append(val)
    	case []byte:
    		b.Write(val)
    	case rune:
    		b.WriteRune(val)
    	}
    	return b
    }
    
    func (b *Buffer) append(s string) *Buffer {
    	defer func() {
    		if err := recover(); err != nil {
    			log.Println("*****内存不够了!******")
    		}
    	}()
    	b.WriteString(s)
    	return b
    }
    

    三、使用

    JsonSnakeCase统一转下划线json

    使用jsonconv.JsonSnakeCase包裹一下要输出json的对象即可

    func main() {
    	type Person struct {
    		HelloWold       string
    		LightWeightBaby string
    	}
    	var a = Person{HelloWold: "chenqionghe", LightWeightBaby: "muscle"}
    	res, _ := json.Marshal(jsonconv.JsonSnakeCase{a})
    	fmt.Printf("%s", res)
    }
    

    输出如下

    {"hello_wold":"chenqionghe","light_weight_baby":"muscle"}
    

    JsonCamelCase统一转驼峰json

    已经指定了下划线标签的结构体,我们也可以统一转为驼峰的json

    func main() {
    	type Person struct {
    		HelloWold       string `json:"hello_wold"`
    		LightWeightBaby string `json:"light_weight_baby"`
    	}
    	var a = Person{HelloWold: "chenqionghe", LightWeightBaby: "muscle"}
    	res, _ := json.Marshal(jsonconv.JsonCamelCase{a})
    	fmt.Printf("%s", res)
    }
    

    输出如下

    {"helloWold":"chenqionghe","lightWeightBaby":"muscle"}
    

    非常方便的解决了json统一转码格式的需求

  • 相关阅读:
    Oracle函数-DECODE
    WPF模板
    WPF数据编辑的提交与撤销
    WPF数据验证
    WPF多源绑定
    WPF筛选、排序和分组
    WPF绑定到集合
    输出的数据格式是如何决定的-------Asp.net WebAPI学习笔记(二)
    路由其实也可以很简单-------Asp.net WebAPI学习笔记(一)
    终结篇:RemoteWebDriver与Grid简介-----Selenium快速入门(十五)
  • 原文地址:https://www.cnblogs.com/chenqionghe/p/13067596.html
Copyright © 2011-2022 走看看