Regex в Powershell не может проверить наличие новых строк - PullRequest
0 голосов
/ 03 октября 2018

Я пытаюсь получить первый блок примечаний к релизу ...
(см. Пример содержимого в коде)

Когда я использую что-то простое, оно работает,
он ломается только при попытке поиска по нескольким строкам (\n).
Я использую (Get-Content $changelog | Out-String), потому что это возвращает 1 строку вместо массива из каждой строки.

$changelog = 'C:\Source\VSTS\AcmeLab\AcmeLab Core\changelog.md'
$regex = '([Vv][0-9]+\.[0-9]+\.[0-9]+\n)(^-.*$\n)+'

(Get-Content $changelog | Out-String) | Select-String -Pattern $regex -AllMatches

<#
SAMPLE:
------
v1.0.23
- Adds an IContainer API.
- Bugfixes.

v1.0.22
- Hotfix: Language operators.

v1.0.21
- Support duplicate query parameters.

v1.0.20
- Splitting up the ICommand interface.
- Fixing the referrer header empty field value.

#>

Мне нужен следующий результат:

v1.0.23
- Adds an IContainer API.
- Bugfixes.

Обновление:

Использование параметров ..

$changelog = 'C:\Source\VSTS\AcmeLab\AcmeLab Core\changelog.md'
$regex = '(?smi)([Vv][0-9]+\.[0-9]+\.[0-9]+\n)(^-.*$\n)+'

Get-Content -Path $changelog -Raw | Select-String -Pattern $regex -AllMatches

Я тоже ничего не получаю .. (неважно, если я использую \n или \r\n)

1 Ответ

0 голосов
/ 04 октября 2018
  • Если вы не застряли с PowerShell v2, проще и эффективнее использовать Get-Content -Raw для чтения всего файла в виде одной строки;кроме того, Out-String добавляет дополнительную строку в строку.
  • Поскольку вы ищете только первое совпадение , вы можете использовать оператор -match - нет необходимости в Select-String s -AllMatches переключатель.
    • Примечание. Хотя вы можете использовать Select-String без него, более эффективно использовать оператор -match, если вы уже прочитали весь файл в память.
  • Соответствие регулярному выражению по умолчанию всегда регистр- нечувствителен в PowerShell, что соответствует общей нечувствительности к регистру PowerShell.

Таким образом, следующее возвращает первый блок, еслиany:

if ((Get-Content -Raw $changelog) -match '(?m)^v\d+\.\d+\.\d+.*(\r?\n-\s?.*)+') { 
  # Match found - output it.
  $Matches[0] 
}

* (?m) включает опцию встроенного регулярного выражения m (многострочный), что приводит к тому, что якоря ^ и $ соответствуют началу и концу отдельные строки , а не строки в целом.
* \r?\n соответствует как CRLF, так и символам новой строки только для LF.
* Вы можете сделать регулярное выражение немного более эффективным, сделав подвыражение (...) без захвата , учитывая, что вам не интересно, что он захватил: (?:...).

Обратите внимание, что -match само по себе возвращает Boolean (сскалярная LHS), но информация о матче записывается вавтоматические $Matches переменные хеш-таблицы, чья запись 0 содержит общее совпадение.


Что касается то, что вы пытались :

'([Vv][0-9]+\.[0-9]+\.[0-9]+\n)(^-.*$\n)+'

неработать, потому что по умолчанию $ совпадает только в самом конце входной строки, в конце последней строки (хотя, возможно, до последней новой строки).Чтобы $ соответствовал концу каждой строки , вам нужно включить опцию многострочного регулярного выражения (что вы сделали во второй попытке).В результате, ничто не соответствует.

'(?smi)([Vv][0-9]+\.[0-9]+\.[0-9]+\n)(^-.*$\n)+'

не работает должным образом, потому что, используя опцию s (однострочный), вы сделали . match и новые строки тоже , так что жадное подвыражение, такое как .*, будет соответствовать остатку строки через строки .В результате все с первого блока на матчах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...