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

Posted

技术标签:

【中文标题】在 PowerShell 中使用分隔符连接部件的最佳方式【英文标题】:Best way to join parts with a separator in PowerShell 【发布时间】:2012-03-24 12:17:16 【问题描述】:

我需要将多个 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

按预期返回:

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

我觉得这不是最聪明的方法。有什么更好的方法吗?

更新

根据@sorens 的回答,我将函数更改为:

function Join-Parts

    param
    (
        $Parts = $null,
        $Separator = ''
    )

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

【问题讨论】:

你考虑过URIBuilder吗? 【参考方案1】:

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

function Combine-UriParts ($base, $path)

    return [Uri]::new([Uri]::new($base), $path).ToString()

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

【讨论】:

【参考方案2】:

Powershell 有一个-join 运算符。如需帮助,请输入帮助about_join

【讨论】:

【参考方案3】:

基于@mjolinor 的答案,这条单线通过了您问题中的所有测试:

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

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

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

请注意,我有 两个 空/空过滤器 (? $_ ):第一个从输入中去除空值或空字符串,它使用空字符串 ('http:/fdfdfddf','','aa/bb') 纠正您的测试用例。第二个也是必要的,通过 trim 函数捕获输入 reduced 为空。

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

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

对于最后一个,这些测试用例输入也将返回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

【讨论】:

@SergevandenOever,现在你让我想知道:-) 你几个月前就接受了我的回答,现在你也换了一个与几个月前不同的答案。然而,mjolinar 的答案只通过了您问题中五个测试用例中的两个,而我的则通过了所有五个。我错过了什么吗? 你完全正确!我在小屏幕上检查我没有回答的问题,忽略了我已经接受了你的答案!我换回来了!对不起:-) 我不赞成这个解决方案有一个非常重要的原因:可读性。没有高级 PowerShell 知识的任何人都无法阅读此解决方案,因此不应传播。 看起来在所有情况下第一个 ? $_ 都是多余的。 @roxton 首先感谢您注意到 PowerShell 已经发展,因此不再需要第一个 null/empty 过滤器!虽然我很欣赏你提出编辑建议的热情,但我拒绝了它,因为它失去了一些背景——阅读仍然显示过滤器的原始帖子的人会有点摸不着头脑,不知道他是如何从这里走到那里的。这就是为什么我认为您在上面的清晰、简洁的评论(它是多余的)更好。再次感谢!【参考方案4】:

这是一个使用 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()

输出:

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

更新 - 这里有一个小功能,应该能够结合你的 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) ','

输出:

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

【讨论】:

不知道这门课!尝试使用 System.Uri。多个部分的路径仍然存在问题。需要 mjoliner 他的答案!不过谢谢! @SergevandenOever 是的 System.Uri 是不可变版本。您可以通过访问 Uri 属性 $builder.Uri 从构建器获取 System.Uri 对象。 @SergevandenOever 我在答案中添加了一个小功能,应该能够组合您的片段。 嗨,安迪,感谢您提供的额外功能。不过看起来有点贵。 @msorens 的答案看起来轻松多了,所以我选择了他的答案。感谢您对我的问题的所有精彩思考!【参考方案5】:

你可以这样做:

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

【讨论】:

我无法编辑,但完美的答案。必须是: ($parts | foreach $_.trim('/')) -join '/' 谢谢。我错过了那个支架。 但仍然不完全正确:('http:/fdfdfddf','','aa/bb' | ForEach-Object $_.trim('/')) -join '/'变成http://fdfdfddf//aa/bb,注意多余的'/' GIGO 是什么意思? :-) 啊……垃圾进,垃圾出……但这正是我的问题:-) 我有多个部分来自 xml 配置文件。 我可以理解有多个部分。您的任何样本数据都没有表明它们会像那个烂摊子那样畸形。

以上是关于在 PowerShell 中使用分隔符连接部件的最佳方式的主要内容,如果未能解决你的问题,请参考以下文章

在 Powershell 中,按记录类型拆分大型文本文件的最有效方法是啥?

使用批处理/powershell 脚本设置自定义行分隔符

如何使用 wrap 小部件在下一行设置分隔符?

使用 powershell 将 Microsoft 表单 webpart 配置到现代页面

如何在视图之间的主页小部件中创建简单的分隔符/分隔符

通过Powershell在SharePoint Online上添加日历Web部件