【问题标题】:Turning a file with string key/values into a Go map将带有字符串键/值的文件转换为 Go 映射
【发布时间】:2019-04-20 15:41:59
【问题描述】:

我有一个文件,其中包含由= 符号分隔的字符串键/值对。它看起来像这样:

"some.key" = "A cool value.";
"some.other.key" = "A cool value with %@ chars and \n. Another Thing.";
"escaped.key" = "A cool \"value\".";
"multiline.key.value" = "1. First sentence is "cool"\
2. Second sentence\
3. Third sentence\
4. Fourth sentence";

请注意,一个值可以在其中包含转义引号,并且它们也可以跨越多行。

我已经尝试过基本的引号匹配,但它不处理值中的转义引号等...这是我目前正在尝试的:

file, err := ioutil.ReadFile("/my/string/file")
if err != nil {
    log.Fatal(err)
}

re := regexp.MustCompile(`".*?"`)
match := re.FindAllString(string(file), -1)
fmt.Println(match)

任何帮助将不胜感激:D

【问题讨论】:

    标签: regex go


    【解决方案1】:

    另一种方法 - 您可以使用带有自定义 split function 的扫描仪,通过配对分隔符 ; 进行拆分,并扫描每个单独的密钥对。然后用“-”分割键值对文本来分割你的键和值。

    file, err := os.Open("/my/string/file")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    
    scanner := bufio.NewScanner(f)
    scanner.Split(customSplitFunc)
    for scanner.Scan() {
        fmt.Println("Key-Value Pair: ", scanner.Text())
        //Split scanner.Text() by "=" to split key and value
    }
    

    并定义customSplitFunc如下

    func customSplitFunc(data []byte, atEOF bool) (advance int, token []byte, err error) {
        if atEOF && len(data) == 0 {
            return 0, nil, nil
        }
    
        if atEOF {
            return len(data), data, nil
        }
    
        //; followed by newline is the k-v pair delimiter
        if i := strings.Index(string(data), ";\n"); i >= 0 {
            //skip the delimiter in advancing to the next pair
            return i + 2, data[0:i], nil
        }
        return
    }
    

    【讨论】:

    • 好主意!但是有一个问题:在自定义拆分功能之后,我的数据是这样的:``` /* A comment */ "key" = "value" ``` 对它执行 string.split 不起作用,如果值在多行上,scanner.Text() 只返回其中的 1 行 :(
    【解决方案2】:

    ^"(.+?)(?<!\\)"\s*=\s*"([\s\S]*?)(?<!\\)"; 匹配两组中的键和值,假设它们都采用"key" = "value"; 的形式。键和值可以有转义引号。空键不匹配。

    然后,对于跨多行的值,您可以将值中的 \\\n 替换为 \n

    我在 (?<!\\) 后面使用否定外观来确保引号前面没有反斜杠。

    【讨论】:

      【解决方案3】:

      我认为(?m)^"([^"]+)"\s*=\s*"(([^"]|(\\")|(\\\n))+)";$ 可以满足您的需求。 将其与FindAllStringSubmatch 一起使用,它将返回所有匹配的对。请注意,如果任何输入的语法无效,则整个内容将不匹配,因此这可能不是您想要的。

      func main() {
          re := regexp.MustCompile(`(?m)^"([^"]+)"\s*=\s*"(([^"]|(\\")|(\\\n))+)";$`)
          matches := re.FindAllStringSubmatch(`"some.key" = "A cool value.";
      "some.other.key" = "A cool value with %@ chars and \n. Another Thing.";
      "escaped.key" = "A cool \"value\".";
      "multiline.key.value" = "1. First sentence is \"cool\"\
      2. Second sentence\
      3. Third sentence\
      4. Fourth sentence";
      `, -1)
          for _, m := range matches {
              fmt.Printf("%q %q\n", m[1], m[2])
          }
      }
      

      (我在您输入的第四行添加了缺少的反斜杠。)

      https://play.golang.org/p/ZHV8jpg17nY

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-13
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多