Превращение файла со строковым ключом / значениями в карту Go - PullRequest
0 голосов
/ 20 апреля 2019

У меня есть файл, который содержит пары ключ / значение строки, разделенные знаком =. Это выглядит так:

"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

Ответы [ 3 ]

3 голосов
/ 20 апреля 2019

Другой подход. Вы можете использовать сканер с пользовательской функцией разделения , чтобы разделить по разделителю вашей пары ; и отсканировать каждую отдельную пару ключей. Затем разделите текст пары «ключ-значение» на «-», чтобы разделить ключи и значения.

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
}
1 голос
/ 20 апреля 2019

Я думаю (?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.

1 голос
/ 20 апреля 2019

^"(.+?)(?<!\\)"\s*=\s*"([\s\S]*?)(?<!\\)"; сопоставляет ключи и значения в двух группах, предполагая, что они все имеют форму "key" = "value";.Ключи и значения могут иметь кавычки.Пустые ключи не совпадают.

Затем можно заменить \\\n в значениях на \n для значений, которые охватывают несколько строк.

Я использую отрицательный взгляд за (?<!\\), чтобы убедиться, что кавычкам не предшествует обратная косая черта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...