Ok, então este é realmente um pouco complicado. Indiscutivelmente, o regex não é a melhor ferramenta para o trabalho, mas pode fazê-lo.
-replace "(?<=^((\|[^|]*){5})+)\|","'n|"
Vou tentar orientá-lo:
- Seu texto tem uma seção que você deseja corresponder e uma seção que você deseja substituir . Tradicionalmente, regex substitui toda a string de pesquisa, então você usaria um grupo de captura para especificar alguma parte da string de pesquisa para ser clonado para a saída de substituição. Outra maneira é usar um lookaround , que foi o que fiz aqui. O PowerShell (.NET) é uma das poucas linguagens regex que suporta lookbehinds de comprimento variável , então estamos com sorte.
- A seção
(?<=)
é um lookbehind. Isso significa que tudo entre o=
e o)
é correspondido , mas não substituído . Portanto,^((\|[^|]*){5})+
é usado como uma condição - a substituição só acontecerá se esse bit corresponder ao texto antes da substituição pretendida. - A seção
^((\|[^|]*){5})*[^|]*
pode ser resumida como "desde o início da linha (^
), corresponder conjuntos de cinco|
s e depois corresponder ao texto até o próximo|
".- O início da linha
^
é importante - caso contrário, pode corresponder a qualquer ponto da linha e não há garantia de quantos|
s vieram antes. - Como
|
tem um significado especial na regex, ele precisa ter escape:\|
. Não precisa ser escapado quando estiver dentro de uma classe de caracteres ([]
). -
[^|]*
significa "texto até o próximo|
" - mais tecnicamente, "quantos caracteres forem diferentes de|
" - mais tecnicamente "repita a classe de caractere[^|]
quantas vezes for possível, onde esse caractere class corresponde a qualquer caractere diferente de|
". -
*
significa "zero ou mais repetições do caractere anterior, o maior número possível" - Portanto,
(\|[^|]*)
significa correspondência|
seguido pelo maior número possível de caracteres até o próximo|
. Isto irá corresponder a|text
-
{5}
significa repetir o token anterior exatamente 5 vezes. É exatamente equivalente a copiar e colar o token anterior 5 vezes. Então, isso vai corresponder a|text|text|text|text|text
-
((\|[^|]*){5})+
é uma ou mais repetições desse grupo inteiro. Por isso, pode corresponder a|text|text|text|text|text
,|text|text|text|text|text|text|text|text|text|text
, etc. - em múltiplos de 5. A razão pela qual usamos+
em vez de*
é que não queremos corresponder ao grupo vazio e substituir o primeiro|
. - E isso faz todo o lookbehind, o que significa que só substituirá um
|
por um múltiplo de 5|
s atrás dele, desde o início da linha.
- O início da linha
- Após isso, com um
\|
como o texto real a ser substituído, precedido pela aparência correspondente. -
Tomando seu exemplo
|STATUS1|HOSTNAME1|IP1|MAC1|IS_WIRED1|STATUS2|HOSTNAME2|IP2|MAC2|IS_WIRED2|STATUS3|HOSTNAME3|IP3|MAC3|IS_WIRED3
, ele corresponderá ao seguinte:|STATUS1|HOSTNAME1|IP1|MAC1|IS_WIRED1**|**STATUS2|HOSTNAME2|IP2|MAC2|IS_WIRED2**|**STATUS3|HOSTNAME3|IP3|MAC3|IS_WIRED3
Você notará aqui (se ainda não o fez) que está realmente tentando substituir todos os 5 |
menos o primeiro, nem todo 6º . Mas o método lookbehind manipula a situação "menos o primeiro" de forma bastante clara.
E agora a string de substituição.
- Como este é o PowerShell, quando queremos
\n
, na verdade queremos'n
porque o caractere de escape do PowerShell é'
. Note que isto é necessário apenas na string de substituição; na regex em si você ainda usaria\n
para passar essa sequência literal para o mecanismo regex. - E como você tem um líder
|
em cada linha, precisamos adicionar um novo|
após a nova linha. Isso funciona porque suas linhas originais não terminam com|
, portanto, não há nada a substituir no final das linhas, portanto, não terminamos com uma nova linha extra nem perdemos|
.
Se você preferir o método de grupo de captura mais tradicional:
-replace "((?:[^|]+\|){4}[^|]+)\|","'$1'n|"
Descobrir como isso funciona é deixado como um exercício para o leitor;) Dica: o $1
backreference deve ser escapado (com '
) porque senão o PowerShell o interpreta como uma variável shell.