簡體   English   中英

如何在Powershell中按特定順序對txt文件進行排序

[英]how to sort a txt file in specific order in Powershell

例如,我有這第一個文本

today is sunny in the LA 
and the temperature is 21C

today is cloudy in the NY 
and the temperature is 18C

today is sunny in the DC 
and the temperature is 25C

這是我想要的順序:

18C 
25C
21C

我想將第一個文件更改為與第二個文件相同的順序,但不刪除任何內容:

today is cloudy in the NY
and the temperature is 18C

today is sunny in the DC 
and the temperature is 25C

today is sunny in the LA
and the temperature is 21C

注意 :下面的PSv3 +解決方案回答了一個不同的問題:它根據段落中包含的溫度值對段落進行數字排序,而不是按照外部規定的順序進行排序。

  • 這樣,鑒於問題的通用標題,它可能仍然很有趣。
  • 有關所問問題的答案,請參閱我的其他帖子

這是一個簡潔的解決方案,但請注意,它需要將輸入文件整體讀取到內存中(無論如何, Sort-Object也會將其輸入對象全部收集到內存中,因為它不使用臨時文件來緩解潛在的內存壓力) :

((Get-Content -Raw file.txt) -split '\r?\n\r?\n' -replace '\r?\n$' |
  Sort-Object { [int] ($_ -replace '(?s).+ (\d+)C$', '$1') }) -join 
    [Environment]::NewLine * 2
  • (Get-Content -Raw file.txt)將輸入文件作為單個多行字符串整體讀取到內存中。

  • -split '\\r?\\n\\r?\\n'將多行字符串分成幾段段落(由空行分隔的行塊),而-replace '\\r?\\n$'刪除尾隨文件末尾的換行符(如果有)。

    • 正則表達式\\r?\\n匹配Windows風格的CRLF和Unix風格的僅LF換行符。
  • Sort-Object { [int] ($_ -replace '(?s).+ (\\d+)C$', '$1') })通過每個段落末尾的溫度數字對段落進行數字排序(例如18 )。

  • -join [Environment]::NewLine * 2將已排序的段落重新組合為單個多行字符串,各段落之間用空行分隔。

    • [Environment]::NewLine是適合平台的換行符序列; 您也可以將換行符硬編碼為"`r`n" (CRLF)或"`n" (LF)。

您可以通過添加類似以下內容將輸出發送到新文件
... | Set-Content sortedFile.txt ... | Set-Content sortedFile.txt (默認情況下,使文件在Windows PowerShell中為“ ANSI”編碼,而在PowerShell Core中為UTF-8編碼;根據需要使用-Encoding )。

由於整個輸入文件讀入內存前面, 可以將運算結果直接返回到輸入文件( ... | Set-Content file.txt ),但是這樣做承擔數據丟失的風險很小,即如果寫入在完成之前被中斷。

Nas的有用答案有效,但它是O(m * n)運算; 即,以規定的順序輸出m段,輸入n段,則需要m * n次運算。 如果要輸出所有輸入的段落(按規定的順序),即,如果m等於n,則工作量為二次方

以下PSv4 +解決方案將更好地擴展,因為它只需要線性而不是二次努力:

# The tokens prescribing the sort order, which may come from 
# another file read with Get-Content, for instance.
$tokensToSortBy = '18C', '25C', '21C'

# Create a hashtable that indexes the input file's paragraphs by the sort
# token embedded in each.
((Get-Content -Raw file.txt) -split '\r?\n\r?\n' -replace '\r?\n$').ForEach({
  $htParagraphsBySortToken[$_ -replace '(?s).* (\d+C)$(?:\r?\n)?', '$1'] = $_
})

# Loop over the tokens prescribing the sort order, and retrieve the
# corresponding paragraph, then reassemble the paragraphs into a single,
# multi-line string with -join
$tokensToSortBy.ForEach({ $htParagraphsBySortToken[$_] }) -join [Environment]::NewLine * 2
  • (Get-Content -Raw file.txt)將輸入文件作為單個多行字符串整體讀取到內存中。

  • -split '\\r?\\n\\r?\\n'將多行字符串分成幾段段落(由空行分隔的行塊),而-replace '\\r?\\n$'刪除尾隨文件末尾的換行符(如果有)。

    • 正則表達式\\r?\\n匹配Windows風格的CRLF和Unix風格的僅LF換行符。
  • $_ -replace '(?s).* (\\d+C)$(?:\\r?\\n)?', '$1'從每個段落中提取排序標記(例如25C ),成為哈希表的鍵。

  • -join [Environment]::NewLine * 2將已排序的段落重新組合為單個多行字符串,各段落之間用空行分隔。

    • [Environment]::NewLine是適合平台的換行符序列; 您也可以將換行符硬編碼為"`r`n" (CRLF)或"`n" (LF)。

您可以通過添加類似以下內容將輸出發送到新文件
... | Set-Content sortedFile.txt ... | Set-Content sortedFile.txt設置為最后一個語句(默認情況下,使文件在Windows PowerShell中使用“ ANSI”編碼,而在PowerShell Core中使用UTF-8編碼;根據需要使用-Encoding )。

$text = Get-Content -path C:\text.txt
$order = '18C','25C','21C'

foreach ($item in $order)
{
    $text | ForEach-Object {
        if ($_ -match "$item`$") { # `$ to match string at the end of the line
            Write-Output $text[($_.ReadCount-2)..($_.ReadCount)] # output lines before and after match
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM