Используйте кортеж в стиле Python для сравнения в powershell - PullRequest
0 голосов
/ 10 февраля 2019

Я пытаюсь перенести этот модуль 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, который сравнивает 2 номера версий приложения (т.е. 1.2.33 и 1.2.34). Приведенный выше модуль дает мне кортеж, который я могу сравнить между 2 версиями #s> или <.</p>

Я специально тестирую $appVersion -lt $myVersionString, который поставляется во время выполнения, поэтому -eq недостаточно для нашего скрипта.

Я пытался использовать $str.split(), чтобы поместить строковые элементы в массив, однако сравнение не работает, и я не хотел перебирать каждый массив для сравнения каждого элемента, так как номера версий могут быть разной длины ...

Examples of lengths
1.2 
2.3.4 
2.3.44

Любое руководство с благодарностью.

Ответы [ 2 ]

0 голосов
/ 10 февраля 2019

Как указал @Lee_Dailey, самым простым решением было бы приведение строк к типу System.Version:

PS /home/me> <b>$s1 = '1.2.3'</b>
PS /home/me> <b>$s2 = '1.19.2'</b>
PS /home/me> <b>[Version]$v1 = $s1</b>
PS /home/me> <b>[Version]$v2 = $s2</b>
PS /home/me> <b>$v1</b>

Major  Minor  Build  Revision
-----  -----  -----  --------
1      2      3      -1

PS /home/me> <b>$v2</b>

Major  Minor  Build  Revision
-----  -----  -----  --------
1      19     2      -1

PS /home/me> <b>$v1 -gt $v2</b>
False
PS /home/me> <b>$v2 -gt $v1</b>
True

Я только что протестировал это в PowerShell Core 6.1 в Linux, и он работал просто отлично, поэтомуЯ ожидаю, что он будет работать и в PowerShell Core на Mac OS X.

Однако вы также можете использовать тот же подход, который вы используете в Python: создавать кортежи изstrings.

PS /home/me> <b>$s1 = '1.2.3'</b>
PS /home/me> <b>$s2 = '1.19.2'</b>
PS /home/me> <b>[int[]]$v1 = $s1.Split('.')</b>
PS /home/me> <b>[int[]]$v2 = $s2.Split('.')</b>
PS /home/me> <b>$t1 = New-Object 'Tuple[int,int,int]' $a1</b>
PS /home/me> <b>$t2 = New-Object 'Tuple[int,int,int]' $a2</b>
PS /home/me> <b>$t1</b>

Item1 Item2 Item3 Length
----- ----- ----- ------
    1     2     3      3

PS /home/me> <b>$t2</b>

Item1 Item2 Item3 Length
----- ----- ----- ------
    1    19     2      3

PS /home/me> <b>$t1 -gt $t2</b>
False
PS /home/me> <b>$t2 -gt $t1</b>
True

Обратите внимание, что разбиение строки даст вам строковый массив, поэтому вы ДОЛЖНЫ привести его к целочисленному массиву, иначе сравнения не будут работать правильно (так как сравнения строк, а не числовые сравненияиспользоваться).

Обратите также внимание, что количество элементов в определении типа (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> <b>$s3 = '1.19.2.1'</b>
PS /home/me> <b>[int[]]$a3 = $s3.Split('.')</b>
PS /home/me> <b>$t3 = New-Object 'Tuple[int,int,int,int]' $a3</b>
PS /home/me> <b>$t3 -gt $t2</b>
<i>Could not compare "(1, 19, 2, 1)" to "(1, 19, 2)". Error: "Cannot convert the
"(1, 19, 2)" value of type "<b>System.Tuple`3</b>[[System.Int32, System.Private.CoreLib,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32,
System.Private.CoreLib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]" to type
"<b>System.Tuple`4</b>[System.Int32,System.Int32,System.Int32,System.Int32]"."</i>
At line:1 char: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> <b>[Version]'1.2'</b>

Major  Minor  Build  Revision
-----  -----  -----  --------
1      2      -1     -1

PS /home/me> <b>[Version]'1.2.3'</b>

Major  Minor  Build  Revision
-----  -----  -----  --------
1      2      3      -1

PS /home/me> <b>[Version]'1.2.3.4'</b>

Major  Minor  Build  Revision
-----  -----  -----  --------
1      2      3      4
0 голосов
/ 10 февраля 2019

Замечено Donald.M & Lee_Dailey решили проблему в комментариях, используя PoshSematicVersion против [версия]. (было обнаружено, что оно не совместимо с 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...