批量正则表达式换行

时间:2013-11-08 13:12:21

标签: regex batch-file findstr linefeed

我想将以下文本的所有行与FINDSTR / R

匹配
LABO_A =
  (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))
    (CONNECT_DATA =
      (SERVICE_NAME = LABO)
    )
  )

我已经尝试What are the undocumented features and limitations of the Windows FINDSTR command? 特别是“搜索跨线休息”部分。但不幸的是它没有用。

我的方法如下:

SETLOCAL
set LF=^


FOR /F %%A IN ('COPY /Z "%~dpf0" NUL') DO SET "CR=%%A"

SETLOCAL enableDelayedExpansion
FINDSTR /R "LABO_A.=.!CR!*!LF!.*(DESCRIPTION.=.!CR!*!LF!.*(ADDRESS.=.(PROTOCOL.=.TCP)(HOST.=.host01)(PORT.=.1521))!CR!*!LF!.*(CONNECT_DATA.=!CR!*!LF!.*(SERVICE_NAME.=.LABO)!CR!*!LF!.*)!CR!*!LF!.*)" %FINDPATH%

我错过了什么吗?或者批量正则表达式是不是足以实现这一点?

解: @dbenham的方法让我重新考虑我的正则表达式字符串。所以我将其编辑为

FINDSTR /R /C:"LABO_A =!CR!*!LF!.*(DESCRIPTION =!CR!*!LF!.*(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))!CR!*!LF!.*(CONNECT_DATA =!CR!*!LF!.*(SERVICE_NAME = LABO)!CR!*!LF!.*)!CR!*!LF!.*)" %FINDPATH% > NUL

我删除了一些不必要的空格并调整了FINDSTR的参数。

现在可行。

3 个答案:

答案 0 :(得分:2)

你的正则表达式错了。您的源代码行在=之后立即结束,但正则表达式中的额外.正在=之后查找其他字符。

我认为您使用.来表示空白区域。我认为你最好使用实际空格,但是你需要/C选项。

以下内容成功匹配。

@echo off
SETLOCAL
set LF=^


FOR /F %%A IN ('COPY /Z "%~dpf0" NUL') DO SET "CR=%%A"

SETLOCAL enableDelayedExpansion
FINDSTR /R /C:"LABO_A =!CR!*!LF! *(DESCRIPTION =!CR!*!LF! *(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))!CR!*!LF! *(CONNECT_DATA =!CR!*!LF! *(SERVICE_NAME = LABO)!CR!*!LF! *)!CR!*!LF! *)" test.txt

请注意,即使正则表达式中的所有行都匹配,也只会打印匹配集的第一行。

我怀疑配置文件中不需要换行符。这是另一种允许更多白色空间变化的变体。

@echo off
setlocal enableDelayedExpansion
set LF=^


FOR /F %%A IN ('COPY /Z "%~dpf0" NUL') DO SET "CR=%%A"
set "ws=[ !cr!!lf!]*"

FINDSTR /RX /C:"LABO_A =!ws!(DESCRIPTION =!ws!(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))!ws!(CONNECT_DATA =!ws!(SERVICE_NAME = LABO)!ws!)!ws!)!ws!" test.txt

我还尝试在我认为可能的每个地方允许空格,但这超出了FINDSTR的最大REGEX字符串长度。

答案 1 :(得分:1)

基本上,批处理正则表达式不够强大。毫无疑问,SED会更好。

尽管如此,这是一种检测文件中出现一系列行的方法。它有点受限制,但应该足以满足你提名的顺序。它假定前导空格不重要。

@ECHO OFF
SETLOCAL enabledelayedexpansion
FOR /f "delims==" %%a IN ('set l_ 2^>nul') DO "SET %%a="
SET /a lines=0
FOR /f "tokens=*" %%a IN (q19859936.txt) DO SET /a lines+=1&SET l_!lines!=%%a

SET hits=0
SET "stop="
FOR /f "tokens=*" %%a IN (q19859936.test) DO (
 SET l_0=%%~a
 CALL :test
 IF DEFINED stop GOTO done
)
:done
IF DEFINED stop (ECHO FOUND ) ELSE (ECHO NOT FOUND)

GOTO :EOF

:test
SET /a hits+=1
ECHO IF NOT "!l_%hits%!"=="%l_0%" 
IF NOT "!l_%hits%!"=="%l_0%" SET hits=0&IF %hits%==1 (GOTO :eof) ELSE (GOTO test)
IF %hits%==%lines% SET stop=Y
GOTO :eof

[编辑代码20131111T1408Z - 首先FORtokens=2]

初始FOR可确保清除变量L_*

文件q19859936.txt被读取为要检测的行序列。

然后检查

q19859936.test。每行依次分配给L_0,内部子程序:test将检查它是否与预期的下一行匹配。

IF NOT语句很重要 - 而且看似不合逻辑(如果你想要的话,你需要添加/i开关以使其不区分大小写...)当批处理解析该行时, %hits%被当前的hits值和 THEN 替换,执行该行,如果发现不匹配,hits将重置为0 。如果HITS计数 WAS 不是1,则重复测试。这样可以处理案例

matches line 1
matches line 2
matches line 3
matches line 1
matches line 2
matches line 3
matches line 4
matches line 5
matches line 6

当预期“第4行”时遇到第二个“第1行”。因此HITS更改为0,但 WAS 4,因此执行会返回:test,并且HITS = 1重复测试。

另一种方法可能是将行读入另一个数组(比如L#*)并测试L_*匹配L#*,用于%LINES%条目。在没有匹配的情况下,波及并将下一行读取分配给L#!lines! ...但我后来想到了。可能也会更容易和更好 - 我会把它作为锻炼给任何可能感兴趣的人。

答案 2 :(得分:0)

如果您在LABO_A参考之后,这将有效。

它使用来自 - https://www.dropbox.com/s/rfdldmcb6vwi9xc/findrepl.bat

的名为findrepl.bat的帮助程序批处理文件

findrepl.bat放在与批处理文件相同的文件夹中或路径上。

type "file.txt" | findrepl "^LABO_A =" /e:"^  \)"