正后视正则表达式未按预期匹配

Positive lookbehind regex not matching as expected

我正在尝试在 python 正则表达式中使用正向回顾来匹配此示例 zpool 输出中的设备名称和序列号。我想我不太了解 lookbehind 语法,因为我无法匹配序列号。

我正在使用桌面上的模式应用程序对此进行沙盒处理。我还有其他几个关于后向断言的 Whosebug 问题,但我能找到的似乎只是表明我走在正确的轨道上,到目前为止我所看到的一切都没有清楚地表明我错了什么。

pool                           ONLINE       0     0     0
  raidz2-0                       ONLINE       0     0     0
    diskid/DISK-PK2331PAG6ZLMT   ONLINE       0     0     0 
    da21                         ONLINE       0     0     0 
    diskid/DISK-PK2331PAG6ZVMT   ONLINE       0     0     0 
    diskid/DISK-PK2331PAG728ET   ONLINE       0     0     0 
    diskid/DISK-PK2331PAG6YGXT   ONLINE       0     0     0 

我想在第一组中抓取设备或序列号,在第二组中抓取其状态(ONLINE|AVAIL)。我使用的正则表达式是:

^\s+(da\d+|(?<=diskid/DISK-)\S+)\s+(ONLINE|AVAIL)\s

它匹配设备名称 da21 及其状态,但它没有看到按序列号命名的设备。这个语法我错过了什么?

为什么它不起作用

让我们看一行,看看你的正则表达式匹配什么:

# your regex
^\s+(da\d+|(?<=diskid/DISK-)\S+)\s+(ONLINE|AVAIL)\s

# your string
    diskid/DISK-PK2331PAG6ZLMT   ONLINE       0     0     0
<                     # ^ assert position at start of string
^^^^                  # \s+ match one or more whitespace characters
    ^!                # da\d+ matches d, fails to match a, backtrack; try next alternation
<<<<<!                # (?<=diskid/DISK-) assert what precedes matches the lookbehind
# This fails because the text to the left of the position that the parser is at does
#     not match diskid/DISK- (it's four spaces as was previously matched by \s+)

如何解决?

有多种正则表达式模式可以满足您要实现的目标:

选项 1:单个捕获组

如果前面有 diskid/DISK-da\d+,则将 \S+ 捕获到捕获组 1,然后将 ONLINEAVAIL 捕获到捕获组 2 .

((?<=diskid/DISK-)\S+|da\d+)\s+(ONLINE|AVAIL)\b

专业版:一个捕获组
缺点:不能保证第一个捕获组在行首

选项 2:锚定到行首

如果前面有 diskid/DISK-,这会将 \S+ 捕获到捕获组 1,或者 da\d+ 进入捕获组 2,然后捕获 ONLINEAVAIL进入捕获组 3。

^\s+(?:diskid/DISK-(\S+)|(da\d+))\s+(ONLINE|AVAIL)\b

专业版:锚定到行首 - 我们可以确保这是我们要匹配的数据所在的位置 (^\s+) 缺点:两个捕获组(我们不能将两组不同的数据与两组不同的前置字符串条件匹配到一个捕获组中)

选项 3:使用 regex

我们可以使用 PyPi regex 库很容易地完成它,让我们产生一组并断言它在字符串中的位置。

分支重置方法(交替产生单个捕获组而不是两个):

^\s+(?|diskid/DISK-(\S+)|(da\d+))\s+(ONLINE|AVAIL)\b
      ^           # same as option 2, but uses branch reset