Хорошо, так что это на самом деле немного сложно. Возможно, регулярное выражение не лучший инструмент для работы, но он может сделать это.
-replace "(?<=^((\|[^|]*))+)\|","`n|"
Я постараюсь провести вас через это:
- В вашем тексте есть раздел, который вы хотите сопоставить, и раздел, который вы хотите заменить . Традиционно, регулярное выражение заменяет всю строку поиска, поэтому вы должны использовать группу захвата, чтобы указать некоторую часть строки поиска, которая будет клонирована для вывода замены. Другой способ - использовать lookaround, что я и сделал здесь. PowerShell (.NET) - один из немногих языков регулярных выражений, который поддерживает просмотр за разной длины, поэтому нам повезло.
(?<=)
Раздел является просмотром назад. Это означает, что все между=
и)
будет соответствовать, но не заменить . Так^((\|[^|]*))+
что используется в качестве условия - замена произойдет только в том случае, если этот бит соответствует тексту перед предполагаемой заменой.^((\|[^|]*))*[^|]*
Раздел можно охарактеризовать как «от начала строки (^
), матч наборы пяти|
секунд, а затем сопоставить текст до следующего|
».- Начало строки
^
важно - в противном случае оно может совпадать в любом месте строки, и нет гарантии, сколько|
s пришло раньше. - Потому что
|
имеет особое значение в регулярном выражении, оно должно быть экранированы:\|
. Его не нужно экранировать, когда он находится внутри класса персонажа ([]
). [^|]*
означает «текст до следующего|
» - более технически, «как можно больше символов, чем|
это возможно» - более технически «повторять[^|]
класс символов столько раз, сколько это возможно, если этот класс символов соответствует любому символу, кроме|
».*
означает «ноль или более повторений предыдущего символа, как можно больше»- Так
(\|[^|]*)
означает совпадение,|
за которым следует как можно больше символов до следующего|
. Это будет соответствовать|text
означает повторить предыдущий токен ровно 5 раз. Это в точности эквивалентно копированию предыдущего токена 5 раз. Так что это будет соответствовать
|text|text|text|text|text
((\|[^|]*))+
это одно или несколько повторений всей этой группы. Так он может соответствовать|text|text|text|text|text
,|text|text|text|text|text|text|text|text|text|text
и т.д. - в упаковке 5. Причина, почему мы используем+
вместо*
есть, мы не хотим, чтобы соответствовать пустую группу и заменить очень первым|
.- И это делает весь взгляд сзади, а это означает, что он заменит a только
|
с точным кратным 5|
с от него, с начала строки.
- Начало строки
- Далее следует
\|
фактический текст для замены, которому предшествует сопоставленный вид сзади. Если взять ваш пример
|STATUS1|HOSTNAME1|IP1|MAC1|IS_WIRED1|STATUS2|HOSTNAME2|IP2|MAC2|IS_WIRED2|STATUS3|HOSTNAME3|IP3|MAC3|IS_WIRED3
, он будет соответствовать следующему:|STATUS1|HOSTNAME1|IP1|MAC1|IS_WIRED1**|**STATUS2|HOSTNAME2|IP2|MAC2|IS_WIRED2**|**STATUS3|HOSTNAME3|IP3|MAC3|IS_WIRED3
Вы заметите здесь (если вы этого еще не сделали), что вы на самом деле пытаетесь заменить каждый 5-й |
минус первый, а не каждый 6-й . Но метод lookbehind достаточно аккуратно обрабатывает ситуацию «минус первая».
А теперь замена строки.
- Поскольку это PowerShell, когда мы хотим
\n
, мы на самом деле хотим,`n
потому что это экранирующий символ PowerShell`
. Обратите внимание, что это необходимо только в строке замены; в самом регулярном выражении вы все равно будете использовать,\n
чтобы передать эту буквальную последовательность в механизм регулярных выражений. - И поскольку у вас есть ведущие
|
в каждой строке, нам нужно добавить новую|
после новой строки. Это работает, потому что ваши исходные строки не заканчиваются на a|
, поэтому в конце строк нечего заменять, поэтому мы не заканчиваем ни новой, ни завершающей строкой|
.
Если вы предпочитаете более традиционный метод захвата группы:
-replace "((?:[^|]+\|)[^|]+)\|","`$1`n|"
Выяснение того, как это работает, оставлено читателю в качестве упражнения;) Совет: $1
обратная ссылка должна быть исключена (с помощью `
), поскольку в противном случае PowerShell интерпретирует ее как переменную оболочки.