Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to join parts with a separator in PowerShell

I need to join multple Url elements into one string, so I wrote the generic Join-Parts function:

filter Skip-Null { $_|?{ $_ } }

function Join-Parts
{
    param
    (
        $Parts = $null,
        $Separator = ''
    )

    [String]$s = ''
    $Parts | Skip-Null | ForEach-Object {
        $v = $_.ToString()
        if ($s -ne '')
        {
            if (-not ($s.EndsWith($Separator)))
            {
                if (-not ($v.StartsWith($Separator)))
                {
                    $s += $Separator
                }
                $s += $v
            }
            elseif ($v.StartsWith($Separator))
            {
                $s += $v.SubString($Separator.Length)
            }
        }
        else
        {
            $s = $v
        }
    }
    $s
}

Join-Parts -Separator '/' -Parts 'http://mysite','sub/subsub','/one/two/three'
Join-Parts -Separator '/' -Parts 'http://mysite',$null,'one/two/three'
Join-Parts -Separator '/' -Parts 'http://mysite','','/one/two/three'
Join-Parts -Separator '/' -Parts 'http://mysite/','',$null,'/one/two/three'
Join-Parts 1,2,'',3,4

Which returns as expected:

http://mysite/sub/subsub/one/two/three
http://mysite/one/two/three
http://mysite/one/two/three
http://mysite/one/two/three
1234

I have the feeling that this is not the smartest approach. Any ideas on a better approach?

UPDATE

Based on the answer by @sorens I changed the function into:

function Join-Parts
{
    param
    (
        $Parts = $null,
        $Separator = ''
    )

    ($Parts | ? { $_ } | % { ([string]$_).trim($Separator) } | ? { $_ } ) -join $Separator 
}
like image 300
Serge van den Oever Avatar asked Mar 06 '12 23:03

Serge van den Oever


1 Answers

Building on the answer from @mjolinor this one-liner passes all the tests in your question:

($parts | ? { $_ } | % { ([string]$_).trim('/') } | ? { $_ } ) -join '/' 

If you do not really care about the last test case (1,2,'',3,4) and can assume all inputs are strings you can shorten that to:

($parts | ? { $_ } | % { $_.trim('/') } | ? { $_ } ) -join '/' 

Note that I have two null/empty filters (? { $_ } ) present: the first strips nulls or empty strings from the input, which rectifies your test case with an empty string ('http:/fdfdfddf','','aa/bb'). The second is also necessary, catching input reduced to empty by the trim function.

If you really want to be fastidious about it, you should add one more trim to eliminate whitespace-only values since those are likely unwanted:

($parts | ? { $_ } | % { $_.trim('/').trim() } | ? { $_ } ) -join '/' 

With this last one these test case inputs will also return http://mysite/one/two:

$parts = 'http://mysite',''     ,'one/two' # empty
$parts = 'http://mysite','     ','one/two' # whitespace
$parts = 'http://mysite','    /','one/two' # trailing virgule
$parts = 'http://mysite','/    ','one/two' # leading virgule
$parts = 'http://mysite','/   /','one/two' # double virgule
like image 93
Michael Sorens Avatar answered Sep 25 '22 00:09

Michael Sorens