如何使用Go语言将非标准格式字符串转换为合法JSON结构?
解决非标准类JSON格式的解析问题(Go语言)
方案一:预处理为合法JSON后解析
这种方法适合格式相对固定的场景,先把非标准格式转换成合法JSON,再用Go标准库的encoding/json解析,新手更容易上手。
关键转换步骤
- 给所有键名(如
timestamp、content、elem等)添加双引号 - 给字符串类型的值(如
demoproj、default等)添加双引号,数字值保留原样 - 将重复的
elem字段合并为JSON数组
Go示例代码
package main import ( "encoding/json" "fmt" "io/ioutil" "regexp" ) // 定义对应的数据结构体 type Key struct { Key string `json:"key"` Value string `json:"value"` } type Elem struct { Name string `json:"name"` Key *Key `json:"key,omitempty"` // 字段为空时不参与序列化 } type Content struct { Origin string `json:"origin"` Elem []Elem `json:"elem"` } type MyData struct { Timestamp int64 `json:"timestamp"` Content Content `json:"content"` } type Root struct { MyData MyData `json:"mydata"` } func main() { // 1. 读取目标文件 data, err := ioutil.ReadFile("your_data.txt") // 替换为你的文件路径 if err != nil { fmt.Printf("读取文件失败: %v\n", err) return } rawStr := string(data) // 2. 预处理转换为合法JSON // 给键名添加双引号 reKey := regexp.MustCompile(`(\w+):`) rawStr = reKey.ReplaceAllString(rawStr, `"$1":`) // 给字符串值添加双引号(跳过数字) reStrValue := regexp.MustCompile(`: (\w+)(?=\s|})`) rawStr = reStrValue.ReplaceAllStringFunc(rawStr, func(s string) string { if regexp.MustCompile(`: \d+`).MatchString(s) { return s } return regexp.MustCompile(`: (\w+)`).ReplaceAllString(s, ": \"$1\"") }) // 将重复elem字段转为数组 rawStr = regexp.MustCompile(`"elem": {`).ReplaceAllString(rawStr, `"elem": [`, 1) rawStr = regexp.MustCompile(`}, "elem": {`).ReplaceAllString(rawStr, "}, {") rawStr = regexp.MustCompile(`}\s*}`).ReplaceAllString(rawStr, "]}") // 处理根节点为合法JSON结构 rawStr = regexp.MustCompile(`mydata ({.*})`).ReplaceAllString(rawStr, `"mydata": $1`) rawStr = fmt.Sprintf("{%s}", rawStr) // 3. 解析JSON到结构体 var root Root err = json.Unmarshal([]byte(rawStr), &root) if err != nil { fmt.Printf("解析JSON失败: %v\n", err) fmt.Println("预处理后的JSON:", rawStr) return } // 打印解析结果 fmt.Printf("解析成功:\n%+v\n", root) }
方案二:自定义递归下降解析器
如果格式变动较大,预处理容易出错,可以手写解析器,通过逐词扫描直接处理结构。
核心思路
- 使用
bufio.Scanner读取并分词(识别大括号、冒号、标识符、数字等) - 递归解析嵌套结构,直接填充到目标结构体中
Go示例代码(简化版)
package main import ( "bufio" "fmt" "os" "strconv" ) type Key struct { Key string Value string } type Elem struct { Name string Key *Key } type Content struct { Origin string Elem []Elem } type MyData struct { Timestamp int64 Content Content } // 分词器 type tokenizer struct { scanner *bufio.Scanner current string } func newTokenizer(file *os.File) *tokenizer { scanner := bufio.NewScanner(file) scanner.Split(bufio.ScanWords) t := &tokenizer{scanner: scanner} t.next() return t } func (t *tokenizer) next() { if t.scanner.Scan() { t.current = t.scanner.Text() } else { t.current = "" } } func (t *tokenizer) expect(s string) error { if t.current != s { return fmt.Errorf("期望'%s',实际得到'%s'", s, t.current) } t.next() return nil } // 解析Key结构 func parseKey(t *tokenizer) (*Key, error) { key := &Key{} if err := t.expect("key:"); err != nil { return nil, err } key.Key = t.current t.next() if err := t.expect("value:"); err != nil { return nil, err } key.Value = t.current t.next() return key, nil } // 解析Elem结构 func parseElem(t *tokenizer) (*Elem, error) { elem := &Elem{} if err := t.expect("name:"); err != nil { return nil, err } elem.Name = t.current t.next() if t.current == "key" { t.next() if err := t.expect("{"); err != nil { return nil, err } k, err := parseKey(t) if err != nil { return nil, err } elem.Key = k if err := t.expect("}"); err != nil { return nil, err } } return elem, nil } // 解析Content结构 func parseContent(t *tokenizer) (*Content, error) { content := &Content{} if err := t.expect("origin:"); err != nil { return nil, err } content.Origin = t.current t.next() for t.current == "elem" { t.next() if err := t.expect("{"); err != nil { return nil, err } elem, err := parseElem(t) if err != nil { return nil, err } content.Elem = append(content.Elem, *elem) if err := t.expect("}"); err != nil { return nil, err } } return content, nil } // 解析MyData结构 func parseMyData(t *tokenizer) (*MyData, error) { mydata := &MyData{} if err := t.expect("timestamp:"); err != nil { return nil, err } ts, err := strconv.ParseInt(t.current, 10, 64) if err != nil { return nil, fmt.Errorf("解析timestamp失败: %v", err) } mydata.Timestamp = ts t.next() if err := t.expect("content"); err != nil { return nil, err } t.next() if err := t.expect("{"); err != nil { return nil, err } content, err := parseContent(t) if err != nil { return nil, err } mydata.Content = *content if err := t.expect("}"); err != nil { return nil, err } return mydata, nil } func main() { file, err := os.Open("your_data.txt") if err != nil { fmt.Printf("打开文件失败: %v\n", err) return } defer file.Close() t := newTokenizer(file) if t.current != "mydata" { fmt.Println("无效格式:根节点不是mydata") return } t.next() if err := t.expect("{"); err != nil { fmt.Printf("解析失败: %v\n", err) return } mydata, err := parseMyData(t) if err != nil { fmt.Printf("解析失败: %v\n", err) return } if err := t.expect("}"); err != nil { fmt.Printf("解析失败: %v\n", err) return } fmt.Printf("解析成功:\n%+v\n", mydata) }
内容的提问来源于stack exchange,提问作者Developer
相关产品推荐
相关产品推荐

