RegEx 适用于在线模拟器,但不适用于带有 findstr 的 BatchFile
RegEx works on Online Simulator but not inside BatchFile with findstr
我试图设置一个批处理文件,它使用 findstr 来杀死所有具有特定模式的行。我要分析的源文件如下所示(我将除第 16 位以外的所有值都更改为数字,通常它们是名称、网址、空字符或单个字符,如 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? post 获取更多信息,但我找不到我的缺陷或监督它。
感谢任何帮助
从批处理中调用 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
在 powershell 中使用别名可以缩短命令
powershell -NoP -C "gc '%FileIn%'|?{$_ -notmatch '^([^|]*\|){16}N'}" >"%FileOut%"
根据 documentation,findstr
对正则表达式的支持非常有限。
您可能想尝试这样的事情:
findstr /V "^[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|N|" "myfile.txt"
但不幸的是,这会导致错误 (FINDSTR: Search string too long.
),因为指定的字符 类 []
太多了,我认为(参考您已经引用的有用线程在你的问题中:What are the undocumented features and limitations of the Windows FINDSTR command?).
但是,我可以想出一种变通方法,使用 for /F
loop 来读取文件并删除感兴趣的列之前的所有 16 列;这仅在前面几列的 none 为空的情况下有效:
@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 regex utility轻松解决问题。 JREPL 是纯脚本(混合 JScript/batch),从 XP 开始可以在任何 Windows 机器上本地运行 - 不需要第 3 方 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
但绕过了执行 RegEx 的需要。
它将文件读取为竖线分隔的csv,并输出OnlineAvailability
字段匹配Y
的行,(可以修改为-NotMatch 'N'
):
@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'"
我试图设置一个批处理文件,它使用 findstr 来杀死所有具有特定模式的行。我要分析的源文件如下所示(我将除第 16 位以外的所有值都更改为数字,通常它们是名称、网址、空字符或单个字符,如 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? post 获取更多信息,但我找不到我的缺陷或监督它。
感谢任何帮助
从批处理中调用 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
在 powershell 中使用别名可以缩短命令
powershell -NoP -C "gc '%FileIn%'|?{$_ -notmatch '^([^|]*\|){16}N'}" >"%FileOut%"
根据 documentation,findstr
对正则表达式的支持非常有限。
您可能想尝试这样的事情:
findstr /V "^[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|[^|]*|N|" "myfile.txt"
但不幸的是,这会导致错误 (FINDSTR: Search string too long.
),因为指定的字符 类 []
太多了,我认为(参考您已经引用的有用线程在你的问题中:What are the undocumented features and limitations of the Windows FINDSTR command?).
但是,我可以想出一种变通方法,使用 for /F
loop 来读取文件并删除感兴趣的列之前的所有 16 列;这仅在前面几列的 none 为空的情况下有效:
@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 有
你可以用我的JREPL.BAT regex utility轻松解决问题。 JREPL 是纯脚本(混合 JScript/batch),从 XP 开始可以在任何 Windows 机器上本地运行 - 不需要第 3 方 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
但绕过了执行 RegEx 的需要。
它将文件读取为竖线分隔的csv,并输出OnlineAvailability
字段匹配Y
的行,(可以修改为-NotMatch 'N'
):
@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'"