在PowerShell中使用分隔符连接部件的最佳方法

Ser*_*ver 5 powershell powershell-2.0

我需要将多个Url元素连接成一个字符串,因此我编写了通用的Join-Parts函数:

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
Run Code Online (Sandbox Code Playgroud)

哪个按预期返回:

http://mysite/sub/subsub/one/two/three
http://mysite/one/two/three
http://mysite/one/two/three
http://mysite/one/two/three
1234
Run Code Online (Sandbox Code Playgroud)

我觉得这不是最聪明的方法.关于更好的方法的任何想法?

UPDATE

基于@sorens的答案,我将功能更改为:

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

    ($Parts | ? { $_ } | % { ([string]$_).trim($Separator) } | ? { $_ } ) -join $Separator 
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*ens 8

在@mjolinor的答案的基础上,这个单行程传递了你问题中的所有测试:

($parts | ? { $_ } | % { ([string]$_).trim('/') } | ? { $_ } ) -join '/' 
Run Code Online (Sandbox Code Playgroud)

如果您并不真正关心最后一个测试用例(1,2,'',3,4)并且可以假设所有输入都是字符串,则可以将其缩短为:

($parts | ? { $_ } | % { $_.trim('/') } | ? { $_ } ) -join '/' 
Run Code Online (Sandbox Code Playgroud)

请注意,我有两个空/空过滤器(? { $_ } ):第一个从输入中剥离空值或空字符串,这将使用空字符串纠正您的测试用例('http:/fdfdfddf','','aa/bb').第二个也是必要的,通过修剪功能将输入减少为空.

如果你真的想要对它很挑剔,你应该再添加一个修剪来消除只有空白的值,因为那些可能是不需要的:

($parts | ? { $_ } | % { $_.trim('/').trim() } | ? { $_ } ) -join '/' 
Run Code Online (Sandbox Code Playgroud)

使用最后一个这些测试用例输入也将返回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
Run Code Online (Sandbox Code Playgroud)


mjo*_*nor 6

你可以这样做:

($parts | foreach {$_.trim('/'))} -join '/'
Run Code Online (Sandbox Code Playgroud)


Oha*_*der 6

从 Path.Combine for URL 的最佳答案中汲取灵感

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

应该很容易扩展到多个部分


And*_*ndi 5

以下是使用UriBuilder类创建URL的示例:

$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()
Run Code Online (Sandbox Code Playgroud)

输出:

https://www.myhost.com:8443/folder/subfolder/page.aspx
Run Code Online (Sandbox Code Playgroud)

更新 - 这是一个应该能够组合您的URL部分的小功能:

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) ','
Run Code Online (Sandbox Code Playgroud)

输出:

http://mysite/sub/subsub/one/two/three
http://mysite/one/two/three
http://mysite/one/two/three
1,2,3,4
Run Code Online (Sandbox Code Playgroud)