可以使re.finditer()从组中排除定界符吗?

时间:2019-11-10 17:50:00

标签: python regex parsing

我的任务是将“源”文本转换为一系列元素:TEXTINPUTINPUT是包裹在两个星号中的那些部分,而TEXT是其他所有内容。

这里是一个例子:

>>> source = 'I came *across* these old photos when I *was* tidying the closet.'
>>> parse(source)
TEXT: 'I came '
INPUT: 'across'
TEXT: ' these old photos when I '
INPUT: 'was'
TEXT: ' tidying the closet.'

这种分析的目的是创建一个“填空”交互式工具来进行语言培训。解析的元素最终将进入客户端,其中TEXT元素按“原样”显示,而INPUT元素则作为输入字段显示,供用户键入。

为此,我对re库文档的Writing a Tokenizer部分中给出的示例进行了一些修改。这是我的解决方案:

def parse(text):
    token_specifications = [
        ('INPUT', r'(\*\w\*)|(\*\w+[^*]*\w+\*)'),
        ('TEXT', r'[^*]+'),
    ]
    token_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specifications)
    elements = []
    for mo in re.finditer(token_regex, text):
        kind = mo.lastgroup
        value = mo.group()
        # A hack to remove the delimiters
        if kind == 'INPUT':
            value = value.replace('*', '')
        print("%s: '%s'" % (kind, value))
        elements.append((kind, value))
    # Testing the result
    if elements != [
        ('INPUT', 'This'),
        ('TEXT', ' is '),
        ('INPUT', 'a'),
        ('TEXT', ' text that '),
        ('INPUT', 'needs to be'),
        ('TEXT', ' parsed. '),
        ('INPUT', 'Highlighted'),
        ('TEXT', ' elements must be in '),
        ('INPUT', 'INPUT'),
        ('TEXT', ' group.'),
    ]:
        raise Exception("Parsing result is wrong!")

text = '*This* is *a* text that *needs to be* parsed. *Highlighted* elements must be in *INPUT* group.'
parse(text)

除了一个小问题,它可以按预期工作,并且看起来很整洁。即,INPUT元素与星号一起出现,我必须明确地将其删除(请参阅代码的A hack to remove the delimiters部分)。

是否有一种方法可以使finditer()函数丢掉定界符,所以我不必显式地这样做吗?

此外,如果还有其他使我的代码更优雅的提示,那么它们将非常受欢迎。

1 个答案:

答案 0 :(得分:1)

您可以简化REGEXcode

text = '*This* is *a* text that *needs to be* parsed. *Highlighted* elements must be in *INPUT* group.'
elements = []
token_specifications = [
    ('INPUT', r'\*(?P<{}>\w+(?:[^*]\w+)*)\*'),
    ('TEXT', r'(?P<{}>[^*]+)'),
    ]
token_regex = '|'.join(exp.format(k) for k, exp in token_specifications)
# for match in re.finditer(r'\*(?P<INPUT>[^*]+)\*|(?P<TEXT>[^*]+)', text):
for match in re.finditer(token_regex, text):
    kind = match.lastgroup
    value = match.group(kind)
    elements.append((kind, value))

print(elements)
# [('INPUT', 'This'), ('TEXT', ' is '), ('INPUT', 'a'), ('TEXT', ' text that '), ('INPUT', 'needs to be'),
# ('TEXT', ' parsed. '), ('INPUT', 'Highlighted'), ('TEXT', ' elements must be in '), ('INPUT', 'INPUT'), ('TEXT', ' group.')]

我将您的INPUT这样的\*(\w+(?:[^*]*\w+)*)\*正则表达式与一个不包含*的捕获组结合在一起。并按如下名称获取捕获的组:match.group('NAME_OF_GROUP')