
本文介绍如何使用 Go 标准库结合灵活的解析策略,将多种格式(逗号/空格分隔、带引号/无引号)的键值对字符串(如 id=1 name=peter age="12")安全、可靠地转换为合法 JSON 字符串,避免手动拼接 JSON 引发的格式与转义问题。
本文介绍如何使用 go 标准库结合灵活的解析策略,将多种格式(逗号/空格分隔、带引号/无引号)的键值对字符串(如 `id=1 name=peter age="12"`)安全、可靠地转换为合法 json 字符串,避免手动拼接 json 引发的格式与转义问题。
在 Go 中,不推荐通过正则替换手动拼接 JSON 字符串(如 fmt.Sprintf("{%s}", ...)),因为这极易导致 JSON 格式错误:未转义的双引号、缺失逗号、键名/值未正确加引号、嵌套结构失效等。Go 提供了成熟稳定的 encoding/json 包,应作为 JSON 序列化的唯一权威途径。
正确的做法是:先将原始字符串解析为 Go 原生数据结构(如 map[string]string),再调用 json.Marshal() 生成严格合规的 JSON。针对您提出的三种输入变体——
-
id=1, name=peter, age=12(逗号+空格分隔) -
id=1 name=peter age=12(纯空格分隔) -
id=1, name=peter, age="12"(值含双引号,需剥离或转义)
我们设计一个可扩展的解析框架,核心思路如下:
-
统一解析接口:定义
parseFn类型函数,接收字符串并返回map[string]string和错误; -
按格式实现解析器:
-
parseFormat1:按,切分字段,再对每个字段用=拆分键值,并用strings.Trim(field, " \"")自动清除键和值两端可能存在的空格与双引号; -
parseFormat2:按空格切分(适用于无逗号格式),其余逻辑一致;
-
-
智能格式识别:通过
classify()函数根据逗号/空格出现频次自动选择解析器(生产环境建议改用更鲁棒的检测逻辑,如正则匹配=\w+或="[^"]+"); -
JSON 安全序列化:
json.Marshal()自动处理所有转义(如age="12"中的引号会被转义为\"12\",若需去除引号则Trim已完成)。
以下是完整、可直接运行的示例代码:
package main
import (
"encoding/json"
"errors"
"fmt"
"strings"
)
type parseFn func(string) (map[string]string, error)
func parseFormat1(in string) (map[string]string, error) {
data := make(map[string]string)
for _, field := range strings.Split(in, ",") {
pair := strings.Split(strings.TrimSpace(field), "=")
if len(pair) != 2 {
return nil, errors.New("invalid field format: missing '=' or extra '='")
}
key := strings.TrimSpace(pair[0])
val := strings.TrimSpace(pair[1])
// 移除值两端的双引号(支持 "12" → 12,也兼容无引号场景)
data[key] = strings.Trim(val, `"`)
}
return data, nil
}
func parseFormat2(in string) (map[string]string, error) {
data := make(map[string]string)
for _, field := range strings.Fields(in) { // strings.Fields 自动按任意空白符分割,更健壮
pair := strings.Split(field, "=")
if len(pair) != 2 {
return nil, errors.New("invalid field format: missing '='")
}
key := strings.TrimSpace(pair[0])
val := strings.TrimSpace(pair[1])
data[key] = strings.Trim(val, `"`)
}
return data, nil
}
func classify(in string) parseFn {
if strings.Contains(in, ",") {
return parseFormat1
}
return parseFormat2 // 默认按空格分割
}
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 pan" age="25"`,
}
for i, input := range testCases {
parser := classify(input)
parsed, err := parser(input)
if err != nil {
fmt.Printf("❌ Line %d (%q): parse error — %v\n", i+1, input, err)
continue
}
jsonBytes, err := json.Marshal(parsed)
if err != nil {
fmt.Printf("❌ Line %d (%q): marshal error — %v\n", i+1, input, err)
continue
}
fmt.Printf("✅ Line %d: %q → %s\n", i+1, input, string(jsonBytes))
}
}关键注意事项:
- ✅
strings.Fields()比strings.Split(in, " ")更可靠,能正确处理多个连续空格或首尾空格; - ✅
strings.Trim(val, "\"")安全移除值两端的双引号,不影响内部引号(如name="peter pan"→"peter pan"); - ⚠️ 若原始值中存在需保留的内部双引号(如
desc="He said \"Hi\""),则需改用更高级解析(如strconv.Unquote),但本例需求明确为“去掉首尾引号”,故Trim已足够; - ? 绝对避免用正则直接生成 JSON 字符串——它无法保证 UTF-8 安全性、特殊字符转义(
\n,\t,, <code>&等)及结构合法性,违反 Go 的“显式优于隐式”哲学。
最终输出均为标准 JSON:{"id":"1","name":"peter","age":"12"}{"id":"1","name":"peter","age":"25"}{"id":"1","name":"peter pan","age":"25"}
此方案兼顾简洁性、可维护性与生产安全性,是处理此类非结构化键值输入的 Go 最佳实践。


















