Best way to join delimited parts in PowerShell

I need to combine multiple Url elements into one string, so I wrote a 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

      

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 a feeling that this is not the smartest approach. Any ideas on a better approach?

UPDATE

Based on @ sorens answer, I changed the function to:

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

    ($Parts | ? { $_ } | % { ([string]$_).trim($Separator) } | ? { $_ } ) -join $Separator 
}

      

+3


source to share


5 answers


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

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

      

If you don't really care about the last test case (1,2,'',3,4)

and can assume that all inputs are strings, you can shorten this:

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

      

Note that I have two empty / empty (? { $_ } )

present filters , first strokes of zeros or empty strings from the input, which allows you to fix your test case with an empty string ('http:/fdfdfddf','','aa/bb')

. The second is also necessary, catching the input reduced to empty with the trim function.



If you really want to be squeamish, you should add another trim to exclude whitespace-only values, as they are probably not desirable:

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

      

With this latter, 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

      

+6


source


Here's an example of generating URLs using the UriBuilder class:

$builder = New-Object System.UriBuilder
$builder.Host = "www.myhost.com"
$builder.Path = ('folder', 'subfolder', 'page.aspx' -join '/')
$builder.Port = 8443
$builder.Scheme = 'https'
$builder.ToString()

      

Outputs:

https://www.myhost.com:8443/folder/subfolder/page.aspx

      



Update - here's a little function that should be able to combine your URL parts:

function Join-Parts {
    param ([string[]] $Parts, [string] $Seperator = '')
    $search = '(?<!:)' + [regex]::Escape($Seperator) + '+'  #Replace multiples except in front of a colon for URLs.
    $replace = $Seperator
    ($Parts | ? {$_ -and $_.Trim().Length}) -join $Seperator -replace $search, $replace
}

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

      

Outputs:

http://mysite/sub/subsub/one/two/three
http://mysite/one/two/three
http://mysite/one/two/three
1,2,3,4

      

+5


source


You can do something like this:

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

      

+5


source


Powershell has an operator -join

. for help help help about_join

+2


source


Draw inspiration from the main answer along the way. Combine URLs?

function Combine-UriParts ($base, $path)
{
    return [Uri]::new([Uri]::new($base), $path).ToString()
}

      

Should be easy enough to spread over multiple parts

0


source







All Articles