2

I am using this to find if file name contains exactly 7 digits

if ($file.Name -match '\D(\d{7})(?:\D|$)') {
    $result = $matches[1]
}

The problem is when there is a file name that contains 2 groups of 7 digits for an example:

patch-8.6.22 (1329214-1396826-Increase timeout.zip 

In this case the result will be the first one (1329214). For most cases there is only one number so the regex is working but I must to recognize if there is more than 1 group and integrated into the if ()

Bandit
  • 399
  • 3
  • 10

1 Answers1

0
  • The -match operator only ever looks for one match.

  • To get multiple ones, you must currently use the underlying .NET APIs directly, specifically [regex]::Matches():

    • Note: There's a green-lighted proposal to implement a -matchall operator, but as of PowerShell 7.3.0 it hasn't been implemented yet - see GitHub issue #7867.
# Sample input.
$file = [pscustomobject] @{ Name = 'patch-8.6.22 (1329214-1396826-Increase timeout.zip' }

# Note: 
# * If *nothing* matches, $result will contain $null
# * If *one* substring matches, return will be a single string.
# * If *two or more* substrings match, return will be an *array* of strings.
$result = ([regex]::Matches($file.Name, '(?<=\D)\d{7}(?=\D|$)')).Value
  • .Value uses member-access enumeration to extract matching substrings, if any, from the elements of the collection returned by [regex]::Matches().

  • I've tweaked the regex to use lookaround assertions ((?<=/...) and (?=...)) so that only the substrings of interest are captured.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Thank you @mklement(). there is a reason why the file name is pscustom object? Can I use this also for get a 7 digit number from "\\XXXXXX.com\global\Patch Managment\1399771\" right? I don't familiar with the lookaround assertions you added ands will be happy for more explanation what it does and why the original ?:\ replaced with ?= – Bandit Dec 02 '22 at 19:02
  • 1
    My pleasure, @Bandit. `[pscustomobject]` was just used as a placeholder for the `[System.IO.FileInfo]` instances as output by `Get-ChildItem` that I presume you'll be working with. Yes, ``\\XXXXXX.com\global\Patch Managment\1399771\`` should work too (if the number is in the _parent directory's path_ rather than in the file _name_, you'll have to match against `.FullName`). The linked rege101.com page explains the regex in detail, but in short: `(?<=...)` looks _behind_ (to the left), without including what the subexpression matches in the match, and `(?=...)` looks _ahead_ (to the right). – mklement0 Dec 02 '22 at 19:13
  • Thanks Why not like this: '(?<=\D)\d{7}(?=:\D|$)' In the original regex was ":"why I don't need it anymore? – Bandit Dec 02 '22 at 19:42
  • As you can see the web is not working for me https://regex101.com/r/8DLQXC/1 – Bandit Dec 02 '22 at 19:53
  • 1
    @Bandit, your regex has a _trailing newline_, that's why it's not working on regex101.com. You can verify that the regex from this answer works with your other sample input as well as follows: `[regex]::Matches('Patch_1399771 + 1254877 ', '(?<=\D)\d{7}(?=\D|$)').Value`. As for `:` - `(?:...)` is an unrelated construct it is a _non-capturing group_. You don't need it, if you use a lookahead assertion instead. – mklement0 Dec 02 '22 at 20:12
  • Thank you @mklement() I am wondering why I need both looks behind and ahead if the match starts from left to right – Bandit Dec 03 '22 at 05:58
  • @Bandit: The look-behind assertion ensures that no digit _precedes_ your 7-digit run, and the look-ahead assertion ensures that none _follows_ it. – mklement0 Dec 03 '22 at 15:04