Split specific string from lines via regex - regex

I have been trying to extract certain equal to 40 values get the sixth last word from multiple lines inside a .txt file with PowerShell.
I have code so far :
$file = Get-Content 'c:\temp\file.txt'
$Array = #()
foreach ($line in $file)
{
$Array += $line.split(",")[6]
}
$Array
$Array | sc "c:\temp\export2.txt"
Txt file : (may be duplicate lines such as hostname01)
4626898,0,3,0,POL,INCR,hostname01,xx,1549429809,0000000507,1549430316,xxx,0,40,1,xxxx,51870834,5040,100
4626898,0,3,0,POL,INCR,hostname02,xx,1549429809,0000000507,1549430316,xxx,0,15,1,xxxx,51870834,5040,100
4626898,0,3,0,POL,INCR,hostname03 developer host,xx,1549429809,0000000507,1549430316,xxx,0,40,1,xxxx,51870834,5040,100
4626898,0,3,0,POL,INCR,hostname01,xx,1549429809,0000000507,1549430316,xxx,0,40,1,xxxx,51870834,5040,100
This is what I want :
hostname01
hostname02
hostname03 developer host

This is not a fast solution, but a convenient and flexible one:
Since your text file is effectively a CSV file, you can use Import-Csv.
Since your data is missing is a header row (column names), which we can supply to Import-Csv via its -Header parameter.
Since you're interested in columns number 7 (hostnames) and 14 (the number whose value should be 40), we need to supply column names (of our choice) for columns 1 through 14.
Import-Csv conveniently converts the CSV rows to (custom) objects, whose properties you can query with Where-Object and selectively extract with Select-Object; adding -Unique suppresses duplicate values.
To put it all together:
Import-Csv c:\temp\file.txt -Header (1..14) |
Where-Object 14 -eq 40 |
Select-Object -ExpandProperty 7 -Unique
For convenience we've named the columns 1, 2, ... using a range expression (1..14), but you're free to use descriptive names.
Assuming that c:\temp\file.txt contains your sample data, the above yields:
hostname01
hostname03 developer host
To output to a file, pipe the above to Set-Content, as in your question:
... | Set-Content c:\temp\export2.txt

If the desired field is always the 6th in the line it is easier to split each line and fetch the 6th member:
Get-Content 'c:\temp\file.txt' | Foreach-Object {($_ -split ',')[6]} | Select-Object -Unique

You could use a non-capturing group to look through the string for the correct format and reference the name of your 6 element with the 1st capture group $1:
(?:\d+,\d,\d,\d,[A-Z]+,[A-Z]+,)([a-zA-Z 0-9]+)
Demo here
(?: ) - Specifies a non-capture group (meaning it's not referenced via $1, or $2 like you normally would with a capture group
\d+, (I won't repeat all of these, but) looking for a one or more digits followed by a literal ,.
[A-Z]+, - Finds an all capital letter string, followed by a literal , (this occurs twice).
([a-zA-Z 0-9]+) - The capture group you're looking for, $1, that will capture all characters a-z, A-Z, spaces, and digits up until a character not in this set (in this case, a comma). Giving you the text you're looking for.

Below should work with what you are trying to do
Get-Content 'c:\temp\file.txt' | %{
$_.Split(',')[6]
}| select -Unique

Related

Using PowerShell regex to confirm that a date is at the TAIL END of a filename

I have a set of folders that are updated daily with a new SSRS report. SSRS reports do not have the facility to append an underscore and file creation date to the end of the filename.
A PowerShell command has been created that will append the file modified date to the start of the file, but needs to be at the end of the file. The issue is not with this part of the process - I can sort this out.
Issue: I cannot get the regex command - used to identify the files that need the change - to identify when the date is at the END of the file, not the beginning. I have tried amending the regex syntax, but have left it in now for clarity.
When run on a folder that already contains files, it appends over and over again.
Rules:
The filename is not a uniform length
The date will always have an _ character then be in YYYYMMDD format
Format: FileName_YYYYMMDD.xlsx
I cannot move renamed files out of the folder - they have to all be created and then remain in the same location
$ParsedDate = [datetime]::MinValue;
$Path = "C:\UserDocuments\Config Updates";
Get-ChildItem -File -Path $Path |
Where-Object {
(-not [regex]::IsMatch($_.Name, "^\d{8}_", [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)) -or (-not [datetime]::TryParseExact($_.Name.Substring(0, 8), "yyyyMMdd", [cultureinfo]::CurrentCulture, [System.Globalization.DateTimeStyles]::None, [ref] $ParsedDate))
} |
ForEach-Object { Rename-Item -Path ($_.FullName) -NewName "$($_.BaseName)_$($_.LastWriteTime.ToString("yyyyMMdd"))$($_.Extension)";}
I am not a PS expert, and this may be a noob question.
I have tried combinations of:
"^\d{8}_" "^_\d{8}" "^\d{8}"
Continuing from my comment, I believe you want to search for files that have a date + underscore at the beginning of the file and these should be renamed so that the date is removed from the start and appended at the end.
Since you already tried, perhaps now some files have been appended an underscore+dae multiple times at the end.
Below code should clean these up too
$Path = "C:\UserDocuments\Config Updates"
# if all your files are .xlsx, then append -Filter '*.xlsx' to the below line
Get-ChildItem -Path $Path -File |
Where-Object { $_.BaseName -match '^\d{8}_' } | # search files that have a date at the beginning
ForEach-Object {
# remove the starting date + underscore AND
# any repeated underscore + date from the end of the file name
# (the ones you tried and where the date was appended over and over again)
$name = $_.BaseName -replace '^\d{8}_|(_\d{8})*$'
$_ | Rename-Item -NewName ('{0}_{1:yyyyMMdd}{2}' -f $name, $_.LastWriteTime , $_.Extension)
}
Regex details:
Match this alternative (attempting the next alternative only if this one fails)
^ Assert position at the beginning of the string
\d Match a single character that is a “digit” (any decimal number in any Unicode script)
{8} Exactly 8 times
_ Match the character “_” literally
|
Or match this alternative (the entire match attempt fails if this one fails to match)
( Match the regex below and capture its match into backreference number 1
_ Match the character “_” literally
\d Match a single character that is a “digit” (any decimal number in any Unicode script)
{8} Exactly 8 times
)
Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
* You repeated the capturing group itself. The group will capture only the last iteration. Put a capturing group around the repeated group to capture all iterations.
Or, if you don’t want to capture anything, replace the capturing group with a non-capturing group to make your regex more efficient.
$ Assert position at the end of the string, or before the line break at the end of the string, if any (line feed)

How to convert a string containing 2 numbers to currency with powershell?

I have text files that contain 2 numbers separated by a '+' sign. Trying to figure out how to replace them with currency equivalent .
Example Strings:
20+2 would be converted to $0.20+$0.02 USD
1379+121 would be> $13.79+$1.21 USD
400+20 would be $4.00+$0.20 USD
and so on.
I have tried using a few angles but they do not work or provide odd results.
I tried to do it here by attempting to find by all patterns I think would come up .
.\Replace-FileString.ps1 "100+10" '$1.00+$0.10' $path1\*.txt -Overwrite
.\Replace-FileString.ps1 "1000+100" '$10.00+$1.00' $path1\*.txt -Overwrite
.\Replace-FileString.ps1 "300+30" '$3.00+$0.30' $path1\*.txt -Overwrite
.\Replace-FileString.ps1 "400+20" '$4.00+$0.20' $path1\*.txt -Overwrite
or this which just doesn't work.
Select-String -Path .\*txt -Pattern '[0-9][0-9]?[0-9]?[0-9]?[0-9]?\+[0-9][0-9]?[0-9]?[0-9]?[0-9]?' | ForEach-Object {$_ -replace ", ", $"} {$_ -replace "+", "+$"}
I tried to do it here by attempting to find by all patterns I think would come up
Don't try this - we're humans, and we won't think of all edge cases and even if we did, the amount of code we needed to write (or generate) would be ridiculous.
We need a more general solution here, and regex might indeed be helpful with this.
The pattern you describe could be expressed as three distinct parts:
1 or more consecutive digits
1 plus sign (+)
1 or more consecutive digits
With this in mind, let's start to simplifying the regex pattern to use:
\b\d+\+\d+\b
or, written out with explanations:
\b # a word boundary
\d+ # 1 or more digits
\+ # 1 literal plus sign
\d+ # 1 or more digits
\b # a word boundary
Now, in order to transform an absolute value of cents into dollars, we'll need to capture the digits on either side of the +, so let's add capture groups:
\b(\d+)\+(\d+)\b
Now, in order to do anything interesting with the captured groups, we can utilize the Regex.Replace() method - it can take a scriptblock as its substitution argument:
$InputString = '1000+10'
$RegexPattern = '\b(\d+)\+(\d+)\b'
$Substitution = {
param($Match)
$Results = foreach($Amount in $Match.Groups[1,2].Value){
$Dollars = [Math]::Floor(($Amount / 100))
$Cents = $Amount % 100
'${0:0}.{1:00}' -f $Dollars,$Cents
}
return $Results -join '+'
}
In the scriptblock above, we expect the two capture groups ($Match.Groups[1,2]), calculate the amount of dollars and cents, and then finally use the -f string format operator to make sure that the cents value is always two digits wide.
To do the substitution, invoke the Replace() method:
[regex]::Replace($InputString,$RegexPattern,$Substitution)
And there you go!
Applying to to a bunch of files is as easy as:
$RegexPattern = '\b(\d+)\+(\d+)\b'
$Substitution = {
param($Match)
$Results = foreach($Amount in $Match.Groups[1,2].Value){
$Dollars = [Math]::Floor(($Amount / 100))
$Cents = $Amount % 100
'${0:0}.{1:00}' -f $Dollars,$Cents
}
return $Results -join '+'
}
foreach($file in Get-ChildItem $path *.txt){
$Lines = Get-Content $file.FullName
$Lines |ForEach-Object {
[regex]::Replace($_, $RegexPattern, $Substitution)
} |Set-Content $file.FullName
}
this regular expression work too
\b\d{3,4}(?=\+)|\d{2,3}(?=\")
https://regex101.com/
Do you want something like this output?
$20+$2 would be converted to $0.20+$0.02 USD
$1379+$121 would be> $13.79+$1.21 USD
$400+$20 would be $4.00+$0.20 USD
Then, you may try this command in powershell.
(gc test.txt) -replace '\b(\d+)\+(\d+)\b','$$$1+$$$2' | sc test.txt
gc , sc : alias for get-content, set-content commands respectively
\b(\d+)\+(\d+)\b : match the target string (numbers+numbers) and capturing numbers to $1, $2 in order
$$ : $ must be escaped to indicate literal $ dollor character (what you want to place in front of numbers)
$1, $2 : back-reference to the captured value
test.txt : contains your sample text
Of course, this is applicable for multiple files like follows
gci '*.txt' -recurse | foreach-object{(gc $_ ) '\b(\d+)\+(\d+)\b','$$$1+$$$2' | sc $_ }
gci : alias for get-childitem command. In default, it returns list in the present directory. If you want to change the directory, then must use -path option and -include option.
-recurse option : enables to search sub-directory
Edited
If you want capturing & dividing values & replacing old value with new one like follows
$0.2+$0.02 would be converted to $0.20+$0.02 USD
$13.79+$1.21 would be> $13.79+$1.21 USD
$4+$0.2 would be $4.00+$0.20 USD
then, you may try this.
gci *.txt -recurse | % {(gc $_) | % { $_ -match "\b(\d+)\+(\d+)\b" > $null; $num1=[int]$matches[1]/100; $num2=[int]$matches[2]/100; $dol='$$'; $_ -replace "\b(\d+)\+(\d+)\b","$dol$num1+$dol$num2"}|sc $_}
This command search files in the present directory and sub-directory. If you don't want to search in sub-directory, then remove -recurse option. And if you want another path, then use -path option and -include option like follows.
gci -path "your_path" -include *.txt | % {(gc $_) ...
Other solutions seem excessively complicated, first turning the string to values and then back to strings. Looking at the examples, it is just chopping up a string and re-assembling it while ensuring that the different parts (dollars and cents) have the correct lengths:
('20+2','1379+121','400+20') -replace
'(\d+)\+(\d+)','00$1+00$2' -replace
'0*(\d+)(\d\d)\+0*(\d+)(\d\d)','$$$1.$2+$$$3.$4 USD'
$0.20+$0.02 USD
$13.79+$1.21 USD
$4.00+$0.20 USD
Explanation:
Substitute all the + separated cent values with 0 padded values so there is a minimum of three digits, i.e. at least one digit in the dollars and exactly 2 for the cents.
Collect the individual dollars and cents for each value into distinct capture groups while simultaneously discarding any extraneous leading zeroes.
Re-substitute the (just padded) strings with the appropriately formatted versions.
It is interesting to note how the second substitution relies on the greedy nature of *. The 0* will match just as many leading zeroes as will still leave enough for the remainder of the pattern.
You can put in the word boundary anchor (\b), at one or both ends of the patterns, if you have parts of a line where there are digits separated by + which are directly adjacent to other text and you want them to be NOT processed, otherwise it is unnecessary.
Note: the example above shows an array of String as input and producing an array of String (each element displayed on a separate line). When -Replace is applied to an array, it enumerates the array, applies the replace to each element and collects each (possibly replaced) element into a result array. The output of Get-Content is an array of String (enumerated by PowerShell when supplying a pipeline). Similarly, the 'input' to Set-Content is an array of String (possibly converted from a general Object[] and/or collected from pipeline input). Thus, to convert a file just use:
(gc somefile) -replace ... -replace ... | sc newfile
# or even
sc newfile ((gc somefile) -replace ... -replace ...)
# Set-Content [-Path] String[] [-Value] Object[]
In the above, newfile and somefile can be the same due to a nice feature of Set-Content whereby it does not even open/create its output file(s) until it has something to write. Thus,
#() | sc existingfile
does not destroy existingfile. Note, however, that
sc existingfile #()
does destroy existingfile. This is because the first example sends nothing to Set-Content while the second example gives Set-Content something (an empty array). Since the output from Get-Content is collected into an (anonymous) array before -Replace is applied, there is no conflict between Get-Content and Set-Content over accessing the same file. The functionally equivalent version
gc somefile | foreach { $_ -replace ... -replace ... } | sc newfile
does not work if newfile is somefile since Set-Content receives each (possibly substituted) line from Get-Content before the next one is read meaning Set-Content can't open the file because Get-Content still has it open.
This is a separate answer because it doesn't explain how to achieve the desired result (already did that) but explains why the listed attempts do not work (an educational motive).
If you're using Replace-FileString.ps1 from GitHub then not only are the examples not a general solution, it won't work as listed above because Replace-FileString.ps1 uses the Replace method of a [regex] object so "400+20" matches "40" then 1 or more "0" then "20". Similarly for other attempts. Note, no "+" is matched in the patterns so all fail (unless you have lines like "40020+125" which matches on the 40020). Just as well, the replacement includes the capture group specifier "$0" (as part of '$1.00+$0.10') and other specifiers. There are no capture groups specified in the pattern so all the group specifiers would be taken literally, except "$0" being the entire match (if found). Thus, "40020+125" would be replaced by substituting '$4.00+$0.20' giving "$4.00+40020.20" ($4='$4' and $0='40020'). Probably, no matches are found. Result -> files not changed. (Phew!)
As for the Select-String attempt, Select-String would probably have matched the required data since the pattern matched up to 5 digits on either side of a +. This would send the matching lines (and ignored the rest, if any) into the ForEach-Object as [Microsoft.PowerShell.Commands.MatchInfo] objects (not strings). (Aside: this is a common mistake by a lot of PowerShell, um, novices. They assume that what they see on the screen is the same as what is churning about inside PowerShell. This is far from the truth and probably leads to most of the confusion amongst new users. PowerShell processes entire objects and typically displays only a summary of the most useful bits.) Anyway, I am unsure what the ForEach-Object is trying to achieve, not least due to the apparent typo. There is at least one " missing in the first script block and possibly a comma also. The best I can interpret it is
{ $_ -replace ", ",", $" }
i.e. change every ", " into ", $". This assumes that the strings to be substituted are all preceded by ", ". Note: lone $ is not an error because it cannot be interpreted as a variable substitution (no following name or {) or capture reference (no following group specifier [0-9`+'_&]). The next script block is clearer, change every "+" into "+$". Unfortunately, again, the first string is interpreted as a regular expression and, unlike the lone $, a lone + here is an error. It needs to be escaped with \. However, even with these errors corrected, there are two big problems:
The default output from Select-String is a collection of [MatchInfo] objects which when (implicitly) converted to String for use as the LHS of -replace include the file name and line number, thereby corrupting the lines from the file. To use just the line itself, specify $_.Line.
A completely incorrect usage of the scriptblock parameters to ForEach-Object. While it would seem that the intent was to perform two replace operations, placing them in individual scriptblocks is an error. Even if it worked, it would output 2 separate partial replacements instead of one completed replacement since $_ is not updated between the two expressions. ($_ is writable!)
ForEach-Object has 3 basic scriptblock groups, 1 -Begin block, 1 -End block and all the rest collectively as the -Process blocks. (The -Parallel block is not relevant here.) The documentation mentions a group called -RemainingScripts but this is actually just an implementation construct to allow the -Process scriptblocks to be specified as individual parameters rather than collected into an array (similar to parameter arrays in C# and VB). I suspect this was done so that users could simply drop the parameter names (-Begin, -Process and -End) and treat the scriptblocks as if they were positional parameters even though, strictly speaking, only -Process is positional and expects an array of scriptblocks (i.e. separated by commas). The introduction of -RemainingScripts in PS3.0 (with attribute ValueFromRemainingArguments so it behaves like a parameter array) was probably done to tidy up what might have been a nasty kludge to get the user friendly behaviour prior to PS3.0. Or maybe it was just formalising what was already going on.
Anyway, back on topic. By specifying multiple scriptblocks, the first is treated as -Begin and, if there are more than 2, the last is treated as -End. Thus, for two scriptblocks, the first is -Begin and the other is -Process. Therefore, even if the first scriptblock were syntactically correct, it would only run once and then still do nothing since $_ is not assigned (=$null) in -Begin. The correct way would be to place both replacements, joined into a single expression, in one scriptblock:
{ $_.Line -replace ", ",", $" -replace "\+","+$" }
Of course, this is just describing how to get it to "work". It is not the correct solution to the problem in the original post (see other answer).

powershell extract number with regex [duplicate]

This question already has answers here:
How do I return only the matching regular expression when I select-string(grep) in PowerShell?
(8 answers)
Closed 4 years ago.
I need to extract only the numbers from external file. I am using the following command:
(Get-Content -Path .\log.html) | Select-String -Pattern 'load is'
It then returns:
<tr><td>server-67 load is: 0</td></tr>
<tr><td>server-68 load is: 5875</td></tr>
<tr><td>server-69 load is: 6077</td></tr>
<tr><td>server-70 load is: 6072</td></tr>
<tr><td>server-71 load is: 5846</td></tr>
<tr><td>server-72 load is: 1900</td></tr>
<tr><td>server-73 load is: 1900</td></tr>
I only need to extract the number portion.
How can I do it?
What distinguishes this question from the near-duplicate at "How do I return only the matching regular expression when I select-string(grep) in PowerShell?" is the desire to extract substrings of interest via surrounding in-line context not to be included in the match:
PS> Select-String '(?<=load is: )\d+' .\log.html | ForEach-Object { $_.Matches[0].Value }
0
5875
6077
6072
5846
1900
1900
If you want to output actual numbers, simply place [int] (for instance) before $_.Matches[0].Value to cast (convert) the text results to an integer.
Select-String can accept file paths directly, so for a single file or a group of files matched by a wildcard expression you generally don't need to pipe from Get-Content.
(For processing entire directory subtrees, pipe from Get-ChildItem -File -Recurse).
Regex '(?<=load is: )\d+' uses a (positive) lookbehind assertion ((?<=...)) to match part of each line without including what was matched in the result; only the \d+ part - a nonempty run of digits - is captured.
Select-String outputs [Microsoft.PowerShell.Commands.MatchInfo] instances whose .Matches property contains the results of regex matching operation; its .Value property contains what the regex captured.
In the case at hand, the lookbehind solution is probably simplest, but an alternative solution is to use a capture group, which is ultimately more flexible:
# Same output as above.
Select-String 'load is: (\d+)' .\log.html | ForEach-Object {$_.Matches[0].Groups[1].Value}
What the capture group (the parenthesized subexpression, (...)) matched is available on the output objects' .Matches.Groups collection, whose element at index 0 contains the overall match, and element 1 containing the 1st capture groups, 2 the 2nd, and so on.
Here's one possibility:
(Get-Content -Path .\log.html) |
Where-Object {$_ -match '^<tr><td>server-(?<Server>\d{1,}) load is: (?<load>\d{1,})</td></tr>$'} |
ForEach-Object {
[PsCustomObject]#{"ServerNumber"=$matches.Server;"ServerLoad"=$matches.Load}
}
This will give you output like this:
ServerNumber ServerLoad
------------ ----------
67 0
68 5875
69 6077
70 6072
71 5846
72 1900
73 1900

Extracting match from text file if subsequent lines contain specific strings

I'm trying to pull certain lines of data from multiple text file using a certain match of data. I have that part working (it matches on the strings that I have and pulling back the entire line). That's what I want, but I also need a certain line of data that occurs before the match (only when it matches). I also have that working, but its not 100% right.
I have tried to accomplish pulling the line above my match by using the -Context parameter. It seems to work, but in some cases it is merging data together from multiple matches and not pulling the line above my matches. Below is a sample of one of the files that I'm searching in:
TRN*2*0000012016120500397~
STC*A3:0x9210019*20170103*U*18535********String of data here
STC*A3:0x810049*20170103*U*0********String of Data here
STC*A3:0x39393b5*20170103*U*0********String of data here
STC*A3:0x810048*20170103*U*0********String of data here
STC*A3:0x3938edc*20170103*U*0********String of data here
STC*A3:0x3938edd*20170103*U*0********String of data here
STC*A3:0x9210019*20170103*U*0********String of data here
TRN*2*0000012016120500874~
STC*A3:0x9210019*20170103*U*18535********String of data here
STC*A3:0x39393b5*20170103*U*0********String of data here
STC*A3:0x3938edc*20170103*U*0********String of data here
STC*A3:0x3938edd*20170103*U*0********String of data here
STC*A3:0x9210019*20170103*U*0********String of data here
TRN*2*0000012016120500128~
STC*A3:0x810049*20170103*U*0********String of Data here
STC*A3:0x39393b5*20170103*U*0********String of data here
STC*A3:0x810024*20170103*U*0********String of data here
STC*A3:0x9210019*20170103*U*0********String of data here
TRN*2*0000012016120500345~
STC*A3:0x9210019*20170103*U*18535********String of data here
STC*A3:0x810049*20170103*U*0********String of Data here
STC*A3:0x39393b5*20170103*U*0********String of data here
STC*A3:0x3938edc*20170103*U*0********String of data here
TRN*2*0000012016120500500~
STC*A3:0x810048*20170103*U*18535********String of data here
TRN*2*0000012016120500345~
STC*A3:0x810049*20170103*U*18535********String of data here
I'm trying to pull the TRN*2 line only when the lines below each TRN*2 have STC*A3:0x810024 and STC*A3:0x810048 in them, but again getting inconsistent results.
Is there a way that I could search for the TRN*2 line and pull the TRN*2 and the lines below it that contain STC*A3:0x810024 and STC*A3:0x810048? If the lines below the TRN*2 line do not contain STC*A3:0x810024 and STC*A3:0x810048, then don't pull anything.
Here is my code so far:
$FilePath = "C:\Data\2017"
$files = Get-ChildItem -Path $FilePath -Recurse -Include *.277CA_UNWRAPPED
foreach ($file in $files) {
(Get-Content $file) |
Select-String -Pattern "STC*A3:0x810024","STC*A3:0x810048" -SimpleMatch -Context 1,0 |
Out-File -Append -Width 512 $FilePath\Output\test_results.txt
}
Your approach won't work, because you're selecting lines that contain STC*A3:0x810024 or STC*A3:0x810048 and the line before them. However, the preceding lines don't necessarily start with TRN. Even if they did, the statement would still produce TRN lines that are followed by any of the STC strings, not just lines that are followed by both STC strings.
What you actually want is split the files before lines starting with TRN, and then check each fragment if it contains both STC strings.
(Get-Content $file | Out-String) -split '(?m)^(?=TRN\*2)' | Where-Object {
$_.Contains('STC*A3:0x810024') -and
$_.Contains('STC*A3:0x810048')
} | ForEach-Object {
($_ -split '\r?\n')[0] # get just the 1st line from each fragment
} | Out-File -Append "$FilePath\Output\test_results.txt"
(?m)^(?=TRN\*2) is a regular expression matching the beginning of a line followed by the string "TRN*2". The (?=...) is a so-called positive lookahead assertion. It ensures that the "TRN*2" is not removed when splitting the string. (?m) is a modifier that makes ^ match the beginning of a line inside a multiline string rather than just the beginning of the string.

How to append a number to a RegEx region variable in PowerShell?

I have JPEG files in a folder named sequentially: table1.jpg, table2.jpg, table3.jpg, ..., table11.jpg
I need to do some processing on them, in sequential order, but a Get-ChildItem will return this (even with Sort):
table1.jpg
table10.jpg
table11.jpg
table2.jpg
table3.jpg
...
I would like to add a 0 to get them in the correct order:
table01.jpg
table02.jpg
table03.jpg
...
table11.jpg
I tried using RegEx with this command to preview the new names:
Get-ChildItem | % { $_.Name -replace "(.*[^0-9])([0-9]{1}\.jpg)",'$10$2' }
The idea is to get the first part of the name without any digit in first region, and one digit plus the extension in the second region. This will exclude files with two digits. And then I can replace by: first region + 0 + second region.
My problem is the "0" is seen as $10 instead of $1+"0", I don't know how to say it.
What would be the correct syntax? I tried "$10$2", "$1\0$2", "$1`0$2", '$1"0"$2'
You can use named groups:
$filename -replace "(?<first>.*[^0-9])(?<second>[0-9]{1}\.jpg)", '${first}0${second}'
The correct syntax for indicating a numbered backreference without ambiguity is ${1}.
Here's a corrected version of your statement:
Get-ChildItem | % { $_.Name -replace "(.*\D)(\d\.jpg)",'${1}0$2' }
Note: I also used \D, which is the built-in character class for [^0-9], and \d in place of [0-9].
'"$1"0$2'
This should do it .