【问题标题】:Split string on comma not present in round brackets or curly brackets in pythonpython中的圆括号或大括号中不存在逗号上的拆分字符串
【发布时间】:2019-01-23 23:51:36
【问题描述】:

下面是我试图用逗号分割的字符串。

如果 () 或 {} 中存在逗号,则不应拆分该字符串。

我正在使用以下代码进行拆分:

现在只处理 (),我如何也包含 {}?

import re
s = "Water,^.*f04.*&~(.*z.,*)$,Iron Oxides (CI 77491, 77492),a{3,4}"
print re.split(r',\s*(?![^()]*\))', s)

输出应该是:

[Water,^.*f04.*&~(.*z.,*)$,Iron Oxides (CI 77491, 77492),a{3,4}]

【问题讨论】:

  • 括号可以嵌套吗?如果是这样,这不是一种常规语言,所以你可能不想用正则表达式来解决它。
  • 它可以是如果它看起来是一个有效的正则表达式。所以基本上如果逗号是正则表达式的一部分并且它在 () 或 {} 或 [] 内,那么那个字符串不应该被拆分

标签: python regex python-2.7 list


【解决方案1】:

假设您的括号可以嵌套,那么您所拥有的不是常规语言。虽然re 确实有很多扩展,可以让它处理实际正则表达式之外的事情,但最好使用一个简单的括号计数解析器来解决这个问题。

类似这样的东西(未经测试,但应该足够简单,易于理解和调试):

bracketmap = {'(': ')', '[': ']', '{': '}'}

def splitify(s):
    stack = []
    lastcomma = 0
    for i, c in enumerate(s):
        if not stack and c == ',':
            yield s[lastcomma:i]
            lastcomma = i+1
        elif c in bracketmap:
            stack.append(bracketmap[c])
        elif c in ')]}':
            if stack.pop() != c:
                raise ValueError('unbalanced brackets')
    if stack:
        raise ValueError('unbalanced brackets')
    if lastcomma <= len(s):
        yield s[lastcomma:]

从评论中,当被问及您的括号是否可以嵌套时,您说:

如果它看起来是一个有效的正则表达式就可以。

因此,如果字符串实际上是正则表达式模式,您需要做的不仅仅是排除括号内的逗号。例如,\{,\} 不是用于计数的大括号内的逗号,而是完全正常的文字逗号。

编写一个完整的正则表达式解析器显然比只计算括号对要复杂一些(尽管如果您想要完全使用 Python re 语法,您可以使用该库编译它,然后使用该库的调试工具进行扫描对于文字括号,而不是自己编写...),但也许您可以只计算未转义的括号对?

    esc = False
    for i, c in enumerate(s):
        if esc:
            esc = False
        elif c = '\\':
            esc = True
        elif not stack and c == ',':
            # same as before

(我在这里假设您不想将 \, 视为文字逗号。如果您这样做,那只是一个微不足道的更改。)

【讨论】:

    【解决方案2】:

    使用regex 模块允许可变长度的后视:

    regex.split(r'(?<![({][^,]*),(?![^,]*[})])', str_)
    
    • (?&lt;![({][^,]*) 是一个零宽度的负向回看,确保 , 前面没有 ({,并且两者之间没有 ,

    • , 匹配文字 ,

    • (?![^,]*[})]) 是一个零宽度的负前瞻,可确保 , 后面没有任何中间 , 后跟 )}

    示例:

    In [1287]: str_ = "Water,^.*f04.*&~(.*z.,*)$,Iron Oxides (CI 77491, 77492),a{3,4}"
    
    In [1288]: regex.split(r'(?<![({][^,]*),(?![^,]*[})])', str_)
    Out[1288]: ['Water', '^.*f04.*&~(.*z.,*)$', 'Iron Oxides (CI 77491, 77492)', 'a{3,4}']
    

    限制:

    • [({] 匹配任何(/{,而[})] 匹配任何)/},因此这可能会导致错误,例如子字符串以( 开头并以} 结尾或相反

    • 不适用于嵌套括号/括号

    【讨论】:

      猜你喜欢
      • 2018-04-14
      • 1970-01-01
      • 2017-08-24
      • 1970-01-01
      • 2018-09-12
      • 1970-01-01
      • 1970-01-01
      • 2022-12-06
      • 2016-04-12
      相关资源
      最近更新 更多