【问题标题】:python, regex, trouble with negative lookahead and capture of the matchpython,正则表达式,负前瞻问题和匹配捕获
【发布时间】:2017-03-02 17:33:16
【问题描述】:

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

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="\1" ' ,r'dip="\1\2' ,line)

但可怕的是:当值不相等时,写入 nat-dip= 的值代替 dip= 的值。我尝试了负前瞻和捕获值,但它不断失败,我无法找出代码行的错误部分,即:

line = re.sub(r'dip="([^"]+)(" .+)(?!nat-dip="(\1)") ' ,r'dip="\3\2' ,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"

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

【问题讨论】:

  • 你在处理html/xml吗?
  • 没有。原始文本。一行一行
  • @zweiund40 当值不匹配时,dip 的值应设置为 nat-dip。那么 nat-dip 是否也应该被移除?

标签: python regex string negative-lookahead


【解决方案1】:

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

dip=\"[^\"]*\"([ ]dp=\"[^\"]*\")[ ]nat-dip=\"([^\"]*)\"
Replace Pattern: dip="\2"\1
\2 contains the value of nat-dip,
\1 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。


更新:根据您的评论。有机会你会说“不,在那种情况下我们需要保持 nat-dip。”。理想情况下,我会使用分支重置(保持捕获组一致,但 Python 不支持。

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

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

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

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

如果满足条件\3包含整个nat-dip属性值。如果条件不满足,\3什么都没有,""

您会注意到替换模式是dip="\4\5"\2\3,因为nat-dip value 是否在\4\5 中是空的,反之亦然取决于是否满足条件。

在分支重置的情况下,两个值都可以对齐到 \4。眼睛可以轻松一点。没有正则表达式支持所有的好东西。

但事实是,我只是向您展示了一个前瞻解决方案,因为您问过,在这种情况下甚至都不需要。简单的交替就可以了,尽管有必要颠倒交替的顺序 (demo) 在某些情况下,条件肯定是一种救命稻草(尤其是关于 lookbehinds

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

【讨论】:

  • 呃……是的。有时,只见树木不见森林。最后它是一样的,你的分辨率更优雅,因为它很简单。
  • 不过。只是出于好奇。用负前瞻和捕获值进行替换看起来如何。过去我有时会遇到这样的问题,我总是需要不止一行代码来解决它。有没有办法按照要求做到这一点?
  • @zweiund40 是的,我完全认为这里就是这种情况。陷入如此深的境地,以至于您过度考虑了正则表达式中可能淹没的一切。 ////另外,用替代方法更新了答案。
  • 呃……这比我想象的要复杂得多。它看起来很棒,但我不得不承认我没有完全理解它。我会抓住我的正则表达式书,然后回到实验室。非常感谢。
  • 什么是upvoting?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-03
  • 1970-01-01
  • 1970-01-01
  • 2021-10-11
  • 2018-12-28
  • 2012-04-14
相关资源
最近更新 更多