带有开始和结束词的多行正则表达式
Multiline Regex with opening and closing word
我得承认,如果涉及到 RegEx 表达式,我是非常基础的。
我有一个用 C# 编写的应用程序,它在文本文件中查找某些正则表达式。我不确定如何解释我的问题,所以我将直接举例。
我的文字:
DeviceNr : 30
DeviceClass = ABC
UnitNr = 1
Reference = 29
PhysState = ENABLED
LogState = OPERATIVE
DevicePlan = 702
Manufacturer = CDE
Model = EFG
ready
DeviceNr : 31
DeviceClass = ABC
UnitNr = 9
Reference = 33
PhysState = ENABLED
LogState = OPERATIVE
Manufacturer = DDD
Model = XYZ
Description = something here
ready
我需要匹配以“DeviceNr”字样开头、以“ready”结尾并具有“DeviceClass = ABC”和“Model = XYZ”的多行文本 - 我只能假设这些行将在此确切的顺序,但我不能假设它们之间会有什么,甚至不能假设它们之间的其他行数。我尝试使用以下正则表达式,但它匹配了整个文本,而不仅仅是 DeviceNr : 31
DeviceNr : ([0-9]+)(?:.*?\n)*? DeviceClass = ABC(?:.*?\n)*? Model = XYZ(?:.*?\n)*?ready\n\n
问题是您要匹配 'DeviceNr : 31' 后跟 'DeviceClass = ABC'(可能有一些中间字符)然后是 'Model = XYZ'(同样可能有一些中间字符)然后是 'ready'(同样可能有一些中间字符)确保这些中间字符中的 none 实际上是另一个 'DeviceNr' 部分的开始 .
因此,为了将任意中间字符与上述强制执行相匹配,我们可以使用以下正则表达式,该表达式使用了负先行断言:
(?:(?!DeviceNr)[\s\S])*?
(?:
- 非捕获组的开始
(?!DeviceNr)
- 断言输入的下一个字符不是 'DeviceNr'
[\s\S]
- 匹配空白或非空白字符,即 any 字符
)
非捕获组结束
*?
非贪婪匹配0个或多个字符只要下一个输入不匹配'DeviceNr'
那么重复使用上面的正则表达式就很简单了,如下:
DeviceNr : (\d+)\n(?:(?!DeviceNr)[\s\S])*?DeviceClass = ABC\n(?:(?!DeviceNr)[\s\S])*?Model = XYZ\n(?:(?!DeviceNr)[\s\S])*?ready
捕获组 1 将具有 DeviceNr
值。
重要提示
上面的正则表达式在执行所需的步骤数方面非常昂贵,因为它必须在匹配 DeviceNr : (\d+)
.
后检查几乎每个字符位置的否定前瞻断言
如果您知道 "DeviceClass = ABC" and "Model = XYZ"
存在并按此顺序,您还可以在每行基础上使用先行断言,首先匹配所有不包含的行,例如 DeviceNr
然后匹配匹配的行,对 Model
和 ready
也这样做
^\s*DeviceNr : ([0-9]+)(?:\r?\n(?!\s*DeviceClass =).*)*\r?\n\s*DeviceClass = ABC\b(?:\r?\n(?!\s*Model =).*)*\r?\n\s*Model = XYZ\b(?:\r?\n(?!\s*ready).*)*\r?\n\s*ready\b
^
字符串开头
\s*DeviceNr : ([0-9]+)
匹配 DeviceNr :
并在 组 1 中捕获 1+ 个数字 0-9
(?:
非捕获组
\r?\n(?!\s*DeviceClass =).*
匹配一个换行符,断言该行不包含DeviceClass =
)*
关闭非捕获组并可选择重复,因为您不知道有多少行
\r?\n\s*DeviceClass = ABC\b
匹配一个换行符,可选的空白字符和 DeviceClass = ABC
(?:\r?\n(?!\s*Model =).*)*\r?\n\s*Model = XYZ\b
之前的做法也适用于Model =
(?:\r?\n(?!\s*ready).*)*\r?\n\s*ready\b
和 ready
相同的方法
请注意,\s
也可以匹配换行符。如果你想防止这种情况,你也可以使用 [^\S\r\n]
来匹配没有换行符的空白字符。
我得承认,如果涉及到 RegEx 表达式,我是非常基础的。 我有一个用 C# 编写的应用程序,它在文本文件中查找某些正则表达式。我不确定如何解释我的问题,所以我将直接举例。
我的文字:
DeviceNr : 30
DeviceClass = ABC
UnitNr = 1
Reference = 29
PhysState = ENABLED
LogState = OPERATIVE
DevicePlan = 702
Manufacturer = CDE
Model = EFG
ready
DeviceNr : 31
DeviceClass = ABC
UnitNr = 9
Reference = 33
PhysState = ENABLED
LogState = OPERATIVE
Manufacturer = DDD
Model = XYZ
Description = something here
ready
我需要匹配以“DeviceNr”字样开头、以“ready”结尾并具有“DeviceClass = ABC”和“Model = XYZ”的多行文本 - 我只能假设这些行将在此确切的顺序,但我不能假设它们之间会有什么,甚至不能假设它们之间的其他行数。我尝试使用以下正则表达式,但它匹配了整个文本,而不仅仅是 DeviceNr : 31
DeviceNr : ([0-9]+)(?:.*?\n)*? DeviceClass = ABC(?:.*?\n)*? Model = XYZ(?:.*?\n)*?ready\n\n
问题是您要匹配 'DeviceNr : 31' 后跟 'DeviceClass = ABC'(可能有一些中间字符)然后是 'Model = XYZ'(同样可能有一些中间字符)然后是 'ready'(同样可能有一些中间字符)确保这些中间字符中的 none 实际上是另一个 'DeviceNr' 部分的开始 .
因此,为了将任意中间字符与上述强制执行相匹配,我们可以使用以下正则表达式,该表达式使用了负先行断言:
(?:(?!DeviceNr)[\s\S])*?
(?:
- 非捕获组的开始(?!DeviceNr)
- 断言输入的下一个字符不是 'DeviceNr'[\s\S]
- 匹配空白或非空白字符,即 any 字符)
非捕获组结束*?
非贪婪匹配0个或多个字符只要下一个输入不匹配'DeviceNr'
那么重复使用上面的正则表达式就很简单了,如下:
DeviceNr : (\d+)\n(?:(?!DeviceNr)[\s\S])*?DeviceClass = ABC\n(?:(?!DeviceNr)[\s\S])*?Model = XYZ\n(?:(?!DeviceNr)[\s\S])*?ready
捕获组 1 将具有 DeviceNr
值。
重要提示
上面的正则表达式在执行所需的步骤数方面非常昂贵,因为它必须在匹配 DeviceNr : (\d+)
.
如果您知道 "DeviceClass = ABC" and "Model = XYZ"
存在并按此顺序,您还可以在每行基础上使用先行断言,首先匹配所有不包含的行,例如 DeviceNr
然后匹配匹配的行,对 Model
和 ready
^\s*DeviceNr : ([0-9]+)(?:\r?\n(?!\s*DeviceClass =).*)*\r?\n\s*DeviceClass = ABC\b(?:\r?\n(?!\s*Model =).*)*\r?\n\s*Model = XYZ\b(?:\r?\n(?!\s*ready).*)*\r?\n\s*ready\b
^
字符串开头\s*DeviceNr : ([0-9]+)
匹配DeviceNr :
并在 组 1 中捕获 1+ 个数字 0-9
(?:
非捕获组\r?\n(?!\s*DeviceClass =).*
匹配一个换行符,断言该行不包含DeviceClass =
)*
关闭非捕获组并可选择重复,因为您不知道有多少行\r?\n\s*DeviceClass = ABC\b
匹配一个换行符,可选的空白字符和DeviceClass = ABC
(?:\r?\n(?!\s*Model =).*)*\r?\n\s*Model = XYZ\b
之前的做法也适用于Model =
(?:\r?\n(?!\s*ready).*)*\r?\n\s*ready\b
和ready
相同的方法
请注意,\s
也可以匹配换行符。如果你想防止这种情况,你也可以使用 [^\S\r\n]
来匹配没有换行符的空白字符。