A file name as below
$inpFiledev = "abc_XYZ.bak"
I need only XYZ in a variable to do a compare with other file name. i tried below:
[String]$findev = [regex]::match($inpFiledev ,'_*.').Value
Write-Host $findev
A file name as below
$inpFiledev = "abc_XYZ.bak"
I need only XYZ in a variable to do a compare with other file name. i tried below:
[String]$findev = [regex]::match($inpFiledev ,'_*.').Value
Write-Host $findev
Asterisks in regex don't behave in the same way as they do in filesystem listing commands. As it stands your regex is looking for underscore, repeated zero or more times, followed by any character (represented in regex by a period). So the regex finds zero underscores right at the start of the string, then it finds 'a', and that's the match it returns.
First, correct that bit:
'_*.'
Becomes "underscore, followed by any number of characters, followed by a literal period". The 'literal period' means we need to escape the period in the regex, by using \.
, remembering that period means any character:
'_.*\.'
_
underscore.*
any number of characters\.
a literal periodThat returns:
_XYZ.
So, not far off.
If you're looking to return something from between characters, you'll need to use capturing groups. Put parentheses around the bit you want to keep:
'_(.*)\.'
Then you'll need to use PowerShell regex groups to get the value:
[regex]::match($inpFiledev ,'_(.*)\.').Groups[1].Value
Which returns: XYZ
The number 1 in the Groups[1] just means the first capturing group, you can add as many as you like to the expression by using more parentheses, but you only need one in this case.
To complement mjsqu's helpful answer with two PowerShell-idiomatic alternatives:
For an overview of how regexes (regular expressions) are used in PowerShell, see Get-Help about_regular_expressions
.
Using -split
to split by _
and .
, extracting the resulting 3-element array's middle element:
PS> ("abc_XYZ.bak" -split '[_.]')[1]
XYZ
-split
's (first) RHS operand is a regex; regex [_.]
is a character set ([...]
) that matches a single char. that is either a literal _
or a literal .
Therefore, input abc_XYZ.bak
is broken into an array containing the strings abc
, XYZ
, and bak
. Applying index [1]
therefore extracts the middle token, XYZ
.Using -replace
to extract the token of interest via a capture group ((...)
, referred to in the replacement operand as $1
):
PS> "abc_XYZ.bak" -replace '^.+_([^.]+).+$', '$1'
XYZ
-replace
too operates on a regex as the first RHS operand - what to replace - whereas the second operand specifies what to replace the matched (sub)string with.
Regex ^.+_([^.]+).+$
:
^.+_
matches one or more (+
) characters (.
) at the start of the input (^
) - note how .
- used outside of a character set ([...]
) - is a regex metacharacter that represents any character (in a single-line input string).
([^.]+)
is a capture group ((...)
) that matches a negated character set ([^...]
): [^.]
matches any literal char. that isn't a literal .
, one or more times (+
).
Whatever matched the sub-expression inside (...)
can be referenced in the replacement operand as $<n>
, where <n>
represents the 1-based index of the capture group in the regex; in this case, $1
can be used to refer to this first (and only) capture group.
.+$
matches one or more (+
) remaining characters (.
) until the end of the input is reached ($
).
Replacement operand $1
simply refers to what the first capture group matched; in this case: XYZ
.
-replace
replacement operands, see this answer.Because you're using the [regex]
accelerator, you need the backslash to escape your end .
(if you want to match it), and you need a dot before your asterix to match any characters after your underscore. If the characters in between are all letters, then use \w+
$findev = [regex]::match($inpFiledev ,'_.*\.')
$findev
_XYZ.
this demos two other ways to get the desired info from the sample string. the 1st uses the basic .Split()
string method on the raw string. the 2nd presumes you are dealing with file objects and starts off by getting the .BaseName
for the file. that already removes the extension, so you need not bother doing it yourself.
if you are dealing with a large number of strings, and not file objects, then the previous regex answers will likely be faster. [grin]
$inpFiledev = 'abc_XYZ.bak'
$findev = $inpFiledev.Split('.')[0].Split('_')[-1]
# fake reading in a file with Get-Item or Get-ChildItem
$File = [System.IO.FileInfo]'c:\temp\testing\abc_XYZ.bak'
$WantedPart = $File.BaseName.Split('_')[-1]
'split on a string = {0}' -f $findev
'split on BaseName of file = {0}' -f $WantedPart
output ...
split on a string = XYZ
split on BaseName of file = XYZ