regex - 为什么 cmd findstr 中的这个正则表达式有效?
问题描述
我需要创建一个 cmd 脚本(不知何故我做到了),它从一系列文件中提取一些文本行并将它们放入一个新的 txt 文件中。
源文件是这样的:
%
!
! AAA
!
! ------------------------ SOME TEXT ABCDEFGHIJKLMN --------------------------
!
! BBB
! ----------------------------------------------------------------------------
! T5 PUNTA ø 6.5/9.5~ $ 63~
! ----------------------------------------------------------------------------
! T12 PUNTA ø 2.5~ $ 39~
! ----------------------------------------------------------------------------
!
! SOME OTHER TEXT
!
! 1] ABC
! 2] DEF
! 3] ...
OTHER LINE 1
OTHER LINE 2
ETC
%
我需要提取的行是两者之间的行"! ----------------------------------------------------------------------------"
,在这种情况下,T5 PUNTA ø 6.5/9.5~ $ 63~
和T12 PUNTA ø 2.5~ $ 39~
.
我正在尝试一些正则表达式findstr
来匹配!
仅在相关行之后的行,这表明搜索结束,直到我(纯属偶然)找到一条与我需要的所有行匹配的指令(运气, 我猜)。
片段是这样的:
@echo off
setlocal enabledelayedexpansion
if exist output.txt ( break > output.txt )
for /r <path> %%g in (<filename>) do (
...
for /f "tokens=* delims= " %%a in (%%g) do (
echo %%a | findstr /r /c:^\!$ >nul
if errorlevel 1 (...)
) else ( echo %%a >> srcoutput.txt
...
)
)
)
请专注于指令echo %%a | findstr /r /c:^\!$ >nul
。由于我不知道的原因,这仅匹配行T5 PUNTA ø 6.5/9.5~ $ 63~
和T12 PUNTA ø 2.5~ $ 39~
. 这正是我想要的,但我不知道它为什么有效!
有人可以帮我理解为什么这个简单的表达方式^\!$
有效吗?在我(错误的)理解中,它应该只在开头和结尾匹配一行!
(我已经逃脱,因为否则它不起作用)。
先感谢您
解决方案
实际上是命令行:
echo %%a | findstr /r /c:^\!$ >nul
只返回包含$
-character 的行。
这就是一步一步发生的事情:
命令行被解析为(假设
%%a
保持<expanded text>
):echo <expanded text> | findstr /r /c:\!$ >nul
因此(未引用的)插入符号 (
^
) 消失了,因为它是cmd
;的转义字符 因为\
没有特殊含义,所以你可以省略它^
;由于启用了延迟扩展(实际上是不必要的),-
!
符号消失了,因为只有一个,所以命令行变为:echo <expanded text> | findstr /r /c:\$ >nul
\
- 符号充当转义字符(尽管特别是对于findstr
!),因此-符号$
在正则表达式 (/R
) 模式下失去其特殊含义(即将匹配锚定到行尾),因此被视为文字字符;管道的左侧传递文本
<expanded text>
(带有尾随SPACE,因为在 之前有一个|
),右侧最终$
在该文本中搜索文字 - 字符;
您将使用以下命令行获得完全相同的结果:
echo %%a | findstr /C:$ > nul
虽然我宁愿把它写成:
echo(%%a| findstr /C:"$" > nul
避免尾随SPACE并安全地回显任何文本。
对于这项任务,我可能会采用另一种方法(请参阅所有解释性rem
说明):
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=D:\Target\Path" & rem // (path to root directory)
set "_MASK=*.txt" & rem // (name or mask of files to process)
set "_SAVE=D:\Path\To\output.txt" & rem // (location of output file)
rem // Gather line-feed character:
(set ^"_LF=^
%= blank line =%
^")
rem // Gather carriage-return character:
for /F %%C in ('copy /Z "%~f0" nul') do set "_CR=%%C"
rem // Open output file only once and write to it:
> "%_SAVE%" (
rem // Find matching files and loop through them:
for /R "%_ROOT%" %%F in ("%_MASK%") do (
rem // Check for file existence (only necessary when a dedicated name is given):
if exist "%%~F" (
rem // Store path of current file:
set "FILE=%%~F"
rem // Toggle delayed expansion to avoid troubles with `!`:
setlocal EnableDelayedExpansion
rem // Remove remaining quotes (only necessary when a dedicated name is given):
set "FILE=!FILE:"=!
rem /* Do a multi-line search by `findstr`, which only returns the first line;
rem the searched string is:
rem # anchored to the beginning of a line,
rem # an `!`, a space and a `T`, then
rem # some arbitrary text (without line-breaks), then
rem # a line-break, then another `!` and a space, then
rem # a sequence of one or more `-`,
rem # anchored to the end of a line;
rem only the portion before the explicit line-break is then returned: */
findstr /R /C:"^^^! T.*~!_CR!!_LF!^! --*$" "!FILE!"
endlocal
)
)
)
endlocal
exit /B
这并不完全搜索! ---
etc. 之间的行,而是搜索两个相邻的行,其中第一行以!
++开头并以 结尾,第二行由SPACE++一个或多个 的序列组成。T
~
!
SPACE-
如果输入文件包含 Unix/Linux 样式的换行符而不是 DOS/Windows 样式的换行符,请在脚本!_CR!!_LF!
中的findstr
搜索字符串中替换为!_LF!
.
推荐阅读
- excel - 如何连接引用单元格的百分比
- java - Spring Boot 升级,set-cooike 标头未从 ResponseEntity 传递
- php - 在 Laravel 的同一页面上发布评论和显示评论
- python - Flask-sqlalchemy 临时会话/上下文变量
- django - 如何在 django 中同时在两个不同的数据库表中插入值?
- javascript - 如何在角度7中的一个ngfor下将两个不同插值中的值相乘
- clips - Is there a way to logically bind values from two different multislots?
- python - opencv/cv2/opencv-python 名称不匹配,如何说服 pip 不查找已通过 conda 安装的包?
- java - 如何在 javafx 中使用节点方法 setAll() 和 addAll()?
- sql - 如何从包含逗号分隔条目的变量中创建(不同的)值列表?