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
做其他事情,那通常需要,而且通常是有意义的,在一个单独的动作中。
我在使用正则表达式时遇到了问题,也许你可以帮我解决这个问题。我的行变量包含我想要操作的这些字符串(每个 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
做其他事情,那通常需要,而且通常是有意义的,在一个单独的动作中。