Andrew
Andrew

Reputation: 144

How to capture a specific line around a regex match in Windows PowerShell?

So, here the example below.

Application Details for the XYZ application:
    =========================================================

    Application Name:       XYXZW1
    Application Id:         XYZ353WERX

Application Details for the XYZ application:
    =========================================================

    Application Name:       XYXZW2
    Application Id:         XYZ353WERX

Application Details for the XYZ application:
    =========================================================
 
    Application Name:       XYXZW3
    Application Id:         XYZ353WERX
    Secret Key:             XYZ86JBHHSD

Application Details for the XYZ application:
    =========================================================

    Application Name:       XYXZW4
    Application Id:         XYZ353WERX
    Secret Key:             XYZ86JBHHSD

Now I want regex to match only those "Application Name: value" which contain the "Secret Key: value" pair in windows powershell. I am not sure this may be the regex reference and it's not working on windows powerShell.

$input_path = ‘C:\Users\Steve\Downloads\input.txt’
$regex = '\s*Application Name:\s*.*\r?\n\s*(?=Application Id \(ClientId\):\s*.*\r?\n\s*Secret Key:\s*.*)|\s*Secret Key:\s*.*'
select-string -Path $input_path -Pattern $regex -AllMatches |  Write-Output

All type of regexes work well on different platforms(tried few) but not on Windows powerShell.

The output should look like this:

   Application Name: XYXZW3 
   Secret Key: XYZ86JBHHSD 
   Application Name: XYXZW4 
   Secret Key: XYZ86JBHHSD 

Upvotes: 2

Views: 393

Answers (3)

The fourth bird
The fourth bird

Reputation: 163277

You can use 2 capture groups if you want to get the value for Application name and Secret key

^[\p{Zs}\t]*Application Name:[\p{Zs}\t]*(.+)\r?\n[\p{Zs}\t]*Application Id:.*\r?\n[\p{Zs}\t]*Secret Key:[\p{Zs}\t]*(.+)

The pattern matches:

  • ^ Start of string
  • [\p{Zs}\t]* Match optional horizontal whitespace chars
  • Application Name:[\p{Zs}\t]* Match Application Name: and optional spaces
  • (.+) Capture group 1, the value of for Application Name
  • \r?\n[\p{Zs}\t]* Match an newline and optional spaces
  • Application Id:.*\r?\n Match Applicatino Id: and the rest of the line
  • [\p{Zs}\t]*Secret Key:[\p{Zs}\t]* Match Secret Key: between optional spaces
  • (.+) Capture group 2, the value for Secret Key

Regex demo


If you only want to match the value of the application name where there is a secret key present, you could also use lookarounds to assert the Application Name: to the left, and Secret Key: to the right without crossing a line that starts with at least ==

(?<=^\s*Application Name:\s*)\S.*(?=(?:\r?\n(?!\s*==).*)*\r?\n\s*Secret Key:)

.NET regex demo

Upvotes: 1

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626747

I would rely on capturing groups here:

(?m)\bApplication Name:\s*(.+)(?:\n(?!\s*={3,}\r?$).*)*^\s*Secret Key:\s*(.+)
/\bApplication Name:\s*(.+)(?:\n(?!\s*={3,}\r?$).*)*^\s*Secret Key:\s*(.+)/gm

See the regex demo. Details:

  • \bApplication Name: - a whole word Application, space, Name, :`
  • \s* - zero or more whitespaces
  • (.+) - Group 1: one or more chars other than line break chars as many as possible
  • (?:\n(?!\s*={3,}\r?$).*)* - any amount of lines that do not start with zero or more whitespaces followed with three or more = chars up to the line end (\r? is added here only in case you will have to deal with regex where $ with /m flag does not match before a CR char, as in .NET)
  • ^ - start of a line
  • \s* - one or more whitespaces
  • Secret Key: - a Secret Key: string
  • \s* - zero or more whitespaces
  • (.+) - Group 2: one or more chars other than line break chars as many as possible

Upvotes: 1

vszholobov
vszholobov

Reputation: 2363

To do it you need to use look-arounds.

/(?<=Application Name:)[^\n]*(?=[^=]*(?=Secret Key))/g

It captures everything between Application Name: and \n if after it Secret Key appears before = char.

It also captures all space chars as well. If you don't want it and you know exact number of spaces, then you can change it to

/(?<=Application Name:\s{7})[^\n]*(?=[^=]*(?=Secret Key))/g

7 is the number of spaces to be skipped.

Demo.

Update:

To also catch Secret value change to

/(?<=Application Name:\s{7})[^\n]*(?=[^=]*(?=Secret Key))/g

You need to handle two matches in a row as a pair of Application Name and Secret Key.

Demo.

Upvotes: 2

Related Questions