Home > other >  regex.ReplaceAll but add same amount of characters if replaces
regex.ReplaceAll but add same amount of characters if replaces

Time:01-18

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?

CodePudding user response:

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("\\[\\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
}

CodePudding user response:

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:

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

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("(\\[\\s{0,}"   label   "\\s{0,}\\])")

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 := "| [ 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 ]"]

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, "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
            testLabel := fmt.Sprintf("test%d", field.num)
            re := regexp.MustCompile(`(\[\s*`   testLabel   `\s*\])`)

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

            // Create final label by padding to len of submatch
            padding := strings.Repeat(" ", len(submatch)-len(field.label))
            finalLabel := field.label   padding

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

which prints:

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


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