Go语言 regex.ReplaceAll,但在替换时添加相同数量的字符

lokaqttq  于 2023-01-22  发布在  Go
关注(0)|答案(2)|浏览(137)

我希望有一个正则表达式匹配替换,比较被替换的字符数与被替换的字符数,丢失的字符有,比如说,一个空格键。
更大的图片我想实现的是有一个带有字段和边框的模板,这可能会改变(因此某些字段中可用的字符数可能会不同),而不是硬编码它,我想让用户接受的字符数量。
我的正则表达式语句:\[\s{0,}\w{1,}\s{0,}\]
带有正则表达式占位符的示例模板:

| [ test1     ] | [ test2 ] | [         test3                   ] |

现在,我想将其替换为类似的内容,以保持文档结构:

___________________________________________________________________
| Test 1 value  | Test2 v.. | Test3 value                         |
|               |           |                                     |

在regex replace之后,我得到的是,它破坏了我的文档结构

___________________________________________________________________
| Test 1 value | Test2 value | Test3 value |
|               |           |                                     |

下面是我的代码:

func replaceField(text string, label string, value string) string {
    re := regexp.MustCompile("\\[\\s{0,}" + label + "\\s{0,}\\]")

    return re.ReplaceAllString(t, value)
}

你知道任何golang库或其他方式,将允许我实现类似的东西?

ruarlubt

ruarlubt1#

你可以改变你的正则表达式来创建一个分组/子匹配,方法是把你的内容放在圆括号里。首先,看看这里的例子,www.example.com。https://pkg.go.dev/regexp#example-Regexp.FindStringSubmatch.
在示例输出中:

["axxxbyc" "xxx" "y"]
["abzc" "" "z"]

我们可以看到匹配正则表达式的整个字符串后跟匹配的两个组(x*)和/或(y|z)中的任何一个。
下面是用括号括起来的原始regexp:

re := regexp.MustCompile("(\\[\\s{0,}" + label + "\\s{0,}\\])")

这里有个更简洁的写法我用反引号来表示字符串,这样就不必使用双斜线,而且我用*替换了{0,},因为它们都表示"0或更多(* any *)空格":

re := regexp.MustCompile(`(\[\s*` + label + `\s*\])`)

现在,当我们调用FindStringSubmatch时,我们会得到如下的结果:
一个三个三个一个
现在我们知道了与正则表达式匹配的内容的长度,我们可以使用该长度减去新内容的长度来计算需要多少空格来填充新内容。
下面是a small, complete example

func main() {
    type Field struct {
        num   int
        label string
    }
    type Fields []Field

    for _, fields := range []Fields{
        {
            {1, "Foo1"},
            {2, "Foo2"},
            {3, "Foo3"},
        },
        {
            {1, "FooBar1"},
            {2, "FooBar2"},
            {3, "FooBar3"},
        },
    } {
        var template = `
            ___________________________________________________________________
            | [ test1     ] | [ test2 ] | [         test3                   ] |
            | control 1     | control 2 | control 3                           |
            `

        for _, field := range fields {
            // Dynamically build re
            label := fmt.Sprintf("test%d", field.num)
            re := regexp.MustCompile(`(\[\s*` + label + `\s*\])`)

            // Find string that satisfies re
            test := re.FindStringSubmatch(template)[0]

            // Pad to len of test
            lenTest := utf8.RuneCountInString(test)
            lenLabel := utf8.RuneCountInString(field.label)
            padding := strings.Repeat(" ", lenTest-lenLabel)
            final := field.label + padding

            // Insert final label into template
            template = strings.Replace(template, test, final, -1)
        }
        fmt.Println(template)
    }
}

其打印:

___________________________________________________________________
| Foo1          | Foo2      | Foo3                                |
| control 1     | control 2 | control 3                           |

___________________________________________________________________
| FooBar1       | FooBar2   | FooBar3                             |
| control 1     | control 2 | control 3                           |
kuarbcqp

kuarbcqp2#

如果可以使用regex以外的其他方法,可以这样做。

func replaceField(text string, label string, value string) string {
    re := regexp.MustCompile("\\[\\s{0,}" + label + "\\s{0,}\\]")
    newText := re.ReplaceAllString(text, value)
    if len(newText) > len(text) {
        newText = newText[:len(text)-2] + ".."
    }
    if len(newText) < len(text) {
        lenDiff := len(text) - len(newText)
        for i := 0; i < lenDiff; i++ {
            newText += " "
        }
    }

    return newText
}

相关问题