Разбить входную строку в го по регулярному выражению - PullRequest
0 голосов
/ 06 ноября 2018

Как я могу разделить входные строки ниже с помощью регулярных выражений в Go? Примеры строк:

Я знаю, как делить на точки, но как мне избежать разбиения в кавычках?

"a.b.c.d" -> ["a", "b", "c", "d"]
"a."b.c".d" -> ["a", "b.c", "d"]
"a.'b.c'.d" -> ["a", "b.c", "d"]

Ответы [ 3 ]

0 голосов
/ 06 ноября 2018

Сопоставление сбалансированных разделителей - сложная проблема для регулярных выражений, о чем свидетельствует ответ Джона . Если вы не используете что-то вроде Go pcre пакета .

Вместо него можно адаптировать Go CSV-парсер . Настройте его на использование . в качестве разделителя, ленивых кавычек (CSV-кавычка ') и записей переменной длины.

package main

import (
    "encoding/csv"
    "fmt"
    "io"
    "log"
    "strings"
)

func main() {
    lines := `a.b.c.d
a.\"b.c\".d
a.'b.c'.d
`

    csv := csv.NewReader(strings.NewReader(lines))
    csv.Comma = '.'
    csv.LazyQuotes = true
    csv.FieldsPerRecord = -1
    for {
        record, err := csv.Read()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }

        fmt.Printf("%#v\n", record)
    }
}
0 голосов
/ 06 ноября 2018

Вот еще один вариант с несколько менее хакерским регулярным выражением. Он использует трюк с мусорным баком . Таким образом, реальные данные по (первой и второй) группам захвата.

Он работает даже с вложенными кавычками, такими как: "a.'b.c'.d.e."f.g.h"", если нет рекурсии из 2 или более уровней (как здесь: "a.'b."c.d"'", кавычки внутри кавычек внутри кавычек).

Это регулярное выражение: ^"|['"](\w+(?:\.\w+)*)['"]|(\w+)

И код:

package main

import (
    "regexp"
    "fmt"
)

func main() {
    var re = regexp.MustCompile(`^"|['"](\w+(?:\.\w+)*)['"]|(\w+)`)
    var str = `"a.'b.c'.d.e."f.g.h""`

    result := re.FindAllStringSubmatch(str, -1)
    for _, m := range result {
        if (m[1] != "" || m[2] != "") {
            fmt.Print(m[1] + m[2] + "\n")
        }
    }
}

Input:

"a.'b.c'.d.e."f.g.h""

Выход:

a
b.c
d
e
f.g.h
0 голосов
/ 06 ноября 2018

Поскольку go не поддерживает негативные запросы, я не думаю, что найти регулярное выражение, соответствующее ., на которое вы хотите разбить, будет легко / возможно. Вместо этого вы можете сопоставить окружающий текст и захватывать только соответствующим образом:

Так что само регулярное выражение немного уродливо, но вот разбивка (игнорирование экранированных символов для go):

(\'[^.'"]+(?:\.[^.'"]+)+\')|(\"[^.'"]+(?:\.[^.'"]+)+\")|(?:([^.'"]+)\.?)|(?:\.([^.'\"]+))

Существует четыре сценария, которым соответствует это регулярное выражение, и фиксируются определенные подмножества этих совпадений:

  • (\'[^.'"]+(?:\.[^.'"]+)+\') - сопоставление и захват текста в одинарных кавычках
    • \' - Совпадение ' буквально
    • [^.'"]+ - совпадение последовательности без кавычек и непериодов
    • (?:\.[^.'"]+)+ - Соответствует периоду, за которым следует последовательность без кавычек и непериодов, повторяемая столько раз, сколько необходимо. Не пойман.
    • \' - Совпадение ' буквально
  • (\"[^.'"]+(?:\.[^.'"]+)+\") - сопоставление и захват текста в двойных кавычках
    • То же, что и выше, но с двойными кавычками
  • (?:([^.'"]+)\.?) - сопоставить текст с необязательным ., не захватывая .
    • ([^.'"]+) - Совпадение и захват последовательности без кавычек и непериодов
    • \.? - При желании сопоставить точку (необязательно, чтобы захватить последний бит текста с разделителями)
  • (?:\.([^.'"]+)) - Соответствует тексту, которому предшествует ., не захватывая .
    • То же, что и выше, но с периодом, предшествующим группе захвата, а также необязательным

Пример кода, который выводит снимки:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile("('[^.'\"]+(?:\\.[^.'\"]+)+')|(\"[^.'\"]+(?:\\.[^.'\"]+)+\")|(?:([^.'\"]+)\\.?)|(?:\\.([^.'\"]+))")
    txt := "a.b.c.'d.e'"

    result:= re.FindAllStringSubmatch(txt, -1)

    for k, v := range result {
        fmt.Printf("%d. %s\n", k, v)
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...