用Python的re-modu匹配正则表达式组(带或)和特殊字符

2024-10-05 14:25:41 发布

您现在位置:Python中文网/ 问答频道 /正文

我试着把下面的标题这样的字符串分开,然后匹配名称和任何附加信息,要么放在括号/大括号中,要么放在破折号之后(常规的,m/n破折号,水平条)。在

regex对我来说似乎很好,我可以在其他regex测试仪上测试它,但是在使用Python运行时它就不起作用了。在

有一些奇怪的事情发生了。第一个虚线标题似乎匹配,但是addition_a组没有包含正确的字符串。此外,由于某些原因,任何特殊字符,如各种破折号根本不匹配。脚本的编码是utf-8,所以我假设原始regex字符串中的破折号应该可以正常工作,但是它们不是。在

# -*- coding: utf-8 -*-
import re
titles = [
    'Spaced (News)',
    'Angry Birds [Game]',
    'Cheats - for all games', # dash
    'Cheats – for all games', # ndash
    'Cheats — for all games', # mdash
    'Cheats ― for all games'  # horizontal bar
]
regex = re.compile(r'^(?P<name>.+)\s+(([-–—―]\s+(?P<addition_a>.+))|([\(\[](?P<addition_b>.+)[\)\]]))$')
for title in titles:
    data = {}
    match = regex.match(title.strip())
    if match:
        data['name'] = match.group('name')
        try:
            data['addition'] = match.group('addition_a')
        except IndexError:
            pass
        try:
            data['addition'] = match.group('addition_b')
        except IndexError:
            pass
    print data

输出:

^{pr2}$

Tags: 字符串namere标题fordatamatchgroup
3条回答

Unicode有占用超过一个字节的“字符”或“符号”,Python不太擅长理解这个概念,因此有时会出现一些问题。您可以执行以下操作之一:

您可以尝试确保正在解析的所有字符串都是unicode,如果您控制了这些字符串,则应该很简单—对于您的示例,只需在字符串的开头添加u指示符,如下所示:

u'Spaced (News)',
u'Angry Birds [Game]',
u'Cheats - for all games', # dash
u'Cheats – for all games', # ndash
u'Cheats — for all games', # mdash
u'Cheats ― for all games'  # horizontal bar

并将其添加到正则表达式中,如下所示:

^{pr2}$

否则,或者如果你不能控制,你可以做一个小的修改,虽然不是完全正确的-将工作。该更改是接受来自集合[-–—―]的多个字符,而不是通过执行[-–—―]+来接受单个字符:

r'^(?P<name>.+)\s+(([-–—―]+\s+(?P<addition_a>.+))|([\(\[](?P<addition_b>.+)[\)\]]))$'

这两个选项中的任何一个都会得到你想要的结果。在

第一个将产生unicode结果:

>>> 
{'addition': u'News', 'name': u'Spaced'}
{'addition': u'Game', 'name': u'Angry Birds'}
{'addition': None, 'name': u'Cheats'}
{'addition': None, 'name': u'Cheats'}
{'addition': None, 'name': u'Cheats'}
{'addition': None, 'name': u'Cheats'}

规则字符串中的第二个:

>>> 
{'addition': 'News', 'name': 'Spaced'}
{'addition': 'Game', 'name': 'Angry Birds'}
{'addition': None, 'name': 'Cheats'}
{'addition': None, 'name': 'Cheats'}
{'addition': None, 'name': 'Cheats'}
{'addition': None, 'name': 'Cheats'}

一个稍微“大锤锤式”的方法是将整个re改为“一些单词和空格,直到它不存在,然后剩下的”。这也避免了可选的additional_aadditional_b命名组和try/except逻辑。在

示例:

for title in titles:
    data = dict(zip(['name', 'addition'], (m.strip() for m in re.findall('([\w\s]+)', title))))
    print data

输出:

^{pr2}$

使用unicode文字。否则,[-–—―]匹配-\xe2\x80\x93\xe2\x80\x94\xe2\x80\x95,而不是{},

# -*- coding: utf-8 -*-
import re
titles = [
    u'Spaced (News)',
    u'Angry Birds [Game]',
    u'Cheats - for all games', # dash
    u'Cheats – for all games', # ndash
    u'Cheats — for all games', # mdash
    u'Cheats ― for all games'  # horizontal bar
]
regex = re.compile(ur'^(?P<name>.+)\s+(([-–—―]\s+(?P<addition_a>.+))|([\(\[](?P<addition_b>.+)[\)\]]))$')
for title in titles:
    match = regex.match(title.strip())
    if match:
        data = {}
        data['name'] = match.group('name')
        data['addition'] = match.group('addition_a') or match.group('addition_b')
        print data

输出:

^{pr2}$
>>> r'[–]'
'[\xe2\x80\x93]'
>>> re.findall(r'[–]', '–')
['\xe2', '\x80', '\x93']
>>> re.findall(ur'[–]', u'–')
[u'\u2013']
>>> print re.findall(ur'[–]', u'–')[0]
–

相关问题 更多 >