【问题标题】:Sort lines of a .txt file with PowerShell使用 PowerShell 对 .txt 文件的行进行排序
【发布时间】:2018-11-20 04:44:12
【问题描述】:

我有一个.txt,如下所示:

MasterCard 
R$ 66,12 

Hipercard 
R$ 7.501,98 

MasterCard 
R$ 48,19 

Hipercard 
R$ 7.742,46 

MasterCard 
R$ 48,19 

Hipercard 
R$ 5.846,14 

MasterCard 
R$ 48,19 

Hipercard 
R$ 4.210,65 

Visa
R$ 4.210,65 

MasterCard 
R$ 48,19 

Hipercard 
R$ 2.892,20 

MasterCard 
R$ 48,19 

Visa
R$ 4.210,65

Hipercard 
R$ 1.944,19 

Hipercard 
R$ 584,04 

Visa
R$ 4.210,65

我需要一个 .bat 文件(可以在 PowerShell 中),它按描述和值组织行,如下所示:

-----------------
MasterCard 
R$ 66,12 

MasterCard 
R$ 48,19 

MasterCard 
R$ 48,19 

MasterCard 
R$ 48,19 

MasterCard 
R$ 48,19 

MasterCard 
R$ 48,19 

----------------      
Hipercard 
R$ 7.501,98 

Hipercard 
R$ 7.742,46 

Hipercard 
R$ 5.846,14 

Hipercard 
R$ 4.210,65

Hipercard 
R$ 2.892,20 

Hipercard 
R$ 1.944,19 

Hipercard 
R$ 584,04 

--------------        
Visa
R$ 4.210,65 

Visa
R$ 4.210,65

Visa
R$ 4.210,65

可以用.bat 文件来做吗?我被困在如何开始。 我正在尝试使用一个简单的命令:sort test.txt /o testout.txt

但它不起作用。


我有另一个想法。运行此命令我可以将所有行放在同一行:

for /f "usebackq tokens=* delims=" %%a in ("frt01.txt") do (echo(%%a)>>test.txt
for /f "usebackqdelims=" %%i in ("test.txt") do @<nul set /p"=%%i ">>"test2.txt"
del test.txt /S /Q /

所以现在,描述和值都在一行中:

MasterCard  R$ 66,12  Hipercard  R$ 7.501,98  MasterCard  R$ 48,19  Hipercard  R$ 7.742,46  MasterCard  R$ 48,19  Hipercard  R$ 5.846,14  MasterCard  R$ 48,19  Hipercard  R$ 4.210,65  MasterCard  R$ 48,19  Hipercard  R$ 2.892,20  MasterCard  R$ 48,19  Hipercard  R$ 1.944,19  Hipercard  R$ 584,04  

我该怎么做才能像下面这样? (在每个值后键入“输入”)

MasterCard  R$ 66,12  
Hipercard  R$ 7.501,98  
MasterCard  R$ 48,19  
Hipercard  R$ 7.742,46  
MasterCard  R$ 48,19  
Hipercard  R$ 5.846,14  
MasterCard  R$ 48,19  
Hipercard  R$ 4.210,65  
MasterCard  R$ 48,19  
Hipercard  R$ 2.892,20  
MasterCard  R$ 48,19  
Hipercard  R$ 1.944,19  
Hipercard  R$ 584,04  

因为那时我可以用这个命令排序:sort test2.txt /o output.txt

我想这样做比较容易。


@michael_heath 我说的是这个:

Hipercard   R$    584,04
Hipercard   R$  1.944,19
Hipercard   R$  2.892,20
Hipercard   R$  4.210,65
Hipercard   R$  5.846,14
Hipercard   R$  7.501,98
Hipercard   R$  7.742,46
------------------------
MasterCard  R$     48,19
MasterCard  R$     48,19
MasterCard  R$     48,19
MasterCard  R$     48,19
MasterCard  R$     48,19
MasterCard  R$     66,12
------------------------
Visa        R$     48,19
Visa        R$     48,19
Visa        R$     48,19
------------------------

【问题讨论】:

    标签: powershell batch-file


    【解决方案1】:

    在对数据进行排序之前,您需要对其进行解析。您可以将ConvertFrom-String cmdlet 与模板一起使用:

    $Template = @'
    {CardProvider*:MasterCard}
    R$ {Amount:66,12}
    
    {CardProvider*:Hipercard}
    R$ {Amount:7.501,98}
    
    {CardProvider*:Visa}
    R$ {Amount:4.210,65}
    
    '@
    
    $Transactions = Get-Content path\to\file.txt |ConvertFrom-String -TemplateContent $Template
    

    $Transactions 变量现在将包含一个对象数组,每个对象具有一个 CardProvider 和一个 Amount 属性。要按提供者排序,然后按金额排序,我们可以执行以下操作:

    # Define output file name
    $OutputFile = 'output.txt'
    # Group by card type first
    $Transactions |Group-Object CardProvider |ForEach-Object {
        # Write seperator to output file:
        '----------------' |Add-Content -Path $OutputFile 
        # Now we sort each group of cards by descending amount
        $_.Group |Sort-Object {$_.Amount -replace '\.' -replace ',','.' -as [decimal]} -Descending |ForEach-Object {
            # Finally write the contents to file again
            $_.CardProvider,"R$ $($_.Amount)","" |Add-Content -Path $OutputFile
        }
    }
    

    【讨论】:

    • 好的,但是,值总是会改变,我忘了说。卡片名称将始终相同,但其下方的值将始终更改
    • @Karen ConvertFrom-String 可能仍然能够推断出模板字符串中描述的模式 - 您是否尝试过测试我提供的代码?为Visa 卡类型添加了另一个示例
    • 当我运行时,它会说命令'ConvertFrom-String -TemplateContent'写错了,你能检查一下,如果可能的话,把所有的放在一行里吗?
    • 您使用的是哪个版本的 PowerShell? ConvertFrom-String 在 Windows PowerShell 5.0 中引入
    • 我有 2.0 版本,我使用的是 Windows 7。
    【解决方案2】:

    这是一个批处理文件解决方案。要将这些行堆叠在一起,您只需使用一个变量来保存上一行。

    @echo off
    setlocal enabledelayedexpansion
    
    set "line1="
    (FOR /F "delims=" %%G IN (input.txt) DO (
        IF NOT DEFINED line1 (
            set "line1=%%G
        ) else (
            echo !line1! %%G
            set "line1="
        )
    ))>temp.txt
    sort temp.txt>output.txt
    

    【讨论】:

    • 什么也没发生,temp.txtoutput.txt 是空的。
    • @Karen,您是否将“input.txt”更改为您的输入文件名?
    • 成功了!谢谢您的帮助!也许你可以回答我的另一个问题? stackoverflow.com/questions/50784742/…
    【解决方案3】:

    所有批处理文件代码

    选项 1

    @echo off
    setlocal enabledelayedexpansion
    
    (
        for /f "tokens=1,2" %%A in (frt01.txt) do (
            if not "%%~A" == "R$" (
                set "card=%%~A          "
                set "card=!card:~,11!"
            ) else (
                set "value=          %%~B"
                set "value=!value:~-9!"
                echo !card! %%~A !value!
            )
        )
    ) > unsorted.txt
    
    sort unsorted.txt /o output.txt
    
    rem  Optional code below to insert ------- between rows after sort.
    
    set "last_card="
    (
        for /f "delims=" %%A in (output.txt) do (
            for /f %%B in ("%%~A") do set "card=%%~B"
            if defined last_card if not "!card!" == "!last_card!" (
                echo ------------------------
            )
            echo %%A
            set "last_card=!card!"
        )
        echo ------------------------
    ) > tmp.txt
    
    move /y tmp.txt output.txt
    

    这是延迟扩展的概念。固定间距是 使用所以sort可以更好地订购不同的长度 卡片和货币价值。

    • for /? 用于令牌描述等。
    • set /? 用于替换语法,即set "card=!card:~,11!"

    选项 2

    @(
        @echo off
        setlocal enabledelayedexpansion
        for /f "tokens=1,2" %%A in (frt01.txt) do (
            if not "%%~A" == "R$" (
                set "card=%%~A          "
                call set "card=%%card:~,11%%"
            ) else (
                set "value=          %%~B"
                call set "value=%%value:~-9%%"
                call echo "%%card%%" "%%A" "%%value%%"
            )
        )
    ) | sort /o output.txt
    

    这是一个不寻常的概念。像以前的代码一样,使用固定的 间距。它不使用临时文件,因为它直接通过管道传输到 sort.

    使用setlocal enabledelayedexpansion,即使没有! 被使用。延迟变量不会扩大。没有, 延迟扩展,call setcall echo 将 不工作。

    在 Win7 上工作,虽然它可能是奇怪的行为 让其他代码成为更好的选择。


    选项 3

    @echo off
    setlocal
    
    if not "%~1" == "" (
        if "%~1" == "/?" goto :help
        for %%A in (%*) do call :read "%%~A"
        exit /b
    )
    
    rem If no arguments, do this optional task instead.
    > "%~dp0unsorted.txt" call :read "frt01.txt"
    sort "%~dp0unsorted.txt" /o "%~dp0output.txt"
    del "%~dp0unsorted.txt"
    
    exit /b
    
    :read
    setlocal enabledelayedexpansion
    
    for /f "usebackq tokens=1,2" %%A in ("%~1") do (
        if not "%%~A" == "R$" (
            set "card=%%~A          "
            set "card=!card:~,11!"
        ) else (
            set "value=          %%~B"
            set "value=!value:~-9!"
            echo !card! %%~A !value!
        )
    )
    exit /b
    
    :help
    echo Prints Hipercard, MasterCard... vertical list as 3 horizontal fixed columns.
    echo If multiple files are passed as arguments, they will be printed in sequence.
    echo.
    echo Syntax: %~nx0 file [file [file]]
    echo.
    echo Examples:
    echo   %~nx0 "test 1.txt"
    echo   %~nx0 test1.txt test2.text ^| sort /o output.txt
    exit /b
    

    这是rem下方的独立脚本或运行代码 备注行。您可以删除可选代码并放置 PATH 中的脚本,以便您可以从控制台运行它 任何地方。

    如果脚本名为cardsorter.cmd,那么您可以即

    cardsorter frt01.txt | sort /o output.txt
    

    在命令提示符下。


    所有选项的输出

    Hipercard   R$    584,04
    Hipercard   R$  1.944,19
    Hipercard   R$  2.892,20
    Hipercard   R$  4.210,65
    Hipercard   R$  5.846,14
    Hipercard   R$  7.501,98
    Hipercard   R$  7.742,46
    MasterCard  R$     48,19
    MasterCard  R$     48,19
    MasterCard  R$     48,19
    MasterCard  R$     48,19
    MasterCard  R$     48,19
    MasterCard  R$     66,12
    Visa        R$  4.210,65
    Visa        R$  4.210,65
    Visa        R$  4.210,65
    

    注意

    选项 1 插入 -------------- 以分隔卡片类型。

    【讨论】:

    • 好的,很好!选项 1 效果很好。但是,如果我想用一条线分隔卡片呢? --------------------
    • 对于选项 3。在 echo !card! %%~A !value! 行之后插入 echo.echo. 打印一个空行。在回声线之后做类似的其他选项。
    • 好的,做到了,但我没有解释得很好。我只想在每种卡片的末尾加上一行---------,然后分开。还有另一个问题。当我对其进行排序时,所有行都排在最前面。
    • 需要在sort之后完成。使用for 循环更新选项1 以读取output.txt 并在行之间插入--------,然后将写入的文件tmp.txt 移动到output.txt
    • 几乎!对不起,如果我解释得不好,我的英语不太好。请查看我的上一次编辑!
    【解决方案4】:

    以下代码将输入文件解析为交易对象数组,对其进行排序,然后输出排序后的数组。并不是说金额被排序为右对齐字符串。

    $unsortedtransactions = @()
    
    Get-Content .\in.txt -ReadCount 3 |
        ForEach-Object {
            $Matches = $null
            "$_" -match '([^\s]*)\s*(\S*)\s*(.*)$(.*)$' | Out-Null
            $thisrecord = [PSCustomObject] @{ Card = $Matches[1]
                Currency = $Matches[2]
                Amount = $("{0,15}" -f @($Matches[3].Trim()))
            }
            $unsortedtransactions += $thisrecord
        }
    
    $sortedtransactions = $unsortedtransactions | Sort-Object -Property Card, Currency, Amount
    
    foreach ($t in $sortedtransactions) {
        $("{0}`r`n{1} {2}`r`n" -f @($t.Card, $t.Currency, $t.Amount.Trim())) |
            Out-File -FilePath st.txt -Encoding ascii -Append
    }
    

    【讨论】:

    猜你喜欢
    • 2022-10-09
    • 1970-01-01
    • 1970-01-01
    • 2014-01-06
    • 2012-05-23
    • 2019-11-19
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多