为了账号安全,请及时绑定邮箱和手机立即绑定

Golang:从文本文件中读取无效的 JSON

Golang:从文本文件中读取无效的 JSON

Go
呼如林 2021-10-04 16:06:43
我有一个包含以下示例数据的 txt 文件:host{      Entry {          id: "foo"      }       Entry {          id: "bar"      }    }port{      Entry {          id: "lorem"      }       Entry {          id: "ipsum"      }    }它有 +300 的条目值。我想读取文件并提取属于端口部分的id值。它不是有效的 JSON,所以我不能使用 json 解码器,还有其他提取值的方法吗?
查看完整描述

2 回答

?
喵喔喔

TA贡献1735条经验 获得超5个赞

如果结构始终相同并且您想要的只是 id 值,您可以执行以下操作(在 Playground 上):


package main


import (

    "fmt"

    "strings"

)


func main() {

    // This will work only if ids don't have spaces

    fields := strings.Fields(input1)

    for i, field := range fields {

        if field == "id:" {

            fmt.Println("Got an id: ", fields[i+1][1:len(fields[i+1])-1])

        }

    }

    fmt.Println()


    // This will extract all strings enclosed in ""

    for i1, i2 := 0, 0;; {

        i := strings.Index(input2[i1:], "\"") // find the first " starting after the last match

        if i > 0 { // if we found one carry on

            i1 = i + 1 + i1 // set the start index to the absolute position in the string

            i2 = strings.Index(input2[i1:], "\"") // find the second "

            fmt.Println(input2[i1 : i1+i2]) // print the string between ""

            i1 += i2 + 1 // set the new starting index to after the last match

        } else { // otherwise we are done

            break

        }

    }



    // Reading the text line by line and only processing port sections

    parts := []string{"port{", "  Entry {", "      id: \"foo bar\"", "  }", "   Entry {", "      id: \"more foo bar\"", "  }", "}"}        

    isPortSection := false

    for _, part := range parts {

        if string.HasPrefix(part, "port"){

            isPortSection = true

        }

        if string.HasPrefix(part, "host"){

            isPortSection = false

        }

        if isPortSection && strings.HasPrefix(strings.TrimSpace(part),"id:") {

            line := strings.TrimSpace(part)

            fmt.Println(line[5:len(line)-1])

        }

    }

}


var input1 string = `port{

  Entry {

      id: "foo"

  }

   Entry {

      id: "bar"

  }

}`


var input2 string = `port{

  Entry {

      id: "foo bar"

  }

   Entry {

      id: "more foo bar"

  }

}`

印刷:


Got an id:  foo

Got an id:  bar


foo bar

more foo bar

您可以将它们粘贴到切片或地图中,或者做任何您想做/需要做的事情,而不是在循环中打印它们。当然,而不是使用您在文件行中读取的字符串文字。


查看完整回答
反对 回复 2021-10-04
?
HUWWW

TA贡献1874条经验 获得超12个赞

我相信text/scanner在这里可能非常有用。它不是即插即用,但允许您标记输入并很好地解析您的字符串(空格、转义值等)。概念的快速证明,带有简单状态机的扫描仪,用于捕获分段中的所有id: {str}模式Entry:


var s scanner.Scanner

s.Init(strings.NewReader(src))


// Keep state of parsing process

const (

    StateNone = iota

    StateID

    StateIDColon

)

state := StateNone


lastToken := ""        // last token text

sections := []string{} // section stack


tok := s.Scan()

for tok != scanner.EOF {

    txt := s.TokenText()

    switch txt {

    case "id":

        if state == StateNone {

            state = StateID

        } else {

            state = StateNone

        }

    case ":":

        if state == StateID {

            state = StateIDColon

        } else {

            state = StateNone

        }

    case "{":

        // Add section

        sections = append(sections, lastToken)

    case "}":

        // Remove section

        if len(sections) > 0 {

            sections = sections[0 : len(sections)-1]    

        }

    default:

        if state == StateIDColon && sections[0] == "port" {

            // Our string is here

            fmt.Println(txt)

        }

        state = StateNone

    }

    lastToken = txt

    tok = s.Scan()

}

你可以在这里玩。如果您需要验证输入结构等,这肯定需要更多的工作,但对我来说似乎是一个很好的起点。


查看完整回答
反对 回复 2021-10-04
  • 2 回答
  • 0 关注
  • 192 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信