RegEx可在Online Simulator上运行,但不能在具有findstr

时间:2018-08-02 11:56:05

标签: batch-file cmd findstr

我试图设置一个批处理文件,该文件使用findstr杀死具有特定模式的所有行。我要分析的源文件看起来像这样(我将16位以外的所有值都更改为数字,通常是名称,URL,空或单个字符,例如Y / N):

ProductCode|SkuID|Bestellnr|ProductName|locale_de-DE_ProductName|locale_it-IT_ProductName|locale_nl-NL_ProductName|locale_fr-FR_ProductName|locale_en-GB_ProductName|locale_da-DA_ProductName|locale_cs-CZ_ProductName|locale_sv-SE_ProductName|locale_pl-PL_ProductName|locale_sk-SK_ProductName|ProductType|ProduktLink|OnlineAvailability|ProductNumber|IsProdukt|TerritoryAvailability|Category|SubCategory|ImageLink|Status|Flag0|Flag1|Flag2
0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|Y|17|18|19|20|21|22|23|24|25|26
0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|N|17|18|19|20|21|22|23|24|25|26
0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|N|17|18|19|20|21|22|23|24|25|26
0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|Y|17|18|19|20|21|22|23|24|25|26
0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|Y|17|18|19|20|21|22|23|24|25|26

我只想排除所有在第16个参数中具有N的行。因此,我想出了一个执行此操作的正则表达式模式:

^([^|]*\|){16}N

RegEx有效的演示(在线资源)

https://regex101.com/r/mE5HVR/1/

当我尝试将这种功能与findstr一起使用时:

FINDSTR /V "^([^|]*\|){16}N" H:\BatchTest\LineProcessing\myfile.txt >H:\BatchTest\LineProcessing\result.txt
pause
exit

我总是得到完整的文件,并且似乎甚至没有使用正则表达式。谁能指出我正确的方向,以便我可以找出自己的错误?我尝试通过此What are the undocumented features and limitations of the Windows FINDSTR command?帖子获取更多信息,但找不到或忽略我的缺陷。

任何帮助表示赞赏

4 个答案:

答案 0 :(得分:3)

从批处理调用Powershell作为工具:

URL::forceSchema("https")

在powershell中使用别名可以缩短命令

@Echo off
Set "FileIn=H:\BatchTest\LineProcessing\myfile.txt"
Set "FileOut=H:\BatchTest\LineProcessing\result.txt"
powershell -NoP -C "Get-Content '%FileIn%' |Where-Object {$_ -notmatch '^([^|]*\|){16}N'}"  >"%FileOut%"
pause
exit

答案 1 :(得分:3)

根据documentationfindstr对正则表达式的支持非常有限。

您可能想尝试这样的事情:

findstr /V "^[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|N|" "myfile.txt"

但不幸的是,这会导致错误(FINDSTR: Search string too long.),因为我认为指定的字符类[]过多(请参阅您已经在问题中引用的有用线程:{{ 3}})。


但是,我想到了一种解决方法,可以使用What are the undocumented features and limitations of the Windows FINDSTR command?来读取文件并删除感兴趣的那一行之前的所有16列;这仅在前面的列都不为空的情况下有效:

@echo off
set "HEAD=" & set "FLAG="
for /F "usebackq tokens=1-16* delims=| eol=|" %%A in ("%~1") do (
    if not defined HEAD (
        set "HEAD=#" & set "FLAG=#"
    ) else (
        set "LINE=%%Q"
        cmd /V /C echo(!LINE!| > nul findstr "^N|" || set "FLAG=#"
    )
    if defined FLAG (
        echo(%%A^|%%B^|%%C^|%%D^|%%E^|%%F^|%%G^|%%H^|%%I^|%%J^|%%K^|%%L^|%%M^|%%N^|%%O^|%%P^|%%Q
        set "FLAG="
    )
)

这使有趣的列显示为第一列,因此findstr现在可以使用。

或者这是根本不使用findstr的另一种方法:

@echo off
set "HEAD=" & set "FLAG="
for /F "usebackq tokens=1-17* delims=| eol=|" %%A in ("%~1") do (
    if not defined HEAD (
        set "HEAD=#" & set "FLAG=#"
    ) else (
        if not "%%Q"=="N" set "FLAG=#"
    )
    if defined FLAG (
        echo(%%A^|%%B^|%%C^|%%D^|%%E^|%%F^|%%G^|%%H^|%%I^|%%J^|%%K^|%%L^|%%M^|%%N^|%%O^|%%P^|%%Q^|%%R
        set "FLAG="
    )
)

如果任何一栏可能为空,则可以使用以下经过修改的代码:

@echo off
set "LINE="
for /F usebackq^ delims^=^ eol^= %%L in ("%~1") do (
    if not defined LINE (
        set "LINE=%%L"
        echo(%%L
    ) else (
        set "LINE=%%L"
        setlocal EnableDelayedExpansion
        for /F "tokens=17 delims=| eol=|" %%K in ("_!LINE:|=|_!") do (
            endlocal
            set "ITEM=%%K"
            setlocal EnableDelayedExpansion
        )
        if not "!ITEM:~1!"=="N" echo(!LINE!
        endlocal
    )
)

此操作会在提取值并将其与_进行比较之前,间歇性地在每个项目前加一个下划线N作为前缀,因此for /F的列不会显示为空。

答案 2 :(得分:2)

用户aschipfl具有explained why both the simple regex and the workaround regex fail。使用FINDSTR没有简单的解决方案。

您可以使用我的JREPL.BAT regex utility轻松解决问题。 JREPL是纯脚本(混合JScript /批处理),可以从XP开始在任何Windows计算机上本地运行-不需要第三方exe文件。

在命令行中,您可以简单地使用:

jrepl "^([^|]*\|){16}(?!N\|)" "" /k 0 /f myfile.txt /o result.txt

在批处理文件中,您需要使用CALL,不幸的是,它将使加引号的^加倍。添加了\XSEQ,以便可以使用扩展的转义序列\c代替^

call jrepl "\c([\c|]*\|){16}(?!N\|)" "" /k 0 /xseq /f myfile.txt /o result.txt

上面的解决方案仅保留至少具有17列且没有N作为第17列的行;这意味着它将排除没有17列的行。

如果您想使用原来的策略,即简单地排除以N作为第17列的行,则

jrepl "" "" /exc "/^([^|]*\|){16}N\|/" /k 0 /f myfile.txt /o result.txt

call jrepl "" "" /exc "/\c([\c|]*\|){16}N\|/" /k 0 /f myfile.txt /o result.txt

/XSEQ不是必需的,因为/EXC正则表达式自动支持扩展的转义序列。

答案 3 :(得分:2)

要补充我之前的评论并与现有的PowerShell一起回答,这是一个批处理文件行,该行使用PowerShell但绕过了执行RegEx的需要。

它以管道分隔的csv格式读取文件,并输出OnlineAvailability字段与Y匹配的行,(可以修改为-NotMatch 'N':< / p>

@PowerShell -NoP "IpCSV 'H:\BatchTest\LineProcessing\myfile.txt' -Del '|'|?{$_.OnlineAvailability -Match 'Y'}|EpCSV 'H:\BatchTest\LineProcessing\result.txt' -NoT -Del '|'"

结果应该是格式正确的csv,并带有双引号字段。


如果您不想使用双引号字段,则此修改可能是合适的:

@PowerShell -NoP "IpCSV 'H:\BatchTest\LineProcessing\myfile.txt' -Del '|'|?{$_.OnlineAvailability -Match 'Y'}|ConvertTo-CSV -NoT -Del '|'|%%{$_ -Replace '""',''}|Out-File 'H:\BatchTest\LineProcessing\result.txt'"