[英]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
)。
$_
代表手頭的輸入段落。 -replace '...', '...'
基於正則表達式執行字符串替換,在這種情況下,將從段落末尾提取溫度數字字符串。
Get-Help about_Regular_Expressions
;有關-replace
運算符的信息,請參見Get-Help about_Regular_Expressions
Get-Help about_Comparison_Operators
。 [int]
將數字字符串轉換為整數,以進行適當的數字排序。 -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
),成為哈希表的鍵。
$_
代表手頭的輸入段落。 -replace '...', '...'
基於正則表達式執行字符串替換。
Get-Help about_Regular_Expressions
;有關-replace
運算符的信息,請參見Get-Help about_Regular_Expressions
Get-Help about_Comparison_Operators
。 -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.