Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I "split" a string in PowerShell using a string of multiple characters?

When using the .Split() operator on a string in PowerShell and trying to split using a string of more than one character, PowerShell exhibits weird behavior - it uses any of the characters in the string to split.

For example:

PS C:\Users\username> "One two three keyword four five".Split("keyword")
On
 t

 th









 f
u
 fiv

I do not know about you, but I was expecting the results to be an array like:

@("One two three "," four five")

How do I split a string, treating the "splitter" as a literal string? For those coming from VBScript, this is how the built-in Split() function behaved in VBScript.

A couple other notes:

  • I have done some searching and found some proposed solutions that use RegEx; I would prefer not to use it if it can be avoided.
  • I want a solution that works on all versions of PowerShell.
like image 867
Frank Lesniak Avatar asked Nov 19 '18 05:11

Frank Lesniak


2 Answers

There is no need to create a function.

You can use the split function in two different ways. If you use:

"One two three keyword four five".Split("keyword")

every single character inside the brackets is used as splitter. But if you instead use:

"One two three keyword four five" -Split ("keyword")

the string "keyword" is used as splitter.

like image 118
Tobias Avatar answered Sep 28 '22 15:09

Tobias


EDIT 2020-05-23: I've moved my code to GitHub, here, where I've made updates to cover a few edge cases: https://github.com/franklesniak/PowerShell_Resources/blob/master/Split-StringOnLiteralString.ps1


The -split operator expects RegEx, but can be made to do this well. However, the -split operator is only available on Windows PowerShell v3+, so it does not fit the requirements in the question.

A [regex] object has a Split() method that can handle this as well, but it expects RegEx as the "splitter". To get around this, we can use a second [regex] object and call the Escape() method to convert our literal string "splitter" into escaped RegEx.

Wrapping all this up into an easy to use function that works back to PowerShell v1 and also works on PowerShell Core v6.

function Split-StringOnLiteralString
{
    trap
    {
        Write-Error "An error occurred using the Split-StringOnLiteralString function. This was most likely caused by the arguments supplied not being strings"
    }

    if ($args.Length -ne 2) `
    {
        Write-Error "Split-StringOnLiteralString was called without supplying two arguments. The first argument should be the string to be split, and the second should be the string or character on which to split the string."
    } `
    else `
    {
        if (($args[0]).GetType().Name -ne "String") `
        {
            Write-Warning "The first argument supplied to Split-StringOnLiteralString was not a string. It will be attempted to be converted to a string. To avoid this warning, cast arguments to a string before calling Split-StringOnLiteralString."
            $strToSplit = [string]$args[0]
        } `
        else `
        {
            $strToSplit = $args[0]
        }

        if ((($args[1]).GetType().Name -ne "String") -and (($args[1]).GetType().Name -ne "Char")) `
        {
            Write-Warning "The second argument supplied to Split-StringOnLiteralString was not a string. It will be attempted to be converted to a string. To avoid this warning, cast arguments to a string before calling Split-StringOnLiteralString."
            $strSplitter = [string]$args[1]
        } `
        elseif (($args[1]).GetType().Name -eq "Char") `
        {
            $strSplitter = [string]$args[1]
        } `
        else `
        {
            $strSplitter = $args[1]
        }

        $strSplitterInRegEx = [regex]::Escape($strSplitter)

        [regex]::Split($strToSplit, $strSplitterInRegEx)
    }
}

Now, using the earlier example:

PS C:\Users\username> Split-StringOnLiteralString "One two three keyword four five" "keyword"
One two three
 four five

Volla!

like image 23
Frank Lesniak Avatar answered Sep 28 '22 14:09

Frank Lesniak