【问题标题】:Splitting on spaces, except between certain characters在空格上拆分,某些字符之间除外
【发布时间】:2012-03-27 12:53:26
【问题描述】:

我正在解析一个包含如下行的文件

类型(“书”)标题(“金苹果”)页数(10-35 70 200-234)cmets(“好读”)

我想将其拆分为单独的字段。

在我的示例中,有四个字段:类型、标题、页面和 cmets。

拆分后想要的结果是

['type("book")', 'title("golden apples")', 'pages(10-35 70 200-234)', 'cmets("good read")]

很明显,简单的字符串拆分是行不通的,因为它只会在每个空格处拆分。 我想分割空格,但保留括号和引号之间的任何内容。

如何拆分?

【问题讨论】:

    标签: python string-parsing


    【解决方案1】:

    让我添加一个非正则表达式的解决方案:

    line = 'type("book") title("golden apples") pages(10-35 70 200-234) comments("good read")'
    
    count = 0 # Bracket counter
    last_break = 0 # Index of the last break
    parts = []
    for j,char in enumerate(line):
        if char is '(': count += 1
        elif char is ')': count -= 1
        elif char is ' ' and count is 0:
            parts.append(line[last_break:(j)])
            last_break = j+1
    parts.append(line[last_break:]) # Add last element
    parts = tuple(p for p in parts if p) # Convert to tuple and remove empty
    
    for p in parts:
        print(p)
    

    一般情况下,您 cannot do with regular expressions 会处理某些事情,并且可能会导致严重的性能损失(尤其是前瞻和后视),这可能导致它们不是特定问题的最佳解决方案。

    还有;我想我会提到可用于创建自定义文本解析器的 pyparsing 模块。

    【讨论】:

    • 我最初提出这个问题已有 8 年了,但我同意,使用解析器比正则表达式更好,尤其是在括号和引号匹配等方面。
    【解决方案2】:

    拆分") " 并将) 添加回除最后一个元素之外的每个元素。

    【讨论】:

      【解决方案3】:

      我会尝试使用积极的后视断言。

      r'(?<=\))\s+'
      

      例子:

      >>> import re
      >>> result = re.split(r'(?<=\))\s+', 'type("book") title("golden apples") pages(10-35 70 200-234) comments("good read")')
      >>> result
      ['type("book")', 'title("golden apples")', 'pages(10-35 70 200-234)', 'comments(
      "good read")']
      

      【讨论】:

      • 如果test test test等输入文本中没有括号将不起作用。
      • 问题已经定义了格式。测试测试测试是不可能的。
      【解决方案4】:

      这个正则表达式应该适合你\s+(?=[^()]*(?:\(|$))

      result = re.split(r"\s+(?=[^()]*(?:\(|$))", subject)
      

      解释

      r"""
      \s             # Match a single character that is a “whitespace character” (spaces, tabs, and line breaks)
         +              # Between one and unlimited times, as many times as possible, giving back as needed (greedy)
      (?=            # Assert that the regex below can be matched, starting at this position (positive lookahead)
         [^()]          # Match a single character NOT present in the list “()”
            *              # Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
         (?:              # Match the regular expression below
                           # Match either the regular expression below (attempting the next alternative only if this one fails)
               \(             # Match the character “(” literally
            |              # Or match regular expression number 2 below (the entire group fails if this one fails to match)
               $              # Assert position at the end of a line (at the end of the string or before a line break character)
         )
      )
      """
      

      【讨论】:

      • 很好,虽然它似乎在返回的列表中添加了一些额外的括号(我不确定它们来自哪里)。我正在使用 py3。
      • 试试这个:re.split(r"\s+(?=[^()]*(?:\(|$))", subject)
      • @Keikoku 修复了它。这是因为捕获组。
      • 如何扩展它以支持圆 () 和方 [] 括号? IE。忽略任何(匹配良好的)这样的括号对之间的所有字符串?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-29
      • 1970-01-01
      • 1970-01-01
      • 2015-11-09
      • 1970-01-01
      • 2015-11-26
      相关资源
      最近更新 更多