Home > Software design >  Split string with "-"
Split string with "-"

Time:10-13

System.Management.Automation.RemoteException
name: CLD:HYB_Z_BASIS_ADMIN_SUPER
description: Basis Administrator
readOnly: 
roleReferences:
- roleTemplateAppId: it!b2455
  roleTemplateName: AuthGroup_Administrator
  name: AuthGroup_Administrator
- roleTemplateAppId: it!b2455
  roleTemplateName: AuthGroup_BusinessExpert
  name: AuthGroup_BusinessExpert
OK

I have above string, each line is delimited by CRLF. I am trying to extract and split below information into two rows delimited with "-" so I can get array of two rows but I am not getting correct result.

My code is:

$Myarray = $string -split "-"

- roleTemplateAppId: it!b2455
  roleTemplateName: AuthGroup_Administrator
  name: AuthGroup_Administrator
- roleTemplateAppId: it!b2455
  roleTemplateName: AuthGroup_BusinessExpert
  name: AuthGroup_BusinessExpert

CodePudding user response:

Use the System.Text.RegularExpressions.Regex.Matches() method to extract multiple matches from a string:

$string = @'
System.Management.Automation.RemoteException
name: CLD:HYB_Z_BASIS_ADMIN_SUPER
description: Basis Administrator
readOnly: 
roleReferences:
- roleTemplateAppId: it!b2455
  roleTemplateName: AuthGroup_Administrator
  name: AuthGroup_Administrator
- roleTemplateAppId: it!b2455
  roleTemplateName: AuthGroup_BusinessExpert
  name: AuthGroup_BusinessExpert
OK
'@

# Find all matches for the given regex and return the matched
# text (.Value) for each.
# Returns 2 three-line strings.
[regex]::Matches($string, '(?m)^- . \n. \n. ').Value

Note: The solution relies on a single, multi-line string as input. If you have an array of strings, join them with [Environment]::NewLine first; e.g. $multilineString = 'foo', 'bar' -join [Environment]::NewLine; you can also apply this technique to output captured from external programs - see the bottom section of this answer.

For a detailed explanation of regex (?m)^- . \n. and the ability to experiment with it, see this regex101.com page.

Note:

  • As of PowerShell 7.2, -match, PowerShell's regular-expression matching operator, only ever finds at most one match; the need to resort to a .NET API for multiple matches introduces significant complexity; GitHub issue #7867 proposes introducing a -matchall operator to remedy that - while the proposal has been green-lit, no one has stepped up to implement it yet.

As for what you tried:

-split "-":

  • tokenizes the entire string, so you'll get unrelated information that requires post-filtering
  • excludes the - from the resulting tokens (since they act as the separators), which makes it harder to filter out the relevant tokens
  • doesn't limit the tokens to only their first 2 lines.

A solution using -split, is possible, but requires additional use of -match, which makes the solution both more complex and less efficient:

# Same output as above.
$string -split '(?m)(^- . \n. \n. )' -match '^- '

Enclosing the relevant part of the regex in (...), i.e. making it a capture group, causes -split to include the group's matches in the tokens returned; -match '^- ' then filters out all tokens that do not start with - , leaving only the 2 two-line strings of interest.

  • Related