Regex заменяет мультилинии в powershell - PullRequest
0 голосов
/ 15 октября 2018

Я хочу заменить эти строки в моем AssemblyInfo.cs, закодированном в UTF-8, Windows CRLF в конце каждой строки

<<<<<<< HEAD
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]
=======
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")]
>>>>>>> v1_final_release

на эти

[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]

.Итак, у меня есть скрипт powershell, который будет анализировать все мои файлы и выполнять замену.

Регулярное выражение, которое я готовлю в regex101: это и работает на 101:

<<<<<<<\sHEAD\n\[assembly:\sAssemblyVersion\("2\.0\.0\.0"\)\]\n\[assembly:\sAssemblyFileVersion\("2\.0\.0\.0"\)\]\n=======\n\[assembly:\sAssemblyVersion\("1\.1\.0\.0"\)\]\n\[assembly: AssemblyFileVersion\("1\.1\.0\.0"\)\]\n>>>>>>>\sv1_final_release

Мне не удается заставить -relace работать на новых строках,Но при таргетинге только на <<<<<<<\sHEAD оно совпадает и производится замена.

Не удалось выполнить все следующие варианты:

  • <<<<<<<\sHEAD\n\[assembly: без ошибок без замены
  • <<<<<<<\sHEAD\r\n\[assembly: без ошибок без замены
  • <<<<<<<\sHEADr n\[assembly: без ошибок без замены, write-host печатает его как <<<<<<<\sHEAD \[assembly:

Это не о /gm или (*CRLF)

Моя инструкция PowerShell для информации:

$ConflictVersionRegex = "<<<<<<<\sHEAD\n\[assembly:\sAssemblyVersion\(`"2\.0\.0\.0`"\)\]\n\[assembly:\sAssemblyFileVersion\(`"2\.0\.0\.0`"\)\]\n=======\n\[assembly:\sAssemblyVersion\(`"1\.1\.0\.0`"\)\]\n\[assembly: AssemblyFileVersion\(`"1\.1\.0\.0`"\)\]\n>>>>>>>\sv1_final_release" 
$ConflictVersionRegexTest = "<<<<<<<\sHEAD`r`n\[assembly:" 
$fileContent = Get-Content($filePath)   
$filecontent = $filecontent -replace $ConflictVersionRegexTest, $AssemblyNewVersion
[System.IO.File]::WriteAllLines($filePath, $fileContent, $Utf8NoBomEncoding)

Чего мне не хватает?Почему он не заменяет?

Большое спасибо

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

На основании отзывов от Poutrathor (OP) возникли две проблемы:

  • Основная проблема заключалась в том, что Get-Content($filePath)(который должен быть записан как
    Get-Content $filePath [1] ) читает файл строка за строкой , что приводит к массиву Строки при захвате в переменную.
    -replace затем работает с каждой входной строкой индивидуально , что означает, что регулярное выражение со строкой не будет ничего совпадать.

    • Решение: Используйте Get-Content -Raw (PSv3 +) для чтения файла в целом в одного , многострочногоstring.
  • Во-вторых, вы упомянули о необходимости замены regex escape-последовательности перевода строки (конец строки) (\n)(LF) с PowerShell аналогом интерполяции строк (`n) - обратите внимание, что PowerShell использует `, обратный тик , в качествеescape-символ:

    • НеТо, что это необходимо только в строке replace , для создания фактических, буквальных новых строк (разрывы строк) на выходе - в отличие от использования конструкции регулярного выражения\n для соответствия новых строк.

    • Однако, в Windows, новые строки обычно представляют собой CRLF последовательности , т.е.CR (\r, `r), за которым сразу следует LF (\n / `n) - то есть \r\n / `r`n - тогда как на Unix-подобных платформах они просто LF, \n / `n.

      • Если вы не уверены, какой стиль перевода строки указан в вводе, используйте\r?\n для сопоставления новых строк в кроссплатформенной совместимой манере .
        Если вас не волнует, какие конкретные символы новой строки вводятся, это безопасно использовать методично, по привычке.
    • Поэтому:

      • В вашем регулярном выражении , в то время как в вашем случае вы можете выбрать между\r\n и `r`n, обратите внимание, что:

        • `r`n работает только в двойных кавычках "..." строк.
        • Обычно предпочтительнее использовать литерал, строки в одинарных кавычках для хранения регулярных выражений - требует использования \r\n (Windows) / \n (Unix) / \r?\n (независимость от платформы) - так что естьне путайте, какие части строки PowerShell интерполируют вперед и какие части интерпретируются механизмом регулярных выражений.
      • В вашей замещающей строке используйте`r`n внутри "..." для создания фактических новых строк.


Как альтернатива использованию escape-последовательностей для представления новых строк, вы можете использовать here-строки для удобного определения многострочных строк с фактическими символами новой строки (разрывы строк) , как показано в Ответ Павла Дила , но есть предостережение :

  • Здесь строки всегда имеют тот же стиль новой строки , что и thВключающий файл сценария , что означает, что:
    • Регулярное выражение, основанное на строке здесь, будет соответствовать только в том случае, если входные данные имеют тот же стиль перевода строки, что и файл сценария .
    • Заменяющая строка на основе строки здесь будет неизменно использовать стиль новой строки файла сценария.

[1] Ваш вызов выглядит как вызов метода .NET , и хотя в этом случае он работает, следует избегать такой путаницы синтаксиса: командлеты и функции PowerShell вызываются как shell команды: без круглых скобок ((...)) и с пробелами разделенные аргументы.

0 голосов
/ 16 октября 2018

См. Следующую демонстрацию:

$newText = @'
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]
'@

$src = @'
<<<<<<< HEAD
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]
=======
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")]
>>>>>>> v1_final_release
Other lines and second instance
<<<<<<< HEAD
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]
=======
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")]
>>>>>>> v1_final_release
Some other lines
'@

$src -replace ('<<<<<<< HEAD\s+',
    '\[assembly: AssemblyVersion\("2\.0\.0\.0"\)\]\s+',
    '\[assembly: AssemblyFileVersion\("2\.0\.0\.0"\)\]\s+'+
    '=======\s+'+
    '\[assembly: AssemblyVersion\("1\.1\.0\.0"\)\]\s+',
    '\[assembly: AssemblyFileVersion\("1\.1\.0\.0"\)\]\s+'+
    '>>>>>>> v1_final_release'),$newText

Кроме того, убедитесь, что ваше содержимое читается как одна большая строка.Это может быть достигнуто с помощью Get-Content $path -Raw или [System.IO.File]::ReadAllText($path).

...