Powershell variable in replacement string with named groups - regex

The following Powershell replace operation with named groups s1 and s2 in regex (just for illustration, not a correct syntax) works fine :
$s -Replace "(?<s1>....)(?<s2>...)" '${s2}xxx${s1}'
My question is : how to replace with a variable $x instead of the literal xxx, that is, something like :
$s -Replace "(?<s1>....)(?<s2>...) '${s2}$x${s1}'
That doesn't work as Powershell doesn't replace variable in single quoted string but the named group resolution doesn't work anymore if replacement string is put in double quotes like this "${s2}$x${s1}".

#PetSerAl comment is correct, here is code to test it:
$sep = ","
"AAA BBB" -Replace '(?<A>\w+)\s+(?<B>\w+)',"`${A}$sep`${B}"
Output:
AAA,BBB
Explanation:
Powershell will evaluate the double quoted string, escaping the $ sign with a back tick will ensure these are not evaluated and a valid string is provided for the -Replace operator.
msdn about replace operator
msdn about escape characters
or via Get-Help about_escape & Get-Help about_comparison_operators

Related

Powershell - How to replace a number with a variable in a string?

Trying to replace a number (20 with a variable $cntr=120) in a string using replace operator. But getting stuck with $cntr in the output. Where I am doing wrong? Any better solutions please.
Input string
myurl.com/search?project=ABC&startAt=**20**&maxResults=100&expand=log
Desired Output string
myurl.com/search?project=ABC&startAt=**120**&maxResults=100&expand=log
Actual Output string
myurl.com/search?project=ABC&startAt=**$cntr**&maxResults=100&expand=log
Code:
$str='myurl.com/search?project=ABC&startAt=20&maxResults=100&expand=log'
$cntr=120
$str = $str -replace '^(.+&startAt=)(\d+)(&.+)$', '$1$cntr$3'
$str
You need to
Use double quotes to be able to use string interpolation
Use the unambiguous backreference syntax, ${n}, where n is the group ID.
In this case, you can use
PS C:\Users\admin> $str='myurl.com/search?project=ABC&startAt=20&maxResults=100&expand=log'
PS C:\Users\admin> $cntr=120
PS C:\Users\admin> $str = $str -replace '^(.+&startAt=)(\d+)(&.+)$', "`${1}$cntr`$3"
PS C:\Users\admin> $str
myurl.com/search?project=ABC&startAt=120&maxResults=100&expand=log
See the .NET regex "Substituting a Numbered Group" documentation:
All digits that follow $ are interpreted as belonging to the number group. If this is not your intent, you can substitute a named group instead. For example, you can use the replacement string ${1}1 instead of $11 to define the replacement string as the value of the first captured group along with the number "1".
A couple things here:
If you just add the "12" you end up with $112$3 which isn't what you want. What I did was appended a slash in front and then removed it on the backend, so the replace becomes $1\12$3.
$str='myurl.com/search?project=ABC&startAt=20&maxResults=100&expand=log'
$cntr=12
$str = ($str -replace '^(.+&startAt=)(\d+)(&.+)$', ('$1\' + $cntr.ToString() +'$3')).Replace("\", "")
$str
Looking to see if there's another way to add the literal "12" in the replace section with the extra character, but this does work.
Here's another way to do it where you have a literal string between the $1 and $3 and then replace that at the end.
$str='myurl.com/search?project=ABC&startAt=20&maxResults=100&expand=log'
$cntr=12
$str = ($str -replace '^(.+&startAt=)(\d+)(&.+)$', ('$1REPLACECOUNTER$3')).Replace("REPLACECOUNTER", "$cntr")
$str

PowerShell regex does not match near newline

I have an exe output in form
Compression : CCITT Group 4
Width : 3180
and try to extract CCITT Group 4 to $var with PowerShell script
$var = [regex]::match($exeoutput,'Compression\s+:\s+([\w\s]+)(?=\n)').Groups[1].Value
The http://regexstorm.net/tester say, the regexp Compression\s+:\s+([\w\s]+)(?=\n) is correct but not PowerShell. PowerShell does not match. How can I write the regexp correctly?
You want to get all text from some specific pattern till the end of the line. So, you do not even need the lookahead (?=\n), just use .+, because . matches any char but a newline (LF) char:
$var = [regex]::match($exeoutput,'Compression\s+:\s+(.+)').Groups[1].Value
Or, you may use a -match operator and after the match is found access the captured value using $matches[1]:
$exeoutput -match 'Compression\s*:\s*(.+)'
$var = $matches[1]
Wiktor Stribiżew's helpful answer simplifies your regex and shows you how to use PowerShell's -match operator as an alternative.
Your follow-up comment about piping to Out-String fixing your problem implies that your problem was that $exeOutput contained an array of lines rather than a single, multiline string.
This is indeed what happens when you capture the output from a call to an external program (*.exe): PowerShell captures the stdout output lines as an array of strings (the lines without their trailing newline).
As an alternative to converting array $exeOutput to a single, multiline string with Out-String (which, incidentally, is slow[1]), you can use a switch statement to operate on the array directly:
# Stores 'CCITT Group 4' in $var
$var = switch -regex ($exeOutput) { 'Compression\s+:\s+(.+)' { $Matches[1]; break } }
Alternatively, given the specific format of the lines in $exeOutput, you could leverage the ConvertFrom-StringData cmdlet, which can perform parsing the lines into key-value pairs for you, after having replaced the : separator with =:
$var = ($exeoutput -replace ':', '=' | ConvertFrom-StringData).Compression
[1] Use of a cmdlet is generally slower than using an expression; with a string array $array as input, you can achieve what $array | Out-String does more efficiently with $array -join "`n", though note that Out-String also appends a trailing newline.

Replace particulars characters in powershell

I am trying to replace a character to escape it in a Powershell string to convert it to JSON later. I would like to replace the double quotes " in the cmdline by a single quote followed by a double quotes, to escape the double quotes.
I have this string : user123" -a.exe
I would like to have user123'" -a.exe
I try different combinations with the -replace function like
$test -replace '"',''"'
but no one works due to the particularity of these characters.
Thanks in advance for your help
To force Windows PowerShell to interpret a double quotation mark literally, use a backtick(`) character.
PS C:\> $test = "user123`" -a.exe"
PS C:\> $test
user123" -a.exe
PS C:\> $test = $test -replace "`"","'`""
PS C:\> $test
user123'" -a.exe
To learn most of the variations and tricks to work with Quotes, type
Help about_Quoting_Rules
at Powershell console.
You need to use backtick(`) character to escape special characters and use String.Replace method
$test = "user123`" -a.exe"
$test.replace("`"","`'`"")
Result:
user123'" -a.exe
If you're dealing with a manipulating quoted text, and find the escaping rules are confusing and/or result in obfuscated code, you can also deal with it as here-strings. Within the here-string delimiters (#'-'#) normal quoting rules don't apply. It can make for longer code, but may be more intuitive to read and debug or do maintenance on later.
$string = #'
user123" -a.exe
'#
$match = #'
"
'#
$replace = #'
"'
'#
$string.replace($match,$replace)
user123"' -a.exe
This is obviously a trivial example, but as the amount of quoted text and increases so will the advantage of using the here-strings over constructing arguments inline using escaped characters.

How to use $_ in content without been replaced by powershell?

I'm trying to replace a word to some php code
$filecontent = [regex]::Replace($filecontent, $myword, $phpcode)
But the $phpcode have some php code using also a Special variable $_
<?php $cur_author = (isset($_GET['author_name'])) ? get_user_by('slug', $author_name) : get_userdata(intval($author)); ?>
The problem is when the code is replace in $filecontent it replaces the $_ variable from the php code ( $_GET ) with it have on the pipeline.
This not happen with the other variables like $author_name .
How can I resolve this?
Does this work for you?
$filecontent = [regex]::Replace($filecontent, $myword, {$phpcode})
In a regex replace operation the $_ is a reserved substituion pattern that represents the entire string
http://msdn.microsoft.com/en-us/library/az24scfc.aspx
Wrapping it in braces makes it a scriptblock delegate, bypassing the normal regex pattern matching algorithms for doing the replacement.
You have two options. First use a single quoted string and PowerShell will treat that as a verbatim string (C# term) i.e. it won't try to string interpolate:
'$_ is passed through without interpretation'
The other option is to escape the $ character in a double quoted string:
"`$_ is passed through without interpretation"
When I'm messing with a regex I will default to using single quoted strings unless I have a variable that needs to be interpolated inside the string.
Another possibility is that $_ is being interpreted by regex as a substitution group in which case you need to use the substitution escape on the $ e.g. $$.
Im not sure I am following you correctly, but does this help?
$file = path to your file
$oldword = the word you want to replace
$newword = the word you want to replace it with
If the Oldword you are replacing has special charactes ( ie. \ or $ ) then you must escape them first. You can escape them by putting a backslash in front of the special character. The Newword, does not need to be escaped. A $ would become "\$".
(get-content $file) | foreach-object {$_ -replace $oldword,$NewWord} | Set-Content $file

Powershell - Replacing a string with a variable ending with a dollar sign

I'm a bit lost with this one. For whatever reason the replace function in powershell doesn't play well with variables ending with a $ sign.
Command:
$var='A#$A#$'
$line=('$var='+"'"+"'")
$line -replace '^.+$',('$line='+"'"+$var+"'")
Expected output:
$line='A#$A#$'
Actual output:
$line='A#$A#
It looks like you're getting hit with a regex substitution that you don't want. The regex special variable $' represents everything after your match. Since your regex matches the entire string, $' is effectively empty. During the replace operation, the .Net regex engine sees $' in your expected output and substitutes in that empty string.
One way to avoid this is to replace all instances of $ in your $var string with $$:
$line -replace '^.+$',('$line='+"'"+($var.Replace('$','$$'))+"'")
You can see more information about regex substitution in .Net here:
Substitutions
I was able to find a band-aid of sorts by replacing $ with a special character and then reverting it back after the change. Preferably you would choose a character that doesn't have a key on your keyboard. For me I chose "¤".
$var='A#$A#$'
$var=$var -replace '\$','¤'
$line=("`$var=''")
$line -replace '^.+$',("`$line='$var'") -replace '¤','$'
I don't really understand the purpose of your posted lines, it seems to me that it would just make more sense to do $line='$line='''+$var+"'", BUT if you insist on your way, just do two replace calls, like this:
$line -replace '^.+$',('$line=''LOL''') -replace 'LOL',$var