Лучший способ объединить детали с разделителем в PowerShell - PullRequest
5 голосов
/ 07 марта 2012

Мне нужно объединить несколько элементов 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

У меня такое ощущение, что это не самый умный подход. Есть идеи по поводу лучшего подхода?

UPDATE

Основываясь на ответе @sorens, я изменил функцию на:

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

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

Ответы [ 5 ]

8 голосов
/ 08 марта 2012

Опираясь на ответ @mjolinor, этот однострочник проходит все тесты по вашему вопросу:

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

Если вы на самом деле не заботитесь о последнем тестовом примере (1,2,'',3,4) и можете считать, что все входные данные являются строками, вы можете сократить это до:

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

Обратите внимание, что у меня есть два пустых / пустых фильтра (? { $_ } ) присутствует: первый удаляет пустые или пустые строки из ввода, что исправляет ваш тестовый случай с пустой строкой ('http:/fdfdfddf','','aa/bb'). Второе также необходимо, перехватывая входные данные , уменьшенные до пустых с помощью функции обрезки.

Если вы действительно хотите быть разборчивым в этом, вам следует добавить еще одно усечение, чтобы исключить только пробельные значения, поскольку они, вероятно, нежелательны:

($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
5 голосов
/ 07 марта 2012

Вот пример создания URL с использованием класса UriBuilder:

$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
5 голосов
/ 07 марта 2012

Вы можете сделать что-то вроде этого:

($parts | foreach {$_.trim('/'))} -join '/'
2 голосов
/ 06 декабря 2018

Черпать вдохновение из топ-ответа на Path.Combine для URL?

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

Должно быть достаточно легко распространяться на несколько частей

2 голосов
/ 07 марта 2012

Powershell имеет оператор -join. для справки введите help about_join

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...