通过正则表达式在go中拆分输入字符串

时间:2018-11-06 17:14:17

标签: regex go

如何在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 :(得分:1)

由于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)
    }
}

答案 1 :(得分:1)

匹配正则表达式是一个复杂的问题,John's answer证明了这一点。除非您使用的是Go pcre package之类的东西。

可以改编Go CSV parser。配置它以使用.作为分隔符,惰性引号(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)
    }
}

答案 2 :(得分:1)

这是另一种选项,它的正则表达式稍微有些黑。它使用trash bin trick。因此,实际数据位于(第一个和第二个)捕获组上。

它甚至适用于嵌套引号:ng build --prod ,只要不存在2或更高级别的递归即可(如此处:"a.'b.c'.d.e."f.g.h"",引号内的引号在引号内)。

正则表达式是:"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") } } }

输出:

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