【问题标题】:How to properly split this list of strings?如何正确拆分此字符串列表?
【发布时间】:2017-07-08 22:04:22
【问题描述】:

我有一个这样的字符串列表:

['z+2-44', '4+55+z+88']

如何在列表中拆分这些字符串,使其类似于

[['z','+','2','-','44'],['4','+','55','+','z','+','88']]

我已经尝试过使用split 方法,但是它将 44 分成 4 和 4,我不确定还有什么可以尝试的。

【问题讨论】:

  • 我猜规范不完整。数学运算符 * 和 / 呢?那么变量 a、b 和 c 呢? pi 是常数、变量还是 p*i?给出的问题将吸引可能对您的所有案例都没有帮助的答案。
  • @martineau 我相信this 的问题不是正确的重复。
  • @Kasramvd:我很想知道你为什么这么认为。
  • @martineau 因为回答这个问题不一定需要了解正则表达式。此外,它也不仅仅是关于字符串处理,它是一个包含字符串的列表。正如您在我的回答中看到的那样。我还提到了正则表达式的正确用法。
  • @Kasramvd:虽然不使用正则表达式当然可以解决问题,但这确实是一种糟糕的方法(如果不使用正则表达式,可能是不学习如何使用正则表达式的借口已经知道了)。但是,如果您强烈认为被标记为重复的问题是错误的,请随时自行重新打开它(或至少投票重新打开它)。

标签: python regex string list split


【解决方案1】:

你可以使用正则表达式:

import re
lst = ['z+2-44', '4+55+z+88']
[re.findall('\w+|\W+', s) for s in lst]
# [['z', '+', '2', '-', '44'], ['4', '+', '55', '+', 'z', '+', '88']]

\w+|\W+ 匹配由单词字符(在您的情况下为字母数字值)或非单词字符(在您的情况下为+- 符号)组成的模式。

【讨论】:

    【解决方案2】:

    这会起作用,使用itertools.groupby

    z = ['z+2-44', '4+55+z+88']
    
    print([["".join(x) for k,x in itertools.groupby(i,str.isalnum)] for i in z])
    

    输出:

    [['z', '+', '2', '-', '44'], ['4', '+', '55', '+', 'z', '+', '88']]
    

    如果字符是字母数字(或不是),它只会对字符进行分组,只需将它们重新加入列表理解中。

    编辑:带括号的计算器的一般情况已作为后续问题here 提出。如果z如下:

    z = ['z+2-44', '4+55+((z+88))']
    

    然后我们得到前面的分组:

    [['z', '+', '2', '-', '44'], ['4', '+', '55', '+((', 'z', '+', '88', '))']]
    

    这在令牌方面不容易解析。因此,只有在 alphanum 时才更改为 join,如果不是,则作为列表,最后使用 chain.from_iterable 变平:

    print([list(itertools.chain.from_iterable(["".join(x)] if k else x for k,x in itertools.groupby(i,str.isalnum))) for i in z])
    

    产生:

    [['z', '+', '2', '-', '44'], ['4', '+', '55', '+', '(', '(', 'z', '+', '88', ')', ')']]
    

    (请注意,备用正则表达式答案也可以这样调整:[re.findall('\w+|\W', s) for s in lst](注意在W 之后缺少+

    "".join(list(x)) 也比 "".join(x) 稍快,但我会让你把它加起来以避免改变已经很复杂的表达式的可见性。

    【讨论】:

    • 你打败了我 3 秒 :P
    • 在我看来,你不是个输不起的人 :) 感谢您的编辑
    【解决方案3】:

    使用re.split函数的替代解决方案:

    l = ['z+2-44', '4+55+z+88']
    print([list(filter(None, re.split(r'(\w+)', i))) for i in l])
    

    输出:

    [['z', '+', '2', '-', '44'], ['4', '+', '55', '+', 'z', '+', '88']]
    

    【讨论】:

      【解决方案4】:

      您只能在列表理解中使用 str.replace()str.split() 内置函数:

      In [34]: lst = ['z+2-44', '4+55+z+88']
      
      In [35]: [s.replace('+', ' + ').replace('-', ' - ').split() for s in lst]
      Out[35]: [['z', '+', '2', '-', '44'], ['4', '+', '55', '+', 'z', '+', '88']]
      

      但请注意,对于较长的字符串,这不是一种有效的方法。在这种情况下,最好的方法是使用正则表达式。

      作为另一种pythonic方式,您也可以使用tokenize模块:

      In [56]: from io import StringIO
      
      In [57]: import tokenize
      
      In [59]: [[t.string for t in tokenize.generate_tokens(StringIO(i).readline)][:-1] for i in lst]
      Out[59]: [['z', '+', '2', '-', '44'], ['4', '+', '55', '+', 'z', '+', '88']]
      

      tokenize 模块为 Python 源代码提供了一个词法扫描器,用 Python 实现。此模块中的扫描仪也将 cmets 作为令牌返回,使其可用于实现“漂亮的打印机”,包括用于屏幕显示的着色器。

      【讨论】:

        【解决方案5】:

        如果你想坚持使用split(因此避免使用正则表达式),你可以为它提供一个可选字符来分割:

        >>> testing = 'z+2-44'
        >>> testing.split('+')
        ['z', '2-44']
        >>> testing.split('-')
        ['z+2', '44']
        

        因此,您可以通过链接拆分命令来制造一些东西。

        不过,使用正则表达式可能更易读:

        import re
        
        >>> re.split('\+|\-', testing)
        ['z', '2', '44']
        

        这只是说“在任何 + 或 - 字符处拆分字符串”(反斜杠是转义字符,因为它们在正则表达式中都有特殊含义。

        最后,在这种特殊情况下,我认为目标是“在每个非字母数字字符处拆分”,在这种情况下,正则表达式仍然可以节省时间:

        >>> re.split('[^a-zA-Z0-9]', testing)
        ['z', '2', '44']
        

        当然值得注意的是,还有一百万种其他解决方案,正如其他一些 SO 讨论中所讨论的那样。

        Python: Split string with multiple delimiters

        Split Strings with Multiple Delimiters?

        为了纪念 Donald Knuth,我在这里的答案是针对简单易读的代码而不是性能。

        【讨论】:

        • Asker 希望这些标志也出现在结果列表中。不仅仅是 z 2 44。
        • 啊,是的,应该更好地阅读这个问题。我会更新答案,但我看到它已经得到了回答。继续!
        猜你喜欢
        • 2017-09-22
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        • 2012-10-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多