PowerShell how to incorporate regex in replace command - regex

I have a txt file (TSTTTT.txt) with a string value of :
$$FULL_LOAD_DAY=Monday
I would like to change it to, through powershell :
$$FULL_LOAD_DAY=Tuesday
I already know that the regex needed to find my entire string is [regardless of the day]:
\$\$FULL_LOAD_DAY=(\w+)(?=[,.]|$)+
I just don't know how to change my usual Powershell command to include regex:
(Get-Content C:\Private\TSTTTT.txt).replace('a', 'b') | Set-Content C:\Private\TSTTTT.txt

You can use the -replace operator to use regex in replacing string.
For example, to replace your string with 'b', use the following:
(Get-Content C:\Private\TSTTTT.txt) -replace '\$\$FULL_LOAD_DAY=(\w+)(?=[,.]|$)+','b' | Set-Content C:\Private\TSTTTT.txt

If I got it right your regex can be much simpler ...
$Day = 'Tuesday'
(Get-Content C:\Private\TSTTTT.txt) -replace '(?<=\$\$FULL_LOAD_DAY=)(\w+)', $Day |
Set-Content C:\Private\TSTTTT.txt

Related

How Do I change a string in a specific line contained in a file preserving all other lines?

I have a file that contains this information:
Type=OleDll
Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#..\..\..\..\..\..\..\Windows\SysWOW64\stdole2.tlb#OLE Automation
Reference=*\G{7C0FFAB0-CD84-11D0-949A-00A0C91110ED}#1.0#0#..\..\..\..\..\..\..\Windows\SysWOW64\msdatsrc.tlb#Microsoft Data Source Interfaces for ActiveX Data Binding Type Library
Reference=*\G{26C4A893-1B44-4616-8684-8AC2FA6B0610}#1.0#0#..\..\..\..\..\..\..\Windows\SysWow64\Conexion_NF.dll#Zeus Data Access Library 1.0 (NF)
Reference=*\G{9668818B-3228-49FD-A809-8229CC8AA40F}#1.0#0#..\packages\ZeusMaestrosContabilidad.19.3.0\lib\native\ZeusMaestrosContabilidad190300.dll#Zeus Maestros Contables Des (Contabilidad)
I need to change the data between {} characters on line 5 using powershell and save the change preserving all other information in the file.
You can use the -replace operator to perform a regex match and string replacement.
If there is only one pair of {} per line, you can do the following where .*? matches any non-newline character as few as possible. Since by default Get-Content creates an object that is an array of lines, you can access each line by index with [4] being line 5.
$content = Get-Content File.txt
$content[4] = $content[4] -replace '{.*?}','{new data}'
$content | Set-Content File.txt
If there could be multiple {} pairs per line, you will need to be more specific with your regex. A positive lookbehind assertion (?<=) will do.
$content = Get-Content File.txt
$content[4] = $content[4] -replace '(?<=Reference=\*\\G){.*?}','{newest data}'
$content | Set-Content File.txt
For the case when you don't know which line contains the data you want to replace, you will need to be more specific about the data you are replacing.
Get-Content File.txt -replace '{9668818B-3228-49FD-A809-8229CC8AA40F}','{New Data}' | Set-Content
If there are an encoding requirements, consider using the -Encoding parameter on the Get-Content and Set-Content commands.
Try Regex: (?<=(?:.*\n){4}Reference=\*\\G\{)[\w-]+
Demo
If the content of the {} is always the same you can do this:
(Get-Content $yourfile) -replace $regex, ('{9668818B-3228-49FD-A809-8229CC8AA40F}') | Set-Content $newValue;
One solution :
$Content=Get-Content "C:\temp\test.txt"
$Row5Splited=$Content[4].Split("{}".ToCharArray())
$Content[4]="{0}{1}{2}" -f $Row5Splited[0], "{YOURNEWVALUE}", $Row5Splited[2]
$Content | Out-File "C:\temp\test2.txt"
One approach would be to find,
(.*Reference=\*\\G{)[^\r\n}]+
and replace with,
$1any_thing_you_like_to_replace_with
RegEx Circuit
jex.im visualizes regular expressions:
If you wish to simplify/modify/explore the expression, it's been explained on the top right panel of regex101.com. If you'd like, you can also watch in this link, how it would match against some sample inputs.

Regular expression seems not to work in Where-Object cmdlet

I am trying to add quote characters around two fields in a file of comma separated lines. Here is one line of data:
1/22/2018 0:00:00,0000000,001B9706BE,1,21,0,1,0,0,0,0,0,0,0,0,0,0,13,0,1,0,0,0,0,0,0,0,0,0,0
which I would like to become this:
1/22/2018 0:00:00,"0000000","001B9706BE",1,21,0,1,0,0,0,0,0,0,0,0,0,0,13,0,1,0,0,0,0,0,0,0,0,0,0
I began developing my regular expression in a simple PowerShell script, and soon I have the following:
$strData = '1/29/2018 0:00:00,0000000,001B9706BE,1,21,0,1,0,0,0,0,0,0,0,0,0,0,13,0,1,0,0,0,0,0,0,0,0,0,0'
$strNew = $strData -replace "([^,]*),([^,]*),([^,]*),(.*)",'$1,"$2","$3",$4'
$strNew
which gives me this output:
1/29/2018 0:00:00,"0000000","001B9706BE",1,21,0,1,0,0,0,0,0,0,0,0,0,0,13,0,1,0,0,0,0,0,0,0,0,0,0
Great! I'm all set. Extend this example to the general case of a file of similar lines of data:
Get-Content test_data.csv | Where-Object -FilterScript {
$_ -replace "([^,]*),([^,]*),([^,]*),(.*)", '$1,"$2","$3",$4'
}
This is a listing of test_data.csv:
1/29/2018 0:00:00,0000000,001B9706BE,1,21,0,1,0,0,0,0,0,0,0,0,0,0,13,0,1,0,0,0,0,0,0,0,0,0,0
1/29/2018 0:00:00,104938428,0016C4C483,1,45,0,1,0,0,0,0,0,0,0,0,0,0,35,0,1,0,0,0,0,0,0,0,0,0,0
1/29/2018 0:00:00,104943875,0016C4B0BC,1,31,0,1,0,0,0,0,0,0,0,0,0,0,25,0,1,0,0,0,0,0,0,0,0,0,0
1/29/2018 0:00:00,104948067,0016C4834D,1,33,0,1,0,0,0,0,0,0,0,0,0,0,23,0,1,0,0,0,0,0,0,0,0,0,0
This is the output of my script:
1/29/2018 0:00:00,0000000,001B9706BE,1,21,0,1,0,0,0,0,0,0,0,0,0,0,13,0,1,0,0,0,0,0,0,0,0,0,0
1/29/2018 0:00:00,104938428,0016C4C483,1,45,0,1,0,0,0,0,0,0,0,0,0,0,35,0,1,0,0,0,0,0,0,0,0,0,0
1/29/2018 0:00:00,104943875,0016C4B0BC,1,31,0,1,0,0,0,0,0,0,0,0,0,0,25,0,1,0,0,0,0,0,0,0,0,0,0
1/29/2018 0:00:00,104948067,0016C4834D,1,33,0,1,0,0,0,0,0,0,0,0,0,0,23,0,1,0,0,0,0,0,0,0,0,0,0
I have also tried this version of the script:
Get-Content test_data.csv | Where-Object -FilterScript {
$_ -replace "([^,]*),([^,]*),([^,]*),(.*)", "`$1,`"`$2`",`"`$3`",$4"
}
and obtained the same results.
My simple test script has convinced me that the regex is correct, but something happens when I use that regex inside a filter script in the Where-Object cmdlet.
What simple, yet critical, detail am I overlooking here?
Here is my PSVerion:
Major Minor Build Revision
----- ----- ----- --------
5 0 10586 117
You're misunderstanding how Where-Object works. The cmdlet outputs those input lines for which the -FilterScript expression evaluates to $true. It does NOT output whatever you do inside that scriptblock (you'd use ForEach-Object for that).
You don't need either Where-Object or ForEach-Object, though. Just put Get-Content in parentheses and use that as the first operand for the -replace operator. You also don't need the 4th capturing group. I would recommend anchoring the expression at the beginning of the string, though.
(Get-Content test_data.csv) -replace '^([^,]*),([^,]*),([^,]*)', '$1,"$2","$3"'
This seems to work here. I used ForEach-Object to process each record.
Get-Content test_data.csv |
ForEach-Object { $_ -replace "([^,]*),([^,]*),([^,]*),(.*)", '$1,"$2","$3",$4' }
This also seems to work. Uses the ? to create a reluctant (lazy) capture.
Get-Content test_data.csv |
ForEach-Object { $_ -replace '(.*?),(.*?),(.*?),(.*)', '$1,"$2","$3",$4' }
I would just make a small change to what you have in order for this to work. Simply change the script to the following, noting that I changed the -FilterScript to a ForEach-Object and fixed a minor typo that you had on the last item in the regular expression with the quotes:
Get-Content c:\temp\test_data.csv | ForEach-Object {
$_ -replace "([^,]*),([^,]*),([^,]*),(.*)", "`$1,`"`$2`",`"`$3`",`"`$4"
}
I tested this with the data you provided and it adds the quotes to the correct columns.

Use Variable in Replace

I have a text file and want to regex/replace something with the content of a variable in PowerShell.
File: my.json
Variable in Powershell $version
Search for: version : "something"
Replace "something" with the content of the variable $version
Here is what I tried. Search and replace works as expected but the result is
version : "$version".
(Get-Content my.json) -replace '(?<pre>"version"[\s]*:[\s]*)(?<V>"[^\"]*")', '$1"$version"' | Out-File my.json
To be able to use variables in the replacement string you need to use a double-quoted replacement string, meaning that you need to escape backreferences and nested double quotes:
(Get-Content my.json) -replace '...', "`$1`"$version`"" | ...
Ansgar's answer is perfectly valid, but ` escape sequences can be ugly and hinder readability.
I would personally use the -f format operator to concatenate the '$1' string literal and the value of $version:
(Get-Content my.json) -replace '...',('$1{0}' -f $version)

replace thousands separators in csv with regex

I'm running into problems trying to pull the thousands separators out of some currency values in a set of files. The "bad" values are delimited with commas and double quotes. There are other values in there that are < $1000 that present no issue.
Example of existing file:
"12,345.67",12.34,"123,456.78",1.00,"123,456,789.12"
Example of desired file (thousands separators removed):
"12345.67",12.34,"123456.78",1.00,"123456789.12"
I found a regex expression for matching the numbers with separators that works great, but I'm having trouble with the -replace operator. The replacement value is confusing me. I read about $& and I'm wondering if I should use that here. I tried $_, but that pulls out ALL my commas. Do I have to use $matches somehow?
Here's my code:
$Files = Get-ChildItem *input.csv
foreach ($file in $Files)
{
$file |
Get-Content | #assume that I can't use -raw
% {$_ -replace '"[\d]{1,3}(,[\d]{3})*(\.[\d]+)?"', ("$&" -replace ',','')} | #this is my problem
out-file output.csv -append -encoding ascii
}
Tony Hinkle's comment is the answer: don't use regex for this (at least not directly on the CSV file).
Your CSV is valid, so you should parse it as such, work on the objects (change the text if you want), then write a new CSV.
Import-Csv -Path .\my.csv | ForEach-Object {
$_ | ForEach-Object {
$_ -replace ',',''
}
} | Export-Csv -Path .\my_new.csv
(this code needs work, specifically the middle as the row will have each column as a property, not an array, but a more complete version of your CSV would make that easier to demonstrate)
You can try with this regex:
,(?=(\d{3},?)+(?:\.\d{1,3})?")
See Live Demo or in powershell:
% {$_ -replace ',(?=(\d{3},?)+(?:\.\d{1,3})?")','' }
But it's more about the challenge that regex can bring. For proper work, use #briantist answer which is the clean way to do this.
I would use a simpler regex, and use capture groups instead of the entire capture.
I have tested the follow regular expression with your input and found no issues.
% {$_ -replace '([\d]),([\d])','$1$2' }
eg. Find all commas with a number before and after (so that the weird mixed splits dont matter) and replace the comma entirely.
This would have problems if your input has a scenario without that odd mixing of quotes and no quotes.

Powershell replace exact string

I want to replace a simple string "WEEK." (with a dot) in a text file with the string "TEST"
$LOG= "C:\FILE.TXT"
$A= "TEST"
(Get-Content $LOG) | Foreach { $_ -Replace "WEEK.", $A } | Set-Content $LOG;
The problem is that my file has this content:
WEEK_A WEEK.
And when I run my script the result is:
TESTA TEST
and the result that i want is:
WEEK_A TEST
I try with ^ "WEEK." and "^WEEK.$" but it not worked
Can you help me with the regexp? Thanks
====== EDIT ==================
Ok. I try with
$LOG= "C:\FILE.TXT"
$A= "TEST"
(Get-Content $LOG) | Foreach { $_ -Replace "WEEK\.", $A } | Set-Content $LOG;
and seems its works
The reason why this happened is because you have used pattern WEEK. The dot was a problem: in a regular expression world, the dot means "any character". That's why it was replacing both WEEK_ and WEEK..
When you have added backslash, then the dot was escaped ie. it lost it's special meaning. Thus making it work.