代码之家  ›  专栏  ›  技术社区  ›  kender

如何用括号外的逗号拆分字符串?

  •  22
  • kender  · 技术社区  · 16 年前

    我有一个这样的格式字符串:

    "Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
    

    所以基本上,它是演员名字的列表(可选地在括号中后跟他们的角色)。角色本身可以包含逗号(演员的名字不能,我强烈希望如此)。

    我的目标是把这个字符串分成一组- (actor name, actor role) .

    一个明显的解决方案是检查每个字符,检查是否出现 '(' , ')' ',' 每当外部出现逗号时就将其拆分。但这似乎有点重…

    我在考虑使用regexp拆分它:首先用括号拆分字符串:

    import re
    x = "Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
    s = re.split(r'[()]', x) 
    # ['Wilbur Smith ', 'Billy, son of John', ', Eddie Murphy ', 'John', ', Elvis Presley, Jane Doe ', 'Jane Doe', '']
    

    这里的奇怪元素是演员名,甚至是角色。然后我可以用逗号拆分名称,并以某种方式提取名称-角色对。但这似乎比我的第一种方法更糟糕。

    用一个regexp或一段好的代码,有没有更容易/更好的方法来实现这一点?

    10 回复  |  直到 13 年前
        1
  •  19
  •   Laurence Gonsalves    16 年前

    一种方法是使用 findall 与一个regex,贪婪地匹配的东西,可以在分隔符之间。如:

    >>> s = "Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
    >>> r = re.compile(r'(?:[^,(]|\([^)]*\))+')
    >>> r.findall(s)
    ['Wilbur Smith (Billy, son of John)', ' Eddie Murphy (John)', ' Elvis Presley', ' Jane Doe (Jane Doe)']
    

    上面的regex匹配一个或多个:

    • 非逗号、非开放paren字符
    • 以开paren开头、包含0个或多个非闭paren,然后是闭paren的字符串

    这种方法的一个奇怪之处是,相邻的分隔符被视为单个分隔符。也就是说,您不会看到空字符串。这可能是一个bug或特性,具体取决于您的用例。

    还要注意,正则表达式是 适用于有可能嵌套的情况。因此,例如,这将不正确地拆分:

    "Wilbur Smith (son of John (Johnny, son of James), aka Billy), Eddie Murphy (John)"
    

    如果需要处理嵌套,最好的办法是将字符串分割成parens、commas和其他东西(本质上是标记化它——这一部分仍然可以用regex完成),然后遍历这些标记重新组合字段,在进行时跟踪嵌套级别(这个跟踪嵌套级别就是正则表达式不能自己执行)。

        2
  •  5
  •   Wogan    16 年前

    我认为最好的方法是使用Python的内置 csv 模块。

    因为只有csv模块 allows 一个字 quotechar ,您需要对输入进行替换以转换 () 像这样的 | " . 然后确保你使用了适当的方言,然后离开。

        3
  •  5
  •   Alan Moore Chris Ballance    16 年前
    s = re.split(r',\s*(?=[^)]*(?:\(|$))', x) 
    

    lookahead将所有内容匹配到下一个左括号或字符串末尾, 敌我识别 中间没有右括号。这样可以确保逗号不在一组括号内。

        4
  •  2
  •   jfs    16 年前

    对人类可读regex的尝试:

    import re
    
    regex = re.compile(r"""
        # name starts and ends on word boundary
        # no '(' or commas in the name
        (?P<name>\b[^(,]+\b)
        \s*
        # everything inside parentheses is a role
        (?:\(
          (?P<role>[^)]+)
        \))? # role is optional
        """, re.VERBOSE)
    
    s = ("Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley,"
         "Jane Doe (Jane Doe)")
    print re.findall(regex, s)
    

    输出:

    [('Wilbur Smith', 'Billy, son of John'), ('Eddie Murphy', 'John'), 
     ('Elvis Presley', ''), ('Jane Doe', 'Jane Doe')]
    
        5
  •  1
  •   Michał Niklas    16 年前

    我的答案不会使用regex。

    我认为简单的字符扫描器和状态“ in_actor_name “应该工作。记住然后陈述” iN-ActoTrm名称 “在此状态下以')'或逗号结尾。

    我的尝试:

    s = 'Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)'
    
    in_actor_name = 1
    role = ''
    name = ''
    for c in s:
        if c == ')' or (c == ',' and in_actor_name):
            in_actor_name = 1
            name = name.strip()
            if name:
                print "%s: %s" % (name, role)
            name = ''
            role = ''
        elif c == '(':
            in_actor_name = 0
        else:
            if in_actor_name:
                name += c
            else:
                role += c
    if name:
        print "%s: %s" % (name, role)
    

    输出:

    Wilbur Smith: Billy, son of John
    Eddie Murphy: John
    Elvis Presley: 
    Jane Doe: Jane Doe
    
        6
  •  1
  •   Don O'Donnell    16 年前

    以下是我过去在这种情况下使用的一种通用技术:

    使用 sub 功能 re 以函数作为替换参数的模块。该函数跟踪打开和关闭parens、括号和大括号,以及单引号和双引号,并且仅在这些带括号和带引号的子字符串之外执行替换。然后,您可以用另一个您确定不会出现在字符串中的字符(我使用ASCII/Unicode组分隔符:chr(29)代码)替换无括号/带引号的逗号,然后对该字符执行简单的string.split。代码如下:

    import re
    def srchrepl(srch, repl, string):
        """Replace non-bracketed/quoted occurrences of srch with repl in string"""
    
        resrchrepl = re.compile(r"""(?P<lbrkt>[([{])|(?P<quote>['"])|(?P<sep>["""
                                + srch + """])|(?P<rbrkt>[)\]}])""")
        return resrchrepl.sub(_subfact(repl), string)
    
    def _subfact(repl):
        """Replacement function factory for regex sub method in srchrepl."""
        level = 0
        qtflags = 0
        def subf(mo):
            nonlocal level, qtflags
            sepfound = mo.group('sep')
            if  sepfound:
                if level == 0 and qtflags == 0:
                    return repl
                else:
                    return mo.group(0)
            elif mo.group('lbrkt'):
                level += 1
                return mo.group(0)
            elif mo.group('quote') == "'":
                qtflags ^= 1            # toggle bit 1
                return "'"
            elif mo.group('quote') == '"':
                qtflags ^= 2            # toggle bit 2
                return '"'
            elif mo.group('rbrkt'):
                level -= 1
                return mo.group(0)
        return subf
    

    如果你没有 nonlocal 在您的Python版本中,只需将其更改为 global 并定义 level qtflags 在模块级别。

    使用方法如下:

    >>> GRPSEP = chr(29)
    >>> string = "Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
    >>> lst = srchrepl(',', GRPSEP, string).split(GRPSEP)
    >>> lst
    ['Wilbur Smith (Billy, son of John)', ' Eddie Murphy (John)', ' Elvis Presley', ' Jane Doe (Jane Doe)']
    
        7
  •  1
  •   Alessandro    13 年前

    这篇文章对我帮助很大。我想用引号外的逗号拆分字符串。我用这个做开胃菜。我的最后一行代码是 regEx = re.compile(r'(?:[^,"]|"[^"]*")+') 这就成功了。多谢。

        8
  •  0
  •   Anand Shah    16 年前

    我当然同意上面的@wogan,使用csv模型是一个很好的方法。已经说过,如果您仍然想尝试一个regex解决方案,请尝试一下,但是您必须使它适应Python方言。

    string.split(/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/)
    

    高温高压

        9
  •  0
  •   ghostdog74    16 年前

    分裂“”

    >>> s="Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
    >>> s.split(")")
    ['Wilbur Smith (Billy, son of John', ', Eddie Murphy (John', ', Elvis Presley, Jane Doe (Jane Doe', '']
    >>> for i in s.split(")"):
    ...   print i.split("(")
    ...
    ['Wilbur Smith ', 'Billy, son of John']
    [', Eddie Murphy ', 'John']
    [', Elvis Presley, Jane Doe ', 'Jane Doe']
    ['']
    

    您可以做进一步的检查以获取那些不随()一起提供的名称。

        10
  •  -1
  •   Tom Swirly    16 年前

    如果您的数据中有任何错误或噪音,上述答案都不正确。

    如果您知道每次数据都是正确的,那么很容易找到一个好的解决方案。但是如果有格式错误会发生什么呢?你想发生什么?

    假设有嵌套括号?假设有不匹配的括号?假设字符串以逗号结尾或以逗号开头,或者一行中有两个逗号?

    以上所有的解决方案都会产生或多或少的垃圾,并且不会向您报告。

    如果由我决定的话,我会从一个非常严格的限制开始,限制“正确”的数据是什么——没有嵌套的括号,没有不匹配的括号,在注释之前、之间或之后没有空段——在我进行验证时进行验证,如果我无法验证,则引发异常。

    推荐文章