python、正则表达式、否定前瞻和匹配捕获问题

python, regex, trouble with negative lookahead and capture of the match

我在使用正则表达式时遇到了问题,也许你可以帮我解决这个问题。我的行变量包含我想要操作的这些字符串(每个 for 循环循环一个字符串):

sip="100.107.0.5" sp="123" dip="100.107.193.1" dp="123" nat-dip="84.2.44.19" sip="100.101.199.1" sp="37690" dip="100.107.0.4" dp="80" nat-dip="100.107.0.4"

最简单的部分:当dip=和nat-dip=后引号中的值相等时,将子字符串nat-dip="..."完全删除。这很容易做到:

line = re.sub(r'dip="([^"]+)(" .+)nat-dip="" ' ,r'dip="' ,line)

但糟糕的是:当值不相等时,写下 nat-dip= 的值代替 dip= 的值。我尝试使用负前瞻并捕获值,但它不断失败,我无法找出代码行的错误部分,即:

line = re.sub(r'dip="([^"]+)(" .+)(?!nat-dip="()") ' ,r'dip="' ,line)

我得到的是:

sip="100.107.0.5" sp="123" dip="" dp="123" nat-dip="84.2.44.19"

... 而不是这个:

sip="100.107.0.5" sp="123" dip="84.2.44.19" dp="123"

我做错了什么?你有什么建议吗?

如果你想在这两种情况下删除 nat-dip,你可以在单个替换中使用这样的表达式 (demo)

dip=\"[^\"]*\"([ ]dp=\"[^\"]*\")[ ]nat-dip=\"([^\"]*)\"
Replace Pattern: dip=""
 contains the value of nat-dip,
 contains the dp attribute and its value since it's caught in the capture

  dip=\"     # Literal dip="
  [^\"]*     # Any character but ", zero or more times.
  \"         # Literal "
  (          # Open Capture Group 1 (to retain dp)
    [ ]      # a single space, bracketed here for visibility
    dp=\"    # Literal dp="
    [^\"]*   # Any character but ", zero or more times.
    \"       # Literal "
  )          # Close Capture group
  [ ]        # A single space
  nat-dip=\" # Literal nat-dip="
  (          # Open capture group 2 (the value of nat-dip)
    [^\"]*   # Any character but ", zero or more times.
  )          # Close capture group 2
  \"         # Literal "

它总是将 dip 的值设置为 nat-dip 的值。当它们相等时,这不是明显的变化。当它们不相等时,它会改变值。在这两种情况下,它都会掉落 nat-dip。


更新: 根据您的评论。有机会你会说 "No, we need to keep nat-dip in that case."。理想情况下,我会使用分支重置(保持捕获组一致,但 Python 不支持。

所以我会使用像这样的 if-then-else 条件 (?(?=lookaround condition)true pattern|false pattern))。网上的一切都说 python 支持这样的组,但 regex101 不断抛出模式错误(即使使用示例中的复制粘贴,所以没有拼写错误),.对于这个演示,我切换到 PCRE demo.

dip=\"([^\"]*)\"([ ]dp=\"[^\"]*\")(?(?![ ]nat-dip="")([ ]nat-dip=\"([^\"]*)\")|[ ]nat-dip=\"([^\"]*)\")

dip=\"([^\"]*)\"([ ]dp=\"[^\"]*\")
(?                            # if
  (?![ ]nat-dip="")         # condition
    ([ ]nat-dip=\"([^\"]*)\")   # then do
  |                           # else
    [ ]nat-dip=\"([^\"]*)\"     # do
  )                           # end if

主要区别在于 else-do 不捕获它的内容。它可以,但它永远不会使用它们。

如果满足条件 </code> 包含整个 <code>nat-dip 属性 值。如果不满足条件,</code>什么都不是,<code>""

您会注意到替换模式是 dip="",因为 nat-dip value 是否在 </code> 中并且 <code> 是否为空,反之亦然取决于如果满足条件。

在分支重置的情况下,两个值都可以与 \4 对齐。可以让眼睛轻松一点。没有 Regex Flavor 支持所有好东西。

但事实是,我只是向您展示一个前瞻性解决方案,因为您提出了问题,在这种情况下甚至没有必要。简单的交替就可以了,尽管有必要颠倒交替的顺序 (demo) 当然,在某些情况下,条件语句是救星(特别是关于 lookbehinds.

终于,多行代码很难做到这一点。我们可以将其分解为带有回调的模式提取,该回调使用 python 的 if 到 return 结果,但我们的目标是提高效率。但可以肯定的是,并非所有事情都可以用一种表达方式来完成。如果你想用 dp 做其他事情,那通常需要,而且通常是有意义的,在一个单独的动作中。