Python正则表达式替换-是否可以进行条件替换?

Python正则表达式替换-是否可以进行条件替换?,python,regex,Python,Regex,我正在尝试编写一个正则表达式,以确保“标记”按照规范正确地重新格式化。(我正在更新一堆遗留的东西。) 一般的想法是标记可以在()或[]中包含括号内的内容。但是,现有标记的格式可能不正确: 好: 样本(样本) Sample[样本] 坏的: 样本((样本) Sample[(示例)] 我目前正在一系列的正则表达式中处理这个问题,但我想知道在技术上是否可以在单个正则表达式中完成 在代码的简化版本中 RE_tag_collapse = re.compile(\ """

我正在尝试编写一个正则表达式,以确保“标记”按照规范正确地重新格式化。(我正在更新一堆遗留的东西。)

一般的想法是标记可以在
()
[]
中包含括号内的内容。但是,现有标记的格式可能不正确:

  • 好:
    • 样本(样本)
    • Sample[样本]
  • 坏的:
    • 样本((样本)
    • Sample[(示例)]
我目前正在一系列的正则表达式中处理这个问题,但我想知道在技术上是否可以在单个正则表达式中完成

在代码的简化版本中

RE_tag_collapse = re.compile(\
    """
        ([\[\(])+               ### opening bracket
            \s*
            (                   # the contents
                [^\]\)]+
            )
            \s*
        ([\]\)])*               # closing bracket
    """
    ,
    re.I | re.VERBOSE
)
edited= re.sub( RE_tag_collapse , r'\1\2\1' , tag )
此正则表达式的问题在于结束标记(第二个
\1
)与开始标记相同

我想做的是将结束标记映射为开始标记的倒数:

  • 转换为
  • [
    转换为
    ]

有人知道这是否容易实现吗?在我看来,我的最佳解决方案是保持现状并使用多个正则表达式。

如果我正确理解了您的问题,您需要确保标记中的括号匹配。据我所知,python中的正则表达式无法计算发生次数。但是,您可以使用Functionn要检查括号是否匹配,请执行以下操作:

def check_tag(tag):
    charstack = []
    for c in tag:
        if c in ["(","]"]:
            charstack.append(c)
        else if c in [")","]"]:
            popped = charstack.pop()
            if not ((c == ")" and popped == "(" ) or (c == "]" and popped == "[")):
                return False
    return len(charstack) == 0

此函数的工作方式是,每当它找到一个左括号时,它就会将其推到堆栈上。每当它遇到一个右括号时,它就会将一个元素从堆栈中推出来,以查看它们是否匹配。如果不匹配,则表示标记的格式不正确。

如果我正确理解了您的问题,您希望确保parenth标记中的ESI匹配。据我所知,python中的正则表达式无法计算出现次数。但是,您可以使用函数检查括号是否匹配,如下所示:

def check_tag(tag):
    charstack = []
    for c in tag:
        if c in ["(","]"]:
            charstack.append(c)
        else if c in [")","]"]:
            popped = charstack.pop()
            if not ((c == ")" and popped == "(" ) or (c == "]" and popped == "[")):
                return False
    return len(charstack) == 0

此函数的工作方式是,每当它找到一个左括号时,它就会将其推到堆栈上。每当它遇到一个右括号时,它就会将一个元素从堆栈中推出来,以查看它们是否匹配。如果不匹配,则表示标记的格式不正确。

修改regexp以将所有的左括号和右括号作为组捕获,t然后,您可以从开始括号集生成正确的结束括号集,并在regexp替换中使用它

像这样:

>>> def subber(matchobj):
    return ' '.join([matchobj.group(1),
             matchobj.group(2),
             matchobj.group(1).replace('[',']').replace('(', ')')[::-1]])

>>> new_RE = re.compile(\
    """
        ([\[\(]+)               ### opening brackets
            \s*
            (                   # the contents
                [^\]\)]+
            )
            \s*
        ([\]\)]+)               # closing brackets
    """
    ,
    re.I | re.VERBOSE
)
>>> txt = 'Sample [(sample]]'
>>> new_RE.sub(subber, txt)
'Sample [( sample )]'
>>> 

结束括号只是将捕获开始括号的组中的每个开始括号替换为结束括号,然后将其反转。

修改您的regexp以将所有开始括号和结束括号捕获为组,然后您可以从开始括号集生成正确的结束括号集,并在regexp子集中使用它惩罚

像这样:

>>> def subber(matchobj):
    return ' '.join([matchobj.group(1),
             matchobj.group(2),
             matchobj.group(1).replace('[',']').replace('(', ')')[::-1]])

>>> new_RE = re.compile(\
    """
        ([\[\(]+)               ### opening brackets
            \s*
            (                   # the contents
                [^\]\)]+
            )
            \s*
        ([\]\)]+)               # closing brackets
    """
    ,
    re.I | re.VERBOSE
)
>>> txt = 'Sample [(sample]]'
>>> new_RE.sub(subber, txt)
'Sample [( sample )]'
>>> 

结束方括号只是在捕获开始方括号的组中用每个开始方括号替换结束方括号,然后将其反转。

对于单个对,很容易,您可以使用反向引用:
([\[\(]).*\1
,除此之外,我有义务告诉您不要使用正则表达式,因为匹配方括号对不可用“常规”或类似的东西。它不是“常规”的事实意味着你不能用有限状态机(fsm)检查它,因为这将需要无限数量的状态,因为括号的数量可以无限大。如果Python的PCRE引擎与Perl 5.10兼容,则应支持递归模式,这可用于匹配平衡表达式。请参阅@Mark的递归模式部分:您的解决方案甚至无法工作,因为
([\[\(]).\1
将匹配
[foo[
,但不匹配
[foo]
@TimPietzcker:非常正确。我经常这样做是为了匹配单引号或双引号,但我显然没有考虑到括号的情况;)对于单对,很简单,您可以使用反向引用:
([\[\[\(]).*\1
,除此之外,我有义务告诉您不要使用正则表达式,因为匹配的括号对不是“正则”或类似的东西。它不是“正则”的事实意味着您无法使用有限状态机(fsm)检查它,因为这将需要无限数量的状态,因为括号的数量可以无限大。如果Python的PCRE引擎与Perl 5.10兼容,则应支持递归模式,这可用于匹配平衡表达式。请参阅@Mark的递归模式部分:您的解决方案甚至无法工作,因为
([\[\(]).\1
会匹配
[foo[
但不会匹配
[foo]
@TimPietzcker:非常正确。我经常这样做是为了匹配单引号或双引号,但我显然没有考虑到括号的情况;)回答得很好。设置一个字符串元组
correct=(“()”,“[])
,然后检查
如果不匹配的话。加入([popped,c])正确:改为返回False
?这确实会使它更灵活,因此如果您想添加{和}之类的内容或者,您只需编辑该元组,而不必编辑整个代码中的字符串,从而使if语句更加复杂。回答得好。设置字符串元组
correct=(“()”,“[]”)并检查
是否为“”。加入([popped,c])正确:返回False
?这确实会使它更灵活,因此如果您想添加{and}或,只需编辑该元组,而不必编辑整个代码中的字符串,从而使if语句更加复杂。