Левая панель не работает при использовании с регулярным выражением в Powershell - PullRequest
0 голосов
/ 01 января 2019

Вот два кодовых блока, которые показывают странное поведение, которое делает Leftpad.

$array = "z", "fg"
$array -replace "(\w{1,2})", '$1'.PadLeft(2, "0")
# output: z, fg

$array = "z", "fg"
$array -replace "(\w{1,2})", '$1'.PadLeft(3, "0")
# output: 0z, 0fg

Почему длина пэда не фиксирована?

EDIT: @LotPings

Я задаю этот вопрос еще раз, потому что ваш способ сделать это при применении к выражению rename-item не повлияет на файлы с квадратными скобками в его именах.

$file_names = ls "G:\Donwloads\Srt Downloads\15" -Filter *.txt
# the files are: "Data Types _ C# _ Tutorial 5.txt", "If Statements (con't) _ C# _ Tutorial 15.txt"
$file_names | 
    ForEach{
        if ($_.basename -match '^([^_]+)_[^\d]+(\d{1,2})$')
            { 
            $file_names | 
                Rename-Item -NewName `
                    { ($_.BaseName -replace $matches[0], ("{0:D2}. {1}" -f [int]$matches[2],$matches[1])) + $_.Extension }
            } 
           }

# output: 05. Data Types.txt
#         If Statements (con't) _ C# _ Tutorial 15.txt

Что касается .PadLeft, я подумал, чтоГруппа замены регулярных выражений имеет строковый тип, она должна работать с .PadLeft, но это не так.

Ответы [ 2 ]

0 голосов
/ 04 января 2019

Через несколько дней после того, как я задал этот вопрос, я случайно выяснил проблему.

$number Ссылки на группы захвата в синтаксисе -replace являются просто буквальными строками!

Powershell никогда не рассматривает их как нечто особенное, но движок Regex делает.Посмотрите на пример ниже:

$array = "z", "fg"  
$array -replace "(\w{1,2})", '$1'.Length
#output: 2
#        2

Выглядит странно?Как получается, что группа захвата $1 имеет длину 2 с "z" и "fg"?Ответ в том, что вычисляемая длина - это строка $1, а не "z", "fg"!
Давайте рассмотрим другой пример, на этот раз давайте заменим букву в группе захвата,посмотрим, что произойдет:

$array -replace "(\w{1,2})", '$1'.Replace("z", "6")
#output: z
#        fg

Вывод показывает, что .replace не относится к группе захвата 1.

$array -replace "(\w{1,2})", '$1'.Replace("1", "6")
#output: $6
#        $6

Видите?Заменяемая строка сама по себе $1.
Теперь нужно понять причину проблемы .padleft.PS добавьте буквенную строку $1 и покажите результат с содержимым группы.
Когда я добавляю его с помощью .Padleft(2, "0"), ничего не происходит, потому что сам "$ 1" имеет длину 2.

$array -replace "(\w{1,2})", '$1'.PadLeft(2, "0")
# output: z
#         fg

Если вместо этого я добавляю его с помощью .Padleft(3, "0"), на этот раз метод pad вступает в силу, он применяет дополнительные «0» к $1, но показывает результат с «0», предшествующим содержанию $1.

$array -replace "(\w{1,2})", '$1'.PadLeft(3, "0")
#output: 0z
#        0fg
0 голосов
/ 01 января 2019

Комментарий Ansgars к вашему последнему вопросу должен был показать, что ваше предположение о порядке действий было неверным.
И Lee_Dailey доказали, что вы ошиблись в другой раз.

Мой ответ на ваш предыдущий вопрос представил альтернативу, которая также работает здесь:

("Data Types _ C# _ Tutorial 5", "If Statements (con't) _ C# _ Tutorial 15") |
  ForEach{ 
    if ($_ -match '^([^_]+)_[^\d]+(\d{1,2})$'){
      "{0:D2}. {1}" -f [int]$matches[2],$matches[1]
    } 
  }

Пример вывода:

05. Data Types
15. If Statements (con't)

Последнее редактирование вашего вопроса фактически является новым вопросом ...

  • Rename-Item принимает ввод по каналу, поэтому ForEach-Object не требуется, если также используется
  • Where-Object с оператором -match для замены if.
    коллекция $ Matches предоставляется таким же образом.
  • Я действительно не знаю, почему вы настаиваете на использовании оператора -replace, когдасоздание NewName с нуля с помощью оператора -format.

$file_names = Get-ChildItem "G:\Donwloads\Srt Downloads\15" -Filter *.txt

$file_names | Where-Object BaseName -match '^([^_]+)_[^\d]+(\d{1,2})$' |
    Rename-Item -NewName {"{0:D2}. {1}{2}" -f [int]$matches[2],$matches[1].Trim(),$_.Extension} -WhatIf
...