【问题标题】:Multiline Regex with opening and closing word带有开始和结束词的多行正则表达式
【发布时间】:2021-08-23 12:15:15
【问题描述】:

我需要承认,如果涉及到 RegEx 表达式,我是非常基础的。 我有一个用 C# 编写的应用程序,它在文本文件中查找某些 Regex 表达式。我不确定如何解释我的问题,所以我将直接举例。

我的文字:

   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.*?ready)) 演示:regex101.com/r/nZj7wS/2
  • 也许是个愚蠢的问题,但是我需要在“DeviceNr”和“ready”之间匹配“DeviceClass = ABC”和“Model = XYZ”行的部分呢?
  • 检查这个:(?=DeviceNr.*?(DeviceClass\s=\s\w+).*?(Model\s=\s\w+).*ready) 演示:regex101.com/r/nZj7wS/3
  • 它仍然没有给我我需要的东西。 regex101.com/r/MBXSht/1 我只需要一个匹配项(第二个匹配项),我需要知道我匹配了两行,并且它们被放置在“DeviceNr”中并且第一个找到“准备好”的词。

标签: regex multiline


【解决方案1】:

如果您知道"DeviceClass = ABC" and "Model = XYZ" 存在并且按照该顺序,您还可以在每行基础上使用先行断言,首先匹配所有不包含例如DeviceNr 的行

然后匹配匹配的行,并为Modelready 执行此操作

^\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 : 并在 group 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\bready 的方法相同

Regex demo

注意\s 也可以匹配换行符。如果你想防止这种情况,你也可以使用[^\S\r\n] 来匹配没有换行符的空白字符。

Regex demo

【讨论】:

  • 谢谢!感谢您的解释,这是非常复杂的模式,但它可以满足我的需求。
【解决方案2】:

问题是您要匹配 'DeviceNr : 31' 后跟 'DeviceClass = ABC' (可能带有一些中间字符),然后是 'Model = XYZ' (同样可能带有一些中间字符),然后是 'ready' (同样可能带有一些中间字符)确保这些中间字符实际上都不是另一个“DeviceNr”部分的开始

因此,为了将任意中间字符与上述强制匹配,我们可以使用以下正则表达式,该表达式使用 负前瞻断言

(?:(?!DeviceNr)[\s\S])*?
  1. (?: - 非捕获组的开始
  2. (?!DeviceNr) - 断言输入的下一个字符不是“DeviceNr”
  3. [\s\S] - 匹配空白或非空白字符,即任何字符
  4. )非捕获组结束
  5. *? 非贪婪匹配0个或多个字符,只要下一个输入不匹配'DeviceNr'

那么简单的事情就是重复使用上面的正则如下:

DeviceNr : (\d+)\n(?:(?!DeviceNr)[\s\S])*?DeviceClass = ABC\n(?:(?!DeviceNr)[\s\S])*?Model = XYZ\n(?:(?!DeviceNr)[\s\S])*?ready

See Regex Demo

捕获组 1 将具有 DeviceNr 值。

重要提示

就执行所需的步骤数而言,上述正则表达式非常昂贵,因为一旦匹配DeviceNr : (\d+),它就必须在几乎每个字符位置检查否定前瞻断言。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-19
    • 1970-01-01
    相关资源
    最近更新 更多