3

所以,我有一个看起来像这样的版本列表:

v1.1.0
v1.2.0
v1.3.0
v1.4.0
v1.5.0
v1.7.0
v1.8.0
v1.9.0
v2.0.0
v2.1.0
v2.10.0
v2.11.0
v2.12.0
v2.2.0
v2.3.0
v2.4.0
v2.5.0
v2.6.0
v2.7.0
v2.8.0
v2.9.0

问题是,它们的顺序不正确。我是 Powershell 的新手,所以我在尝试对它们进行排序时遇到了一些问题。我试图这样做:

$tags = git tag
$versions = $tags | %{ new-object System.Version ($_) } | sort

但我得到这个错误:

new-object:使用“1”参数调用“.ctor”的异常:“版本字符串部分太短或太长。” 在 line:1 char:24 + $versions = $tags | %{ 新对象 System.Version ($_) } | 排序 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand

任何人都可以帮忙吗?


更新

我使用了一种如下所示的解决方案:

$location = Get-Location
$path = $location.tostring() + "\CHANGELOG.md"
$tags = git tag
$i = 0

Clear-Content $path
Add-Content $path "Change Log"
Add-Content $path "=========="
Add-Content $path " "

$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }
$tags | Sort-Object $ToNatural

foreach($tag in $tags) 
{
    if (-NOT ($tag -match "v(\d+\.)(\d+\.)(\*|\d+)")) { continue }
    $i = $i + 1
    if ($i -eq 0) { continue }
    $tag
    If ($i -gt 0) {
        $previous = $tags[$i - 1]

        Add-Content $path " "
    }
}

这种工作,但所有标签似乎都是控制台记录的,它显示了这一点:

1.6.0
changeDeliveryFieldAccess
orders/autoComplete
returns/autoComplete
save-lines-dates
services/serviceDetails
tile-colours
users/confirmation
v0.1
v1.1.0
v1.2.0
v1.3.0
v1.4.0
v1.5.0
v1.7.0
v1.8.0
v1.9.0
v2.0.0
v2.1.0
v2.2.0
v2.3.0
v2.4.0
v2.5.0
v2.6.0
v2.7.0
v2.8.0
v2.9.0
v2.10.0
v2.11.0
v2.12.0
v.2.7.1

如您所见,其中有一些我不想要的。具体来说:

1.6.0
changeDeliveryFieldAccess
orders/autoComplete
returns/autoComplete
save-lines-dates
services/serviceDetails
tile-colours
users/confirmation
v.2.7.1

一旦从我的列表中清除了这些,那么顺序将是正确的:)


更新 2

所以我尝试了另一种希望更好的解决方案:

$location = 获取位置 $path = $location.tostring() + "\CHANGELOG.md" $tags = git tag $i = 0

Clear-Content $path
Add-Content $path "#Change Log"
Add-Content $path "=========="
Add-Content $path " "

$tags |
  Where-Object { $_.Substring(1) -as [version] } |
   Sort-Object { [version] $_.Substring(1) }

foreach($tag in $tags) {
    write-host "$($tag) is ok"
}

我不确定我这样做是否正确,但这是上述代码的输出:

1.6.0 is ok
changeDeliveryFieldAccess is ok
orders/autoComplete is ok
returns/autoComplete is ok
save-lines-dates is ok
services/serviceDetails is ok
tile-colours is ok
users/confirmation is ok
v.2.7.1 is ok
v0.1 is ok
v1.1.0 is ok
v1.2.0 is ok
v1.3.0 is ok
v1.4.0 is ok
v1.5.0 is ok
v1.7.0 is ok
v1.8.0 is ok
v1.9.0 is ok
v2.0.0 is ok
v2.1.0 is ok
v2.10.0 is ok
v2.11.0 is ok
v2.12.0 is ok
v2.2.0 is ok
v2.3.0 is ok
v2.4.0 is ok
v2.5.0 is ok
v2.6.0 is ok
v2.7.0 is ok
v2.8.0 is ok
v2.9.0 is ok
4

4 回答 4

7

tl;博士

您后来指出您的$tags数组还包含其他非版本字符串,因此必须过滤掉这些字符串:

$sortedVersionTags = $tags |
  Where-Object { $_.Substring(1) -as [version] } |
    Sort-Object { [version] $_.Substring(1) }
  • Where-Object { $_.Substring(1) -as [version] }只传递那些可以转换[version]( System.Version) 对象的字符串-as [version]——在删除v开头的 ( .Substring(1); 忽略删除v是你最初的问题) 之后;-as运算符要么返回成功转换的值,要么返回$null.

  • Sort-Object然后将过滤后的标签排序为版本号,从而产生正确的顺序 - 请参阅下一节以获取说明。

  • $sortedVersionTags然后仅以原始形式(作为v前缀字符串)接收版本标签,并正确排序。


版本号中的v前缀会阻止它们转换为[System.Version]实例;只需先将其删除(不是从输入本身中删除;只是暂时的,用于创建版本信息对象,例如v1.1.0-> 1.1.0)。

此外,您的命令可以简化:

# $tags is an array of lines, as output by `git tag`
$tags | Sort-Object { [version] $_.Substring(1) }
  • [version]是 PowerShell 中内置的类型加速器(简称),它指的是[System.Version]. [1]

  • 您可以简单地字符串强制转换为[version],这比使用更简洁和快速New-Object

  • Sort-Object接受一个表达式,通过一个脚本块 ( { ... }),代替一个固定的属性来排序;在脚本块内,$_指的是给定的输入对象;$_.Substring(1)只需删除第一个字符(v)。

    • 请注意,该表达式只是暂时使用,用于排序Sort-Object仍然输出原始字符串- 排序。

使用您的示例输入,上面的产量(注意如何v2.10.0正确排序 after v2.9.0,这不会是词法排序的情况):

v1.1.0
v1.2.0
v1.3.0
v1.4.0
v1.5.0
v1.7.0
v1.8.0
v1.9.0
v2.0.0
v2.1.0
v2.2.0
v2.3.0
v2.4.0
v2.5.0
v2.6.0
v2.7.0
v2.8.0
v2.9.0
v2.10.0
v2.11.0
v2.12.0

如果您宁愿输出System.Version实例而不是输入字符串,则命令会变得更加简单(PSv3+ 语法):

[version[]] $tags.Substring(1) | Sort-Object

如果有可能并非其中包含的所有字符串都$tags可以通过这种方式转换(由于没有v<version>格式),请使用以下(PSv4+ 语法):

# Reports non-convertible lines as non-terminating errors, but processes all others.
$tags.ForEach({ [version] $_.Substring(1) }) | Sort-Object

这种方法确保遇到无法转换的字符串不会破坏整个命令

  • 可以转换的是,和 是输出。

  • 无法转换的导致打印到控制台的错误,也会反映到$Error之后的自动收集中。您可以使用 抑制控制台输出2>$null


[1] 通常,PowerShell 允许您省略System.类型名称中的前缀。

于 2019-03-07T16:34:36.090 回答
2

对字符串中包含的任意长度的数字进行排序的更通用方法是Roman Kuzmin 的 $ToNatural

如果您将其存储在您的脚本/配置文件中:

$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }

您可以简单地使用:

$tags | Sort-Object $ToNatural

v1.1.0
v1.2.0
v1.3.0
...
v2.7.0
v2.8.0
v2.9.0
v2.10.0
v2.11.0
v2.12.0
于 2019-03-07T16:48:12.330 回答
0

我相信如果您想毫无问题地对它们进行排序,您需要将这些字符串正确地解析为版本对象。


$tags = @(
    'v1.1.0'
    'v1.2.0'
    'v1.3.0'
    'v1.4.0'
    'v1.5.0'
    'v1.7.0'
    'v1.8.0'
    'v1.9.0'
    'v2.0.0'
    'v2.1.0'
    'v2.10.0'
    'v2.11.0'
    'v2.12.0'
    'v2.2.0'
    'v2.3.0'
    'v2.4.0'
    'v2.5.0'
    'v2.6.0'
    'v2.7.0'
    'v2.8.0'
    'v2.9.0'
)


 #----------------------------------------------------------------------------# 
 #     Parse Will Fail As 'v' In String is Not Valid Semantic Versioning      # 
 #----------------------------------------------------------------------------# 
$tags | % { 
    $tag = $_
    $version = [version]::new()
    if ([version]::TryParse($tag, [ref]$version))
    {
        $version
    }
    else 
    {"ParseFailed--$($tag)"}

} | Sort-Object


 #----------------------------------------------------------------------------# 
 #                        Parsing String Successfully                         # 
 #----------------------------------------------------------------------------# 
$tags | % { 
    $tag = $_ -replace '[a-zA-Z]'
    $version = [version]::new()
    if ([version]::TryParse($tag, [ref]$version))
    {
        $version
    }
    else 
    {"ParseFailed--$($tag)"}

} | Sort-Object


ToString()如果您还想将其用作2.1.0字符串类型,则可以对返回的对象进行 a 。

于 2019-03-07T16:17:49.527 回答
0

问题是版本字符串中不允许使用“v”。如果先将其删除,则可以正确排序:

$tags | Sort-Object {[Version]($_ -replace "[a-zA-Z]","")}

请注意,这并没有真正删除“v”(它会在没有它的情况下创建一个副本),它仍然会出现在输出中:

v1.1.0
v1.2.0
v1.3.0
v1.4.0
v1.5.0
...
于 2019-03-07T16:35:14.500 回答