【问题标题】:Golang replace all whitespace not between quotesGolang替换引号之间的所有空格
【发布时间】:2020-05-08 00:47:12
【问题描述】:

我读了this 引用关于替换引号之间的所有空格,但我最近开始使用golang,它说golang 不支持perl 类型正则表达式。有什么方法可以使用正则表达式替换 golang 中的所有空格。

如果有办法只使用正则表达式,我将不胜感激。

例子:

A B " C" -> AB" C"
A B ' C' -> AB' C'
A B ` C` -> AB` C`

A B \'C\' -> AB\'C\'
A B '\` C \`' -> AB'\` C \`'
A B "\' C C \"\'\"" -> AB"\' C C \"\'\""

【问题讨论】:

  • 我怀疑由于缺乏后向支持,您可能会获得 100% 安全的纯 Go 正则表达式解决方案。 This demo 在大多数情况下都可以完成这项工作:regexp.MustCompile(`(?s)"[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*'|` + "`[^`\\\\]*(?:\\\\.[^`\\\\]*)*`" + `|\s+`) 然后r.ReplaceAllStringFunc(test, func(m string) string { if (strings.TrimSpace(m) == "") { return "" } else { return m } })
  • 即使 RE2 支持前瞻和后瞻,像\s+(?=((\\[\\"]|[^\\"])*"(\\[\\"]|[^\\"])*")*(\\[\\"]|[^\\"])*$) 这样的东西怎么比几行程序代码更容易理解。为代码的未来读者编写代码,而不是为了一些最少行的虚荣指标。

标签: regex go


【解决方案1】:

替换引号之间的所有空格。

例子:

A B " C" -> AB" C"
A B ' C' -> AB' C'
A B ` C` -> AB` C`

A B \'C\' -> AB\'C\'
A B '\` C \`' -> AB'\` C \`'
A B "\' C C \"\'\"" -> AB"\' C C \"\'\""

代码必须正确,而且要正确,代码必须是可读的。到目前为止,还没有提供正确或可读的正则表达式解决方案。


在 Go 中解析文本。

例如,

package main

import (
    "fmt"
    "unicode"
)

// Remove all whitespace not between matching unescaped quotes.
func removeUnquotedSpace(s string) (string, error) {
    rs := make([]rune, 0, len(s))
    const out = rune(0)
    var quote rune = out
    var escape = false
    for _, r := range s {
        if !escape {
            if r == '`' || r == '"' || r == '\'' {
                if quote == out {
                    // start unescaped quote
                    quote = r
                } else if quote == r {
                    // end (matching) unescaped quote
                    quote = out
                }
            }
        }
        // backslash (\) is the escape character
        // except when it is the second backslash of a pair
        escape = !escape && r == '\\'
        if quote != out || !unicode.IsSpace(r) {
            // between matching unescaped quotes
            // or not whitespace
            rs = append(rs, r)
        }
    }
    if quote != out {
        err := fmt.Errorf("unmatched unescaped quote: %q", quote)
        return "", err
    }
    return string(rs), nil
}

func main() {
    tests := []struct {
        in, out string
    }{
        {`A B " C"`, `AB" C"`},
        {"A B ' C'", "AB' C'"},
        {"A B ` C`", "AB` C`"},
        {`A B \'C\'`, `AB\'C\'`},
        {"A B '\\` C \\`'", "AB'\\` C \\`'"},
        {`A B "\' C C \"\'\""`, `AB"\' C C \"\'\""`},

        {`A B " C \\"`, `AB" C \\"`},
    }
    for _, tt := range tests {
        out, err := removeUnquotedSpace(tt.in)
        fmt.Printf(
            "|| %v || %v || %v || %v\n",
            tt.in, out, out == tt.out, err,
        )
    }
}

游乐场:https://play.golang.org/p/-3cDwSaakIb

输出:

|| A B " C" || AB" C" || true || <nil>
|| A B ' C' || AB' C' || true || <nil>
|| A B ` C` || AB` C` || true || <nil>
|| A B \'C\' || AB\'C\' || true || <nil>
|| A B '\` C \`' || AB'\` C \`' || true || <nil>
|| A B "\' C C \"\'\"" || AB"\' C C \"\'\"" || true || <nil>
|| A B " C \\" || AB" C \\" || true || <nil>

【讨论】:

    【解决方案2】:

    Go 的内置正则表达式使用 RE2,它速度快且具有很多功能,但缺少很多重要的功能,例如前瞻和后视。

    幸运的是,您可以使用pcre (Perl Compatible Regular Expressions) Go library。现在正则表达式可以工作了。

    package main
    
    import(
        "github.com/glenn-brown/golang-pkg-pcre/src/pkg/pcre"
        "fmt"
    );
    
    func main() {
        re := pcre.MustCompile(`\s+(?=((\\[\\"]|[^\\"])*"(\\[\\"]|[^\\"])*")*(\\[\\"]|[^\\"])*$)`, 0)
    
        string := `A B " \"C \"" D`
        replaced := re.ReplaceAll([]byte(string), []byte(``), 0);
        fmt.Printf("%s", replaced);
    }
    

    【讨论】:

    • 使用 PCRE,它变得更容易并且不那么压倒性,但是 \s+(?=((\\[\\"]|[^\\"])*"(\\[\\"]|[^\\"])*")*(\\[\\"]|[^\\"])*$) 模式不会完成所有工作并且不会做得很好,因为它不支持正确转义的引号并且不支持OP提到的所有三种“引号”。
    • 当我尝试将它与go get 一起使用时,我收到此错误cc1.exe: sorry, unimplemented: 64-bit mode not compiled in
    • 此外,这个正则表达式不符合我的要求,它不适用于 ` 或 '
    • @the 那是你说你想从另一个答案中使用的正则表达式。现在有了可用的 PCRE,您可以从其他提出相同问题的问题中找到更适用的正则表达式,不需要特定于 Go 的正则表达式。至于go get的问题,我不知道。
    猜你喜欢
    • 1970-01-01
    • 2014-10-31
    • 2014-12-11
    • 1970-01-01
    • 2012-12-17
    • 1970-01-01
    • 2023-03-07
    • 2019-01-06
    • 1970-01-01
    相关资源
    最近更新 更多