golang format data to JSON format in one pass

huangapple go评论78阅读模式
英文:

golang format data to JSON format in one pass

问题

我的原始数据格式:

id=1, name=peter, age=12

我将其转换为JSON字符串:

{"id" : "1", "name" : "peter", "age" : "12"}

我使用以下golang语句进行转换:

Regex, err = regexp.Compile(`([^,\s]*)=([^,\s]*)`)  
JSON := fmt.Sprintf("{\"%s}", Regex.ReplaceAllString(inp, `"$1" : "$2"`))

inp是保存原始数据格式的变量。

然而,现在我得到了一个新的格式:

id=1 name=peter age=12

我也想使用类似上面使用的方法将其转换为JSON字符串,即使用正则表达式进行一次性格式化。

{"id"="1", "name"="peter", "age"="12"}

我该如何实现这个目标?

更新:额外的要求。如果输入格式是

id=1, name=peter, age="12"

我需要去掉引号或转义",以便我可以在下一步中进行处理。双引号可以出现在任何值字段的开头和结尾。

英文:

My original data format:

id=1, name=peter, age=12

I converted it to JSON string:

{"id" : "1", "name" : "peter", "age" : "12"}

I use the following golang statement to do the conversion:

Regex, err = regexp.Compile(`([^,\s]*)=([^,\s]*)`)  
JSON := fmt.Sprintf("{%s}", Regex.ReplaceAllString(inp, `"$1" : "$2"`))

inp is the variable that holds the original data format.

However, now I get a new format:

id=1 name=peter age=12

and I also want to convert to JSON string using similar method that I used above, i.e., use regex to do a one pass formatting.

{"id"="1", "name"="peter", "age"="12"}

How can I achieve that?

UPDATE: One additional requirement. if the input format is

id=1, name=peter, age="12"

I need to get rid of the "" to be or escape " so I can process in the next step. The double quote can appear at the beginning and the end of any value field.

答案1

得分: 1

问题有两个部分:简单的部分是将数据序列化为JSON,Go语言有标准库提供了相应的方法。我会使用该库而不是自己尝试编码JSON。

稍微复杂一点的部分是将输入解析为可以轻松序列化的结构体或映射,并使其足够灵活以接受不同的输入格式。

我会使用一个通用接口将文本转换为结构体或映射,然后为解析每种新的输入类型实现该接口。

示例代码:(可以在这里运行)

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
)

// parseFn描述了将输入转换为映射的函数。
// 如果格式是已知的,这可以是结构体或其他类型。
// 在实际代码中,这将返回map[string]interface{},但为了这个
// 演示,我只使用了string类型。
type parseFn func(string) (map[string]string, error)

// parseFormat1用于以逗号分隔的字段
func parseFormat1(in string) (map[string]string, error) {
	data := map[string]string{}
	fields := strings.Split(in, ",")
	for _, field := range fields {
		pair := strings.Split(field, "=")
		if len(pair) != 2 {
			return nil, errors.New("invalid input")
		}
		data[strings.Trim(pair[0], ` "`)] = strings.Trim(pair[1], ` "`)
	}
	return data, nil
}

// parseFormat2用于没有逗号的行
func parseFormat2(in string) (map[string]string, error) {
	data := map[string]string{}
	fields := strings.Split(in, " ")
	for _, field := range fields {
		pair := strings.Split(field, "=")
		if len(pair) != 2 {
			return nil, errors.New("invalid input")
		}
		data[strings.Trim(pair[0], ` "`)] = strings.Trim(pair[1], ` "`)
	}
	return data, nil
}

// nullFormat是当我们不知道格式时的备选方案
func nullFormat(in string) (map[string]string, error) { return nil, errors.New("invalid format") }

// classify尝试猜测要用于输入的解析器
func classify(in string) parseFn {
	switch {
	case strings.Count(in, ",") > 1:
		return parseFormat1
	case strings.Count(in, " ") > 1:
		return parseFormat2
	default:
		return nullFormat
	}
}

func main() {
	testCases := []string{
		`id=1, name=peter, age=12`,
		`id=1, name=peter, age="12"`,
		`id=1 name=peter age=12`,
		`id=1;name=peter;age="12"`,
	}

	for ix, tc := range testCases {
		pfn := classify(tc)
		d, err := pfn(tc)
		if err != nil {
			fmt.Printf("\nerror parsing on line %d: %v\n", ix, err)
			continue
		}
		b, err := json.Marshal(d)
		if err != nil {
			fmt.Printf("\nerror marshaling on line %d: %v\n", ix, err)
			continue
		}
		fmt.Printf("\nSuccess on line %d:\n INPUT: %s\nOUTPUT: %s\n", ix, tc, string(b))
	}
}

以上是给出的代码示例,它演示了如何根据输入的不同格式进行解析,并将其序列化为JSON。你可以在提供的链接中运行该代码。

英文:

There are two parts to the question: The easy part is serialising to JSON, Go has standard library methods for doing that. I would use that library rather than trying to encode the JSON myself.

The slightly trickier part of your question is parsing the input into a struct or map that can be easily serialised out, and making it flexible enough to accept different input formats.

I would do it with a general interface for converting text to a struct or map, and then implementing the interface for parsing each new input type.

Sample code: (You can run it here)

package main
import (
"encoding/json"
"errors"
"fmt"
"strings"
)
// parseFn describes the function for converting input into a map.
// This could be a struct or something else if the format is well known.
// In real code this would return map[string]interface{}, but for this
// demo I'm just using string
type parseFn func(string) (map[string]string, error)
// parseFormat1 is for fields separated by commas
func parseFormat1(in string) (map[string]string, error) {
data := map[string]string{}
fields := strings.Split(in, ",")
for _, field := range fields {
pair := strings.Split(field, "=")
if len(pair) != 2 {
return nil, errors.New("invalid input")
}
data[strings.Trim(pair[0], ` "`)] = strings.Trim(pair[1], ` "`)
}
return data, nil
}
// parseFormat2 is for lines with no commas
func parseFormat2(in string) (map[string]string, error) {
data := map[string]string{}
fields := strings.Split(in, " ")
for _, field := range fields {
pair := strings.Split(field, "=")
if len(pair) != 2 {
return nil, errors.New("invalid input")
}
data[strings.Trim(pair[0], ` "`)] = strings.Trim(pair[1], ` "`)
}
return data, nil
}
// nullFormat is what we fall back on when we just don't know
func nullFormat(in string) (map[string]string, error) { return nil, errors.New("invalid format") }
// classify just tries to guess the parser to use for the input
func classify(in string) parseFn {
switch {
case strings.Count(in, ", ") > 1:
return parseFormat1
case strings.Count(in, " ") > 1:
return parseFormat2
default:
return nullFormat
}
}
func main() {
testCases := []string{
`id=1, name=peter, age=12`,
`id=1, name=peter, age="12"`,
`id=1 name=peter age=12`,
`id=1;name=peter;age="12"`,
}
for ix, tc := range testCases {
pfn := classify(tc)
d, err := pfn(tc)
if err != nil {
fmt.Printf("\nerror parsing on line %d: %v\n", ix, err)
continue
}
b, err := json.Marshal(d)
if err != nil {
fmt.Printf("\nerror marshaling on line %d: %v\n", ix, err)
continue
}
fmt.Printf("\nSuccess on line %d:\n INPUT: %s\nOUTPUT: %s\n", ix, tc, string(b))
}
}

huangapple
  • 本文由 发表于 2017年4月28日 05:26:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/43668177.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定