正则表达式意外结束:Python.Regex

1 投票
4 回答
7312 浏览
提问于 2025-04-16 21:57

当我使用下面的python正则表达式来实现描述的功能时,我遇到了“意外的模式结束”的错误。

正则表达式:

modified=re.sub(r'^(?i)((?:(?!http://)(?!testing[0-9])(?!example[0-9]).)*?)(?-i)
(CODE[0-9]{3})(?!</a>)',r'<a href="http://productcode/\g<1>">\g<1></a>',input)

这个正则表达式的目的:

输入:

CODE876
CODE223
matchjustCODE657
CODE69743
code876
testing1CODE888
example2CODE098
http://replaced/CODE665

应该匹配:

CODE876
CODE223
CODE657
CODE697

并将出现的内容替换为

http://productcode/CODE876
http://productcode/CODE223
matchjusthttp://productcode/CODE657
http://productcode/CODE69743

不应该匹配:

code876
testing1CODE888
testing2CODE776
example3CODE654
example2CODE098
http://replaced/CODE665

最终输出

http://productcode/CODE876
http://productcode/CODE223
matchjusthttp://productcode/CODE657
http://productcode/CODE69743
code876
testing1CODE888
example2CODE098
http://replaced/CODE665

编辑和更新 1

modified=re.sub(r'^(?i)((?:(?!http://)(?!testing[0-9])(?!example[0-9]).)*?)(CODE[0-9]{3})(?!</a>)',r'<a href="http://productcode/\g<1>">\g<1></a>',input)

现在不再出现这个错误了。但是,这个正则表达式没有匹配到任何需要的模式。是不是在匹配组或者匹配本身上有问题?因为当我这样编译这个正则表达式时,我的输入没有匹配到。

编辑和更新 2

f=open("/Users/mymac/Desktop/regex.txt")
s=f.read()

s1 = re.sub(r'((?!http://|testing[0-9]|example[0-9]).*?)(CODE[0-9]{3})(?!</a>)', 
            r'\g<1><a href="http://productcode/\g<2>">\g<2></a>', s)
print s1

输入

CODE123 CODE765 testing1CODE123 example1CODE345 http://www.coding.com/CODE333 CODE345

CODE234

CODE333

输出

<a href="http://productcode/CODE123">CODE123</a> <a href="http://productcode/CODE765">CODE765</a> testing1<a href="http://productcode/CODE123">CODE123</a> example1<a href="http://productcode/CODE345">CODE345</a> http://www.coding.com/<a href="http://productcode/CODE333">CODE333</a> <a href="http://productcode/CODE345">CODE345</a>

<a href="http://productcode/CODE234">CODE234</a>

<a href="http://productcode/CODE333">CODE333</a>

正则表达式对原始输入有效,但对从文本文件中读取的字符串输入无效。

查看输入4和5以获取更多结果 http://ideone.com/3w1E3

4 个回答

0

对于复杂的正则表达式,可以使用 re.X 标志 来帮助你记录你在做什么,并确保括号能正确配对(也就是说,可以通过缩进来表示当前的嵌套层级)。

5

你主要的问题是这个(?-i)的东西,这在Python 2.7和3.2中是不可能实现的。想了解更多细节,请看下面。

import re
# modified=re.sub(r'^(?i)((?:(?!http://)(?!testing[0-9])(?!example[0-9]).)*?)(?-i)
# (CODE[0-9]{3})(?!</a>)',r'<a href="http://productcode/\g<1>">\g<1></a>',input)
# observation 1: as presented, pattern has a line break in the middle, just after (?-i)
# ob 2: rather hard to read, should use re.VERBOSE
# ob 3: not obvious whether it's a complile-time or run-time problem
# ob 4: (?i) should be at the very start of the pattern (see docs)
# ob 5: what on earth is (?-i) ... not in 2.7 docs, not in 3.2 docs
pattern = r'^(?i)((?:(?!http://)(?!testing[0-9])(?!example[0-9]).)*?)(?-i)(CODE[0-9]{3})(?!</a>)'
#### rx = re.compile(pattern)
# above line failed with "sre_constants.error: unexpected end of pattern"
# try without the (?-i)
pattern2 = r'^(?i)((?:(?!http://)(?!testing[0-9])(?!example[0-9]).)*?)(CODE[0-9]{3})(?!</a>)'
rx = re.compile(pattern2)
# This works, now you need to work on observations 1 to 4,
# and rethink your CODE/code strategy

看起来建议没有被重视……这是用re.VERBOSE格式写的模式:

pattern4 = r'''
    ^
    (?i)
    (
        (?:
            (?!http://)
            (?!testing[0-9])
            (?!example[0-9])
            . #### what is this for?
        )*?
    ) ##### end of capturing group 1
    (CODE[0-9]{3}) #### not in capturing group 1
    (?!</a>)
    '''
2

好的,看起来问题出在 (?-i) 这个部分,这让人有点意外。这个内联修饰符的语法本来是用来让你可以对正则表达式的某些部分应用修饰符的。至少在大多数情况下是这样。但在 Python 中,它似乎总是会影响整个正则表达式,就像外部的标志(re.I, re.M 等)一样。另一种 (?i:xyz) 的语法也不管用。

顺便说一下,我觉得没有必要像你这里那样使用三个单独的前瞻:

(?:(?!http://)(?!testing[0-9])(?!example[0-9]).)*?

可以把它们用“或”连接起来:

(?:(?!http://|testing[0-9]|example[0-9]).)*?

编辑:我们似乎已经从正则表达式为什么会抛出异常的问题,转到了它为什么不工作的这个问题。我不太确定我理解你的需求,但下面的正则表达式和替换字符串可以返回你想要的结果。

s1 = re.sub(r'^((?!http://|testing[0-9]|example[0-9]).*?)(CODE[0-9]{3})(?!</a>)', 
            r'\g<1><a href="http://productcode/\g<2>">\g<2></a>', s)

在 ideone.com 上看看效果

这就是你想要的吗?


编辑:我们现在知道替换是在更大的文本中进行的,而不是在独立的字符串上。这让问题变得更加复杂,但我们也知道完整的 URL(以 http:// 开头的那些)只会出现在已经存在的锚元素中。这意味着我们可以把正则表达式分成两个选择:一个是匹配完整的 <a>...</a> 元素,另一个是匹配我们的目标字符串。

(?s)(?:(<a\s+[^>]*>.*?</a>)|\b((?:(?!testing[0-9]|example[0-9])\w)*?)(CODE[0-9]{3}))

关键是用一个函数来替代静态字符串进行替换。每当正则表达式匹配到一个锚元素时,函数会在 group(1) 中找到它并保持不变。否则,它会使用 group(2) 和 group(3) 来构建一个新的。

这是另一个演示(我知道这段代码很糟糕,但我现在太累了,不想学更 Pythonic 的写法。)

撰写回答