regex.ReplaceAll but add same amount of characters if replaces

huangapple go评论86阅读模式
英文:

regex.ReplaceAll but add same amount of characters if replaces

问题

我想要一个正则表达式匹配替换,它将替换的字符数与替换和缺失的字符数进行比较,并用空格键替换缺失的字符。

我想要实现的更大目标是拥有一个带有字段和边框的模板,这些字段可能会更改(因此某些字段中可用的字符数可能不同),而不是硬编码,我希望将接受的字符数量留给用户决定。

我的正则表达式语句:\[\s{0,}\w{1,}\s{0,}\]

带有正则表达式占位符的示例模板:

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

现在,我想要替换它,以保持文档结构:

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

然而,通过正则表达式替换后,我得到了破坏文档结构的结果:

___________________________________________________________________
| 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 库或其他方法?

英文:

I would like to have a regex match replace that compares the number of replaced characters with the ones that are replacement and the missing ones have, say, a spacebar instead.

The bigger picture what I want to achieve is to have a template with fields and borders, which might be changed (therefore number of characters available in certain fields might be different) and instead of hardcoding it I would like to leave amount of accepted characters up to the user.

My regular expression statement: \[\s{0,}\w{1,}\s{0,}\]

Example template with placeholders for regex:

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

Now, I would like to replace it for something like that to keep the document structure:

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

What I get after regex replace though is that, which breaks my document structure

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

And here's my code:

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

	return re.ReplaceAllString(t, value)
}

Do you know any golang library or other way that would allow me to achieve something similar?

答案1

得分: 0

如果你不想使用正则表达式,可以这样做。

func replaceField(text string, label string, value string) string {
    newText := strings.ReplaceAll(text, "["+label+"]", 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
}
英文:

If you can use other than regex. You can do it like this.

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

    return newText
}

答案2

得分: 0

你可以通过将原来的正则表达式放在括号中来创建一个分组/子匹配。在这个例子中,我们可以看到匹配正则表达式的整个字符串,然后是匹配的两个组 (x*) 和/或 (y|z)

这是你原来的正则表达式加上括号的写法:

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

这是一个更简洁的写法:我使用了反引号作为字符串字面量,这样我就不必使用双斜杠了,并且我用 * 替换了 {0,},因为两者都表示“0个或多个(任意)空格”:

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

现在,当我们调用 FindStringSubmatch 时,我们会得到类似下面的结果:

template := "| [ test1    ] | [ test2 ] ..."
re := regexp.MustCompile(`(\[\s*test1\s*\])`)
fmt.Printf("%q\n", re.FindStringSubmatch(template))

re = regexp.MustCompile(`(\[\s*test2\s*\])`)
fmt.Printf("%q\n", re.FindStringSubmatch(template))
["[ test1    ]" "[ test1    ]"]
["[ test2 ]" "[ test2 ]"]

现在我们知道了匹配正则表达式的字符串的长度,我们可以用这个长度减去新字符串的长度来计算需要填充新字符串的空格数。

这是一个小而完整的示例:

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                           |
英文:

You can change your regular expression to create a grouping/submatch by wrapping what you had in parentheses. Check out the example here, first, <https://pkg.go.dev/regexp#example-Regexp.FindStringSubmatch>.

In the example output:

[&quot;axxxbyc&quot; &quot;xxx&quot; &quot;y&quot;]
[&quot;abzc&quot; &quot;&quot; &quot;z&quot;]

we can see the entire string that matched the regular expression followed by any of the two groups that matched, (x*) and/or (y|z).

Here's your original regexp wrapped in parentheses:

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

and here's a cleaner way to write that: I'm using a backquote for a string literal so I don't have to do double slashes, and I've replaced {0,} with * because both mean "0-or-more (any) whitespace":

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

now, when we call FindStringSubmatch, we'll get something like:

template := &quot;| [ test1    ] | [ test2 ] ...&quot;
re := regexp.MustCompile(`(\[\s*test1\s*\])`)
fmt.Printf(&quot;%q\n&quot;, re.FindStringSubmatch(template))

re = regexp.MustCompile(`(\[\s*test2\s*\])`)
fmt.Printf(&quot;%q\n&quot;, re.FindStringSubmatch(template))
[&quot;[ test1    ]&quot; &quot;[ test1    ]&quot;]
[&quot;[ test2 ]&quot; &quot;[ test2 ]&quot;]

Now we know the length of the thing that matched the regular expression, and we can use that length minus the length of the new thing to figure how many spaces are needed to pad the new thing.

Here's a small, complete example:

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

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

		for _, field := range fields {
			// Dynamically build re
			label := fmt.Sprintf(&quot;test%d&quot;, 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(&quot; &quot;, lenTest-lenLabel)
			final := field.label + padding

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

which prints:

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


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

huangapple
  • 本文由 发表于 2023年1月18日 10:24:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/75154142.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定