Puneet Tiwari
Puneet Tiwari

Reputation: 41

Split string in powershell with space

I have a string as "Device: ILO 5 Firmware Version : 2:33 Firmware date : 10-10-2020" I want to split this string as below in an array

ILO 5
2:33
10-10-2020

How can it be done in powershell?

Upvotes: 1

Views: 2872

Answers (5)

Doug Maurer
Doug Maurer

Reputation: 8868

Here's another approach using regex that may be easier to read.

# store the string for the following demonstrations
$str = "Device: ILO 5 Firmware Version : 2:33 Firmware date : 10-10-2020"

$str -split '\s*:\s{1,}|\s(?!\d)'

This will give us the following array

Device
ILO 5
Firmware
Version
2:33
Firmware
date
10-10-2020

Now we just pick out the desired values

$device,$fwversion,$fwdate = ($str -split '\s*:\s{1,}|\s(?!\d)')[1,4,7]

[PSCustomObject]@{
    Device    = $device
    FWVersion = $fwversion
    FWDate    = $fwdate
}

Output

Device FWVersion FWDate    
------ --------- ------    
ILO 5  2:33      10-10-2020

You could also use pass all the elements into a ForEach-Object loop like this.

,($str -split '\s*:\s{1,}|\s(?!\d)') | ForEach-Object {
    [PSCustomObject]@{
        Device    = $_[1]
        FWVersion = $_[4]
        FWDate    = $_[7]
    }
}

Note the comma that makes the output get passed through as part of an array.

The regex pattern splits on a colon that is followed by at least 1 space and has an optional space in front of it OR a space that is not followed by a numeric digit.

Upvotes: 0

mklement0
mklement0

Reputation: 437176

A generalized solution, which:

  • doesn't require knowing the field names in advance.
  • returns the field values only, as an array (as stipulated in your question - see bottom section if want to capture name-value pairs):
# Sample input string.
$str = 'Device: ILO 5 Firmware Version : 2:33 Firmware date : 10-10-2020'

# Split so as to only return field *values*.
$str -split '(?:^| +)\w+ ?\w* *: +' -ne ''

Assumptions:

  • No value contains substring ': '
  • Names contain only letters and _ and at most one space (i.e. are composed of one or two words).

Output:

ILO 5
2:33
10-10-2020
  • For an explanation of the above regex used with the -split operator, including the ability to experiment with it, see this regex101.com page.

  • -ne '' filters out the unwanted empty token that results from the regex also matching at the start of the input string.


To also capture the field names, and return an (ordered) hashtable or [pscustomobject], more work is needed:

# Sample input string.
$str = 'Device: ILO 5 Firmware Version : 2:33 Firmware date : 10-10-2020'

# Split into field names and values.
# Note the capture group - (...) - around the sub-expresssion
# that matches the field name. 
# -split includes capture-group matches in the result.
$namesAndValues = $str -split '(?:^| +)(\w+ ?\w*) *: +' -ne ''

# Construct an ordered hashtable from the name-value pairs
# You can easily convert it to a [pscustomobject] with: [pscustomobject] $result
$result = [ordered] @{}
for ($i = 0; $i -lt $namesAndValues.Count; $i += 2) {
  $result[$namesAndValues[$i]] = $namesAndValues[$i+1]
}

# Output the result:
$result

Output:

Name                           Value
----                           -----
Device                         ILO 5
Firmware Version               2:33
Firmware date                  10-10-2020

Upvotes: 1

js2010
js2010

Reputation: 27428

You can split the string on whitespace, but ILO and 5 will be two different array elements. The comma operator has a higher precedence than the join operator, hence the parentheses.

$string = 'Device: ILO 5 Firmware Version : 2:33 Firmware date : 10-10-2020'
$split = -split $string
($split[1,2] -join ' '),$split[6,10]

ILO 5
2:33
10-10-2020

Upvotes: 0

Jack van Deur
Jack van Deur

Reputation: 59

This might be ugly and there might be other ways but this is one way to do it:

First create an empty array:

$Array = @()

Get all the elements in a temp array:

$TempArray = "Device: ILO 5 Firmware Version : 2:33 Firmware date : 10-10-2020" -split(' ')

Next add the first values in the temparray, index 1 and 2, as a string:

$array += $temparray[1..2] -as [string]

Then add the others:

$Array += $temparray[6]
$Array += $temparray[-1]

This adds the sixth and the last element (-1). The result is:

ILO 5
2:33
10-10-2020

Upvotes: 0

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174465

You could use a regular expression to match and extract the values:

$string = "Device: ILO 5 Firmware Version : 2:33 Firmware date : 10-10-2020"

if($string -match 'Device:\s*(.*?)\s*Firmware Version :\s*(.*?)\s*Firmware date :\s*([\d\-]+)'){
  [pscustomobject]@{
    Device = $Matches[1]
    FWVersion = $Matches[2]
    FWDate = $Matches[3]
  }
}

\s* matches 0 or more spaces, .*? matches 0 or more of any characters, non-greedily, and [\d\-]+ will find any sequence of one or more characters that are either digits or -. The () around .*? and [\d\-]+ instructs the regex engine to capture the matching values, which is how we can then extract those values from the automatic $Matches variable afterwards.

This should produce an object with those three properties:

Device FWVersion FWDate
------ --------- ------
ILO 5  2:33      10-10-2020

Upvotes: 0

Related Questions