0

Using powershell on Windows, when I use the following simple regular expression to remove any space characters at the end of the string and also append a period, I get duplication of the replacement string when there are spaces. Almost as if the spaces and the end-of-line is matched separately:

PS C:\>  "walk along the edge"   -replace ' *$',"s."
walk along the edges.
PS C:\>  "walk along the edge "  -replace ' *$',"s."
walk along the edges.s.
PS C:\>  "walk along the edge  " -replace ' *$',"s."
walk along the edges.s.

But I expected a more consistent behavior, like this:

$ echo "walk along the edge"   | sed "s/ *$/s./"
walk along the edges.
$ echo "walk along the edge "  | sed "s/ *$/s./"
walk along the edges.
$ echo "walk along the edge  " | sed "s/ *$/s./"
walk along the edges.

This is consistent between PS v7.2.5 and 4.1, both on Windows. Referencing standard GNU sed on RHEL-flavored linux, if that matters. I tried some parenthesis to "force" grouping, and escaping the dollar sign, to no avail.

How do I force the entire matching expression to be evaluated as one big match, in powershell?

Adding an extra space (or using the + metacharacter rather than *) is not quite what is required:

PS C:\>  "walk along the edge   " -replace '  *$',"s."
walk along the edges.
PS C:\>  "walk along the edge"   -replace '  *$',"s."
walk along the edge

Although it solves all the cases where there is a space, it fails for the case where there is not a space.

Justin
  • 397
  • 7
  • 17
  • 2
    Due to the `*` quantifier it also matches an empty string at the end of the line. This is somewhat counter-intuitive behavior, as one would assume that the first match had already consumed all available characters. – zett42 Aug 16 '22 at 18:03
  • 1
    See also: https://stackoverflow.com/questions/52369618/why-do-regex-engines-allow-automatically-attempt-matching-at-the-end-of-the-in – zett42 Aug 16 '22 at 18:13

2 Answers2

3

You can add a boundary before the spaces and this returns correctly every time.

PS C:\Users\TMTech> "walk along the edge"   -replace '\b *$',"s."
walk along the edges.

PS C:\Users\TMTech> "walk along the edge "  -replace '\b *$',"s."
walk along the edges.

PS C:\Users\TMTech> "walk along the edge  " -replace '\b *$',"s."
walk along the edges.
TheMadTechnician
  • 34,906
  • 3
  • 42
  • 56
2

You can force the single match by capturing the preceding character, like this:

"walk along the edge      "   -replace '(\S) *$','$1s.'
trincot
  • 317,000
  • 35
  • 244
  • 286