正则表达式适用于在线模拟器,但不适用于带有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

正则表达式工作的演示(在线资源)

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

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

FINDSTR /V "^([^|]*|){16}N" H:BatchTestLineProcessingmyfile.txt >H:BatchTestLineProcessingresult.txt
pause
exit

我总是得到完整的文件,似乎甚至没有使用正则表达式。谁能指出我正确的方向,我可以搜索我的错误?我尝试使用此获取更多信息 Windows FINDSTR 命令有哪些未记录的功能和限制?帖子,但我找不到我的缺陷或监督它。

任何帮助表示赞赏

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

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

将别名与 powershell 一起使用可能会缩短命令

powershell -NoP -C "gc '%FileIn%'|?{$_ -notmatch '^([^|]*|){16}N'}"  >"%FileOut%"

根据文档,findstr对正则表达式的支持非常有限。

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

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

但不幸的是,这会导致错误(FINDSTR: Search string too long.),因为[]指定太多字符类,我认为(请参阅您在问题中已经引用的有用线程:Windows FINDSTR 命令的未记录功能和限制是什么?


但是,我可以想到一个解决方法,使用for /F循环来读取文件并删除感兴趣的列之前的所有 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

用户 aschipfl 解释了为什么简单的正则表达式和解决方法正则表达式都失败了。使用FINDSTR没有简单的解决方案。

您可以使用我的 JREPL.BAT 正则表达式实用程序轻松解决问题。JREPL 是纯脚本(混合 JScript/batch),从 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正则表达式会自动支持扩展的转义序列。

为了补充我之前的评论并配合现有的PowerShell答案,这里有一个批处理文件行,它利用PowerShell但绕过了执行正则表达式的需要。

它将文件读取为以竖线分隔的 csv 格式,并输出其OnlineAvailability字段与Y匹配的行(可以修改为-NotMatch 'N')

@PowerShell -NoP "IpCSV 'H:BatchTestLineProcessingmyfile.txt' -Del '|'|?{$_.OnlineAvailability -Match 'Y'}|EpCSV 'H:BatchTestLineProcessingresult.txt' -NoT -Del '|'"

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


如果您不希望使用那些双引号字段,也许此修改是合适的:

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

相关内容

最新更新