取代 powershell 中的每 6 個管道

取代 powershell 中的每 6 個管道

我意識到我在問一個已經被問過和回答的類似問題,但我無法推斷出我需要的答案,因為正則表達式和正則表達式引擎足夠不同。我有硬體資產管理日誌,這些日誌是管道分隔的,但端點之間不是主要分隔的。日誌如下圖所示:

|STATUS1|HOSTNAME1|IP1|MAC1|IS_WIRED1|STATUS2|HOSTNAME2|IP2|MAC2|IS_WIRED2|STATUS3|HOSTNAME3|IP3|MAC3|IS_WIRED3

我想做的是|用回車符替換每 6 個,如下所示:

|STATUS1|HOSTNAME1|IP1|MAC1|IS_WIRED1
|STATUS2|HOSTNAME2|IP2|MAC2|IS_WIRED2
|STATUS3|HOSTNAME3|IP3|MAC3|IS_WIRED3

我得到的最接近的選擇每個端點,但我不太確定如何使用 powershell 使用它。

[^\|]*\|[^\|]*\|[^\|]*\|[^\|]*\|[^\|]*\|[^\|]*

我熟悉 PS 中的替換指令,我想像最終結果會是這樣的:

$hosts = $hosts -replace "<highspeed_low_drag_velcro_snap_regex_here>","\r\n"

先致謝!

答案1

好吧,這實際上有點棘手。可以說,正規表示式不是完成這項工作的最佳工具,但它可以做到這一點。

-replace "(?<=^((\|[^|]*){5})+)\|","`n|"

我將嘗試引導您完成它:

  • 您的文本中有一個您想要的部分匹配以及您想要的部分代替。傳統上,正規表示式會取代整個搜尋字串,因此您可以使用捕獲組指定要複製到替換輸出的搜尋字串的某些部分。另一種方法是使用環視四周,這就是我在這裡所做的。 PowerShell (.NET) 是少數支援的正規表示式語言之一可變長度回顧,所以我們很幸運。
  • (?<=)部分是回顧。這意味著=和之間的所有內容)都是匹配的但不是被取代。所以^((\|[^|]*){5})+被用作狀態- 僅當該位元與預期替換先前的文字相符時,才會發生替換。
  • ^((\|[^|]*){5})*[^|]*部分可以概括為「從行 ( ^) 的開頭開始,匹配五個 s 組|,然後將文字配對到下一個|」。
    • 行的開頭^很重要 - 否則它可以匹配行中的任何位置,並且無法保證|之前有多少個 s 。
    • 由於|在正規表示式中具有特殊意義,因此需要對其進行轉義:\|。在字元類別 ( ) 內時不需要轉義[]
    • [^|]*意思是“文本到下一個|” - 更技術性地說,“盡可能多的字符” - 更技術性地說,“盡可能多次地|重複字符類,其中該字符類與除”之外的任何字符匹配。[^|]|
    • *表示“前一個字元重複零次或多次,盡可能多”
    • 因此(\|[^|]*)意味著匹配|後跟盡可能多的字符,直到下一個|。這將匹配|text
    • {5}意味著重複前一個標記 5 次。它完全相當於將前面的標記複製貼上 5 次。所以這將匹配|text|text|text|text|text
    • ((\|[^|]*){5})+是整個組的一次或多次重複。因此它可以匹配|text|text|text|text|text,等 - 5的|text|text|text|text|text|text|text|text|text|text倍數。+*|
    • 這使得整個lookbehind,意味著它只會從行的開頭替換後面|恰好是5的倍數的a。|
  • 接下來是 a\|作為要替換的實際文本,前面是匹配的lookbehind。
  • 以您的範例為例|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
    

您會在這裡注意到(如果您還沒有)您實際上正在嘗試替換每個第五名 |減去第一個,而不是所有第六名。但lookbehind方法相當乾淨地處理「減去第一個」的情況。


現在是替換字串。

  • 因為這是 PowerShell,所以當我們想要 時\n,我們實際上想要,`n因為 PowerShell 轉義字元是`。請注意,這僅在替換字串中是必需的;在正規表示式本身中,您仍然可以使用\n將該文字序列傳遞給正規表示式引擎。
  • 因為每行都有一個前導,所以我們需要在新行之後|新增一行。|這是可行的,因為您的原始行不以 a 結尾|,因此行末尾沒有任何內容可以替換,因此我們最終不會得到額外的新行或尾隨|

如果您喜歡更傳統的捕獲組方法:

-replace "((?:[^|]+\|){4}[^|]+)\|","`$1`n|"

弄清楚它是如何運作的留給讀者作為練習;) 提示:$1必須對反向引用進行轉義(使用`),否則 PowerShell 會將其解釋為 shell 變數。

相關內容