我正在尝试将此python模块移植到powershell
def str_to_tuple(s):
''' @source kindall at stackoverflow
http://stackoverflow.com/a/11887825/3447669
'''
return tuple(map(int, (s.split("."))))
最终的结果是,我将我的python代码移植到powershell中,以便在windows服务器上使用,因为团队的其他成员不了解python。
我有一个python脚本,可以比较两个应用程序版本号(即1.2.33和1.2.34)。上面的模块给了我一个元组,我可以在两个版本#s>或<之间进行比较;。
我专门测试在运行时提供的
$appVersion -lt $myVersionString
,所以-eq
对我们的脚本来说不是一个足够的测试。
我曾尝试使用$str.split()
将字符串元素放入数组中,但比较不起作用,而且我不想循环遍历每个数组来比较每个项,因为版本号可以是不同的长度。。。
Examples of lengths
1.2
2.3.4
2.3.44
感谢您的指导。
@Lee_Dayey指出,最简单的解决方案是将字符串强制转换为类型System.Version
:
PS/home/me>$s1='1.2.3'PS/hom/me>$s2='1.19.2'PS/home>[版本]$v1=$s1PS/home>[版]$v2=$s2PS-home/me>$v1主要次要内部版本修订----------------------1 2 3-1PS/home/me>$v2主要次要版本修订----------------------1 19 2-1PS/home/me>$v1-gt$v2错误PS/home/me>$v2-gt$v1True
我刚刚在Linux上的PowerShell Core 6.1中测试了它,它运行得很好,所以我希望它能在Mac OS上的PowerShell核心中运行;X也是。
然而,您也可以使用与Python中使用的方法完全相同的方法:从字符串创建元组。
PS/home/me>$s1='1.2.3'PS/hom/me>$s2='1.19.2'PS/home>[int[]]$v1=$s1.拆分('.'ple[int,int,int]'$a2PS/home/me>$t1第1项第2项第3项长度--------------------1 2 3 3PS/home/me>$t2第1项第2项第3项长度--------------------1 19 2 3PS/home/me>$t1-gt$t2错误PS/home/me>$t2-gt$t1True
请注意,拆分字符串会得到一个字符串数组,因此必须将其强制转换为整数数组,否则比较将无法正常工作(因为将使用字符串比较而不是数字比较)。
还要注意,类型定义(Tuple[<type>,<type>,...]
)中的元素数量必须与创建元组的数组中的元素数相匹配。这个答案显示了一个可重用的函数,用于从任意数组创建元组:
function New-Tuple {
Param(
[Parameter(
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true
)]
[ValidateCount(2,20)]
[array]$Values
)
Process {
$types = ($Values | ForEach-Object { $_.GetType().Name }) -join ','
New-Object "Tuple[$types]" $Values
}
}
这样你就可以改变
$t1 = New-Object 'Tuple[int,int,int]' $a1
$t2 = New-Object 'Tuple[int,int,int]' $a2
至
$t1 = New-Tuple $a1
$t2 = New-Tuple $a2
不过,要注意,比较元组需要它们具有相同数量的元素,否则比较将失败:
PS/home/me>$s3='1.19.2.1'PS/hom/me>[int[]]$a3=$s3.拆分('.')PS/home/me>1$t3=新对象'Tuple[int,int,int,int]'$a3PS-home/me>$t3-gt$t2无法将"(1,19,2,1)"与"(1、19,2)"进行比较。错误:"无法转换"(1,19,2)"类型的值">System.Tuple`3[[System.Int32,System.Private.CoreLib,Version=4.0.0.0,Culture=neutral,PublicKeyToken=7cec85d7bea7798e],[System.Int32,System.Private.CoreLib,版本=4.0.0.0,区域性=中性,PublicKeyToken=7ec85d7bea7798e],[System.Int32,System.Private.CoreLib,Version=4.0.0.0,Culture=neutral,PublicKeyToken=7cec85d7bea7798e]]"到类型">System.Tuple`4[System.Int32,System.Int32,System.Int32,System.Int32]".">在行:1个字符:1+$t3-gt$t2+~~~~~~~~~~~+CategoryInfo:InvalidOperation:(:)[],RuntimeException+FullyQualifiedErrorId:ComparisonFailure
因此,您必须确保版本元组始终具有相同的长度,例如,将0
元素附加到数组中,然后从结果中拾取前4个元素:
[int[]]$a = ('1.2'.Split('.') + (0, 0, 0, 0))[0..3]
$t = New-Object 'Tuple[int,int,int,int]' $a
[Version]
类型加速器没有这个问题,因为它创建了相同类型的对象,版本字符串中缺少的数字会自动填充值-1
。
PS/home/me>[版本]'1.2'主要次要版本修订----------------------1 2-1-1PS/home/me>[版本]'1.2.3’主要次要版本修订----------------------1 2 3-1PS/home/me>[版本]'1.2.3.4'主要次要版本修订----------------------1 2 3 4
已通知Donald.M&Lee_Dayey在评论中使用PoshSematicVersion与[version]解决了该解决方案(发现与PowerShell Core不兼容)
这是我在发布解决方案之前开发的解决方案,也许这可以与PowerShell Core一起使用——尽管不确定且未经测试。不管你愿不愿意,这是我的解决方案。
然而,str_to_tuple()函数是一个与原始函数非常相似的单行函数!从技术上讲,返回的不是元组,而是[System.Array],但可能存在类型元组。
(注意:具有负版本控制的未知行为-甚至存在。)
function str_to_tuple($s) {
return (($s.split(".") | ForEach-Object {([int]::parse($_))}))
}
# returns 1 if left ($lhs) is greater than right
# returns -1 if right ($rhs) is greater than left
# returns 0 if both right and left versions equal
function comp_vers {
Param([Parameter(Position=0,Mandatory=$true)]$lhs, [Parameter(Position=1,Mandatory=$true)]$rhs)
$min = [math]::Min($lhs.count,$rhs.count)
for($i=0; $i -lt $min; $i++) {
if ($lhs[$i] -eq $rhs[$i]) { continue }
if ($lhs[$i] -gt $rhs[$i]) { return 1 }
else { return -1 }
}
if ($lhs.count -eq $rhs.count) { return 0 }
# Section 2 - compares version numbers further (for example, 1.1 versus 1.1.0.0 - should be equal)
$max = [math]::Max($lhs.count,$rhs.count)
$is_lhs_high = ($l.count -eq $max)
for($i = $min; $i -lt $max; $i++) {
if ($is_lhs_high) {
if ($lhs[$i] -gt 0) { return 1 }
} else {
if ($rhs[$i] -gt 0) { return -1 }
}
}
return 0
}
function vers_output($comp) {
Switch($comp) {
1 { " > " }
0 { " = " }
-1 { " < " }
}
}
$tuple = str_to_tuple("1.1")
$tuple2 = str_to_tuple("1.1.0.0")
$tuple3 = str_to_tuple("3.3")
$tuple4 = str_to_tuple("2.2.2")
$tuple5 = str_to_tuple("2.2.2.0.1")
vers_output(comp_vers $tuple $tuple) # 1.1 = 1.1
vers_output(comp_vers $tuple2 $tuple) # 1.1.0.0 = 1.1
vers_output(comp_vers $tuple $tuple3) # 1.1 < 3.3
vers_output(comp_vers $tuple3 $tuple4) # 3.3 > 2.2.2
vers_output(comp_vers $tuple4 $tuple5) # 2.2.2 < 2.2.2.0.1