我试图设置一个批处理文件,该文件使用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?帖子获取更多信息,但找不到或忽略我的缺陷。
任何帮助表示赞赏
答案 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)
根据documentation,findstr
对正则表达式的支持非常有限。
您可能想尝试这样的事情:
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'"