【问题标题】:Python regex split into characters except if followed by parenthesesPython 正则表达式拆分为字符,除非后跟括号
【发布时间】:2016-07-27 18:30:01
【问题描述】:

我有一个类似"F(230,24)F[f(22)_(23);(2)%[+(45)FF]]" 的字符串,其中除了括号和它们所包含的内容之外的每个字符都代表一种指令。一个字符后面可以跟在可选括号中指定的可选参数列表。

这样的字符串我想把字符串拆分成 ['F(230,24)', 'F', '[', 'f(22)', '_(23)', ';(2)', '%', '[', '+(45)', 'F', 'F', ']', ']'],但目前我只得到['F(230,24)', 'F', '[', 'f(22)_(23);(2)', '%', '[', '+(45)', 'F', 'F', ']', ']'](子字符串未正确拆分)。

目前我正在使用list(filter(None, re.split(r'([A-Za-z\[\]\+\-\^\&\\\/%_;~](?!\())', string))),这只是一堆乱七八糟的字符和对( 的否定前瞻。 list(filter(None, <list>)) 用于从结果中删除空字符串。

我知道这很可能是由于 Python 的 re.split 被设计为不会在零长度匹配 as discussed here 上拆分造成的。 但是我想知道什么是一个好的解决方案?有没有比re.findall更好的办法?

谢谢。

编辑:不幸的是,我不允许使用像 regex module 这样的自定义包

【问题讨论】:

  • 你的正则表达式是什么?包括您这样做的原因也可能会有所帮助,因为可能有更简单的方法。
  • 抱歉完全忘记在行之间包含它!
  • 你可以只做re.findall(s, "([^()](\\([^)]+\\))?)")(将[^()]替换为你想要的所有字符)
  • 参数只是逗号分隔的数字吗?
  • 现在是的。但事实上它们将来也可能是字符串,所以我想我对findall 方法更满意。

标签: python regex string split


【解决方案1】:

您可以使用re.findall 找出所有单个字符,可选地后跟一对括号:

import re
s = "F(230,24)F[f(22)_(23);(2)%[+(45)FF]]"
re.findall("[^()](?:\([^()]*\))?", s)

['F(230,24)',
 'F',
 '[',
 'f(22)',
 '_(23)',
 ';(2)',
 '%',
 '[',
 '+(45)',
 'F',
 'F',
 ']',
 ']']
  • [^()] 匹配除括号外的单个字符;
  • (?:\([^()]*\))? 表示非捕获组(?:),由一对括号括起来,使用? 使该组可选;

【讨论】:

  • 这比通过拆分更优雅地解决了模式。谢谢! :)
  • 只是为了澄清:非捕获组用于分配?使该组可选,但不将其作为捕获组,以便在没有显式捕获组时返回整个匹配项?
  • 没错。这是必要的,因为? 只会将其前面的字符设为可选,如果我们想让模式可选,我们必须对其进行分组。
【解决方案2】:

我知道这很可能是由于 Python 的 re.split 被设计为不会在零长度匹配时拆分

您可以使用regex moduleVERSION1 标志。从您链接的线程中获取that example - 看看split() 如何也产生零宽度匹配:

>>> import regex as re
>>> re.split(r"\s+|\b", "Split along words, preserve punctuation!", flags=re.V1)
['', 'Split', 'along', 'words', ',', 'preserve', 'punctuation', '!']

【讨论】:

  • 不幸的是我不能使用自定义包。
【解决方案3】:

另一种解决方案。这次该模式识别具有 SYMBOL[(NUMBER[,NUMBER...])] 结构的字符串。如果字符串与正则表达式匹配,则函数parse_it 返回 True 和标记,如果不匹配则返回空False

import re
def parse_it(string):
    '''
    Input: String to parse
    Output: True|False, Tokens|empty_string
    '''
    pattern = re.compile('[A-Za-z\[\]\+\-\^\&\\\/%_;~](?:\(\d+(?:,\d+)*\))?')
    tokens = pattern.findall(string)
    if ''.join(tokens) == string:
        res = (True, tokens)
    else:
        res = (False, '')
    return res

good_string = 'F(230,24)F[f(22)_(23);(2)%[+(45)FF]]'
bad_string = 'F(2a30,24)F[f(22)_(23);(2)%[+(45)FF]]' # There is an 'a' in a bad place.

print(parse_it(good_string))
print(parse_it(bad_string))

输出:

(真, ['F(230,24)', 'F', '[', 'f(22)', '_(23)', ';(2)', '%', ' [', '+(45)', 'F', 'F', ']', ']'])
(False, '')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-12
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-22
    相关资源
    最近更新 更多