如何在Powershell中按特定顺序对txt文件进行排序

时间:2018-09-15 16:03:04

标签: 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

3 个答案:

答案 0 :(得分:2)

注意:下面的PSv3 +解决方案回答了一个不同问题:它根据段落中包含的温度值以数字方式对段落进行排序,而不是外部规定的命令。

    这样,鉴于问题的通用标题,它可能仍然很有趣。
  • 有关所要求的问题的答案,请参见my other post

这是一个简洁的解决方案,但请注意,它需要将输入文件整体读取到内存中(无论如何,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 '...', '...'基于正则表达式执行字符串替换,在这种情况下,该表达式将从段落末尾提取温度数字字符串。
    • Cast [int]将数字字符串转换为整数,以进行正确的数字排序。
  • -join [Environment]::NewLine * 2将排序后的段落重新组合为一个多行字符串,各段落之间用空行分隔。

    • [Environment]::NewLine是适合平台的换行符序列;您也可以将换行符硬编码为"`r`n"(CRLF)或"`n"(LF)。

您可以通过添加诸如
之类的内容将输出发送到新文件 ... | Set-Content sortedFile.txt(默认情况下,文件在Windows PowerShell中使用“ ANSI”编码,而在PowerShell Core 中使用UTF-8编码;根据需要使用-Encoding)。

由于将整个输入文件预先读取到内存中,因此 可以将结果直接写回输入文件(... | Set-Content file.txt),但这会带来轻微的风险数据丢失,即在完成之前中断写入。

答案 1 :(得分:1)

Nas' helpful answer有效,但是它是O(m * n)运算;即,以规定的顺序输出m段,输入n段,则需要m * n次运算。如果要输出所有 输入段落(按规定的顺序),即,如果m等于n,则工作量为二次

以下PSv4 +解决方案将更好地扩展,因为它只需要 linear 而不是 quadratic

# 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至最后一条语句(默认情况下,文件在Windows PowerShell中使用“ ANSI”编码,而在PowerShell Core 中使用UTF-8编码;根据需要使用-Encoding )。

答案 2 :(得分:0)

$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
        }
    }
}