replace whole string if contains substring - powershell

I want to completely replace a string if it contains a specific substring, using replace. How can this be done?
I have tried the following, with expected output "STRING":
$a="abc123STRINGabc123"
$a.replace('*STRING*','STRING')

Use the -replace operator and a regular expression.
$a = 'abc123STRINGabc123'
$b = 'abc123foobarabc123'
$srch = 'STRING'
$repl = 'GNIRTS'
$pattern = '.*{0}.*' -f [regex]::Escape($srch)
$a -replace $pattern, $repl # output: GNIRTS
$b -replace $pattern, $repl # output: abc123foobarabc123

Related

Change pipe delimited file to comma delimited in Powershell

I have a pipe delimited .TXT file. I need to change the delimiter to a comma instead but still keep the file extension as .TXT. The file looks like this:
Column 1 |Column 2
13|2019-09-30
96|2019-09-26
173|2019-09-25
I am using Windows Powershell 5.1 version for my script.
I am using the following code:
$file = New-Object System.IO.StreamReader -Arg "c:\file.txt"
$outstream = [System.IO.StreamWriter] "c:\out.txt"
while ($line = $file.ReadLine()) {
$s = $line -replace '|', ','
$outstream.WriteLine($s)
}
$file.close()
$outstream.close()
Instead of just replacing the pipe with a comma, the output file looks like this:
C,o,l,u,m,n, 1 , |,C,o,l,u,m,n, 2
1,3,|,2,0,1,9,-,0,9,-,3,0
9,6,|2,0,1,9,-,0,9,-,2,6
1,7,3,|,2,0,1,9,-,0,9,-,2,5
The only problem with your answer is in how you try to replace the | characters in the input:
$s = $line -replace '|', ',' # WRONG
PowerShell's -replace operator expects a regex (regular expression) as its first RHS operand, and | is a regex metacharacter (has special meaning)[1]; to use it as a literal character, you must \-escape it:
# '\'-escape regex metacharacter '|' to treat it literally.
$s = $line -replace '\|', ','
While PowerShell's -replace operator is very flexible, in simple cases such as this one you can alternatively use the [string] type's .Replace() method, which performs literal string replacements and therefore doesn't require escaping (it's also faster than -replace):
# Use literal string replacement.
# Note: .Replace() is case-*sensitive*, unlike -replace
$s = $line.Replace('|', ',')
[1] | denotes an alternation in a regex, meaning that the subexpressions on either side are matched against the input string and one of them matching is sufficient; if your full regex is just |, it effectively matches the empty string before and after each character in the input, which explains your symptom; e.g., 'foo' -replace '|', '#' yields #f#o#o#
You can use Import-Csv and Export-Csv by specifying the -Delimiter.
Import-Csv -Delimiter '|' -Path "c:\file.txt" | Export-Csv -Delimiter ',' -Path "c:\file.txt" -NoTypeInformation
You will find the -split and -join operators to be of interest.
Get-Content -Path "C:\File.TXT" | ForEach-Object { ($_ -split "\|") -join "," } | Set-Content -Path "C:\Out.TXT"

How pipe after replace in PowerShell?

I would like a to replace characters inside a string and then split it.
Example below:
$in = "string with spaces"
$out = $in -replace 's' | $_.Split(' ')
Leads to ExpressionsMustBeFirstInPipeline.
How come this doesn't work?
There's nothing wrong with the result of the replacement going into the pipeline, but your next step doesn't actually read from the pipeline. For the construct you chose you need a ForEach-Object loop:
$out = $in -replace 's' | ForEach-Object { $_.Split(' ') }
or call Split() on the result of the replacement (without pipeline):
$out = ($in -replace 's').Split(' ')
However, if you use the -split operator instead of the Split() method you can simply daisy-chain it (again without using the pipeline):
$out = $in -replace 's' -split ' '
try this
$in = "string with spaces"
$out = $in -split ' ' -replace 's'
echo $out
You can use the Replace string method instead. E.g to replace s with blank, and then split on space:
$out = $in.Replace('s','').split(' ')

using matched patterns in powershell -replace

The following prints out 123$replace456, I'd like it to print 123yyy456. How do I do this in powershell?
$path = '123xxx456'
$search = "(\d*)xxx(\d*)"
$replace = 'yyy'
$path -replace $search, '$1$replace$2'
Use a double-quoted string for the replacement pattern in order for $replace to expand correctly. Remember to escape the $ in front of backreferences (ie `$1):
$path -replace $search, "`$1$replace`$2"

Parse string using the Where-Object cmdlet

So I have this simple collection:
$str = "bla_sdf_r1_vrr_1.0.1", "bla_sdf_r1_trr_1.0.2"
If this string contains the word vrr i want to take the version number 1.0.1 and if this string contains the word trr i want to take the version number 1.0.2
This is what I have tried and it works fine:
$fld = $str | Where { $_.Contains("vrr") }
$ver = $fld.Split("_")[4]
But I want to do that in one line.
So I tried:
$fld = $str | Where { $_.Contains("vrr") } | -split[4]
But this probably not the right way.
Any suggestions?
You could do that with a regex. In case it doesn't contain vrr, the output is empty:
[regex]::Match('bla_sdf_r1_vrdr_1.0.1', '.*vrr_(.*)').Groups[1].Value
You can use Regex.
"bla_sdf_r1_vrr_1.0.1" -match "[\d\.]*$"
It searches your string for digits and . as many times as possible in the end of the string.
Your result is in the automatic variable $matches[0]
Edit:
Given your collection, you could do something like this:
$str | ForEach-Object { if($_ -match "[\d\.]*$") { $matches[0] } }
If the current string matches the regex I wrote, print the match.
you can group the matches and access them by number (or also name them)
$str = "bla_sdf_r1_vrr_1.0.1", "bla_sdf_r1_trr_1.0.2"
$str | %{
if ($_ -match '(vrr|trr)_([0-9.]+)') {
$matches[1] + " is " + $matches[2]
}
}
Output
vrr is 1.0.1
trr is 1.0.2
The output will be the same with this variant:
$str = "bla_sdf_r1_vrr_1.0.1", "bla_sdf_r1_trr_1.0.2"
$str | %{
if ($_ -match '(?<xrr>vrr|trr)_(?<version>[0-9.]+)') {
$matches.xrr + " is " + $matches.version
}
}
$str = "bla_sdf_r1_vrr_1.0.1", "bla_sdf_r1_trr_1.0.2"
$str | where {($_ -split "_")[3] -in ("vrr", "trr") } | select #{N="Type";E={($_ -split "_")[3]}}, #{N="Version";E={($_ -split "_")[4]}}

Switch strings in a file

I have a string needs to be changed in a file between two values. What I want to do is if I found value A then change to value B, if I found value B then change to value A. there will be a message box popup saying that value has been changed to [xxxxx] then background picture will be also changed accordingly.
$path = c:\work\test.xml
$A = AAAAA
$B = BBBBB
$settings = get-content $path
$settings | % { $_.replace($A, $B) } | set-content $path
I could not figured out how to use IF A then replace with B or IF B then replace A. Also, the code above will delete rest of contents in the file and only save the part that I modified back to the file.
Assuming that $A and $B contain just simple strings rather than regular expressions you could use a switch statement with wildcard matches:
$path = 'c:\work\test.xml'
$A = 'AAAAA'
$B = 'BBBBB'
(Get-Content $path) | % {
switch -wildcard ($_) {
"*$A*" { $_ -replace [regex]::Escape($A), $B }
"*$B*" { $_ -replace [regex]::Escape($B), $A }
default { $_ }
}
} | Set-Content $path
The [regex]::Escape() makes sure that characters having a special meaing in regular expressions are escaped, so the values are replaced as literal strings.
If you're aiming for something a little more advanced, you could use a regular expression replacement with a callback function:
$path = 'c:\work\test.xml'
$A = 'AAAAA'
$B = 'BBBBB'
$rep = #{
$A = $B
$B = $A
}
$callback = { $rep[$args[0].Groups[1].Value] }
$re = [regex]("({0}|{1})" -f [regex]::Escape($A), [regex]::Escape($B))
(Get-Content $path) | % {
$re.Replace($_, $callback)
} | Set-Content $path
This isn't tested extensively, but I think it should work:
path = c:\work\test.xml
$A = 'AAAAA'
$B = 'BBBBB'
[regex]$regex = "$A|$B"
$text =
Get-Content $path |
foreach {
$regex.Replace($text,{if ($args[0].value -eq $A){$B} else {$A}})
}
$text | Set-Content $path
Hard to be sure without knowing exactly what the data looks like.