re.search未返回(貌似)正确的正则表达式的匹配项

时间:2018-10-31 10:36:23

标签: python regex python-3.x

我正在尝试运行简单的正则表达式匹配以提取dms坐标的一部分。

正则表达式看起来足够牢固,将以下内容复制到regexr时,我得到一个匹配项:

regex: ^([0-9]{1,2})[:|°| ]([0-9]{1,2})[:|'|′| ]?([0-9]{1,4}(?:\.[0-9]+){0,1})?[\"|″| ]([N|S])$
body: 51°30'30.7080"N

在我的python脚本中,我必须遵循以下条件:

# coding: utf8
import re
dms_regex = "^([0-9]{1,2})[:|°| ]([0-9]{1,2})[:|'|′| ]?([0-9]{1,4}(?:\.[0-9]+){0,1})?[\"|″| ]([N|S])$"

def dmsToCoordinates(dms_lat):
    print(dms_lat)
    matches = re.search(dms_regex, dms_lat)
    print(matches)

dmsToCoordinates("51°30'30.7080\"N")

我的终端输出是:

51°30'30.7080"N
None

很明显,我希望能找到一场比赛。请让我知道我在做错什么,然后再将自己扔出窗外。

1 个答案:

答案 0 :(得分:3)

事实证明(大多数情况下是偶然的),关于该问题的评论是:您错误地使用了错误的(旧)python版本。

python 2的主要问题之一(如果不是 the 主要问题)是如何彻底破坏字符串的处理方式。 str类型是一个字节串,对于Unicode文本具有单独的Unicode类型。这样将什么是文本和什么数据融合在一起。

因此,当您输入非ASCII字符(例如度数符号)并在python 2中运行代码时,会发生以下情况:

>>> '°'
'\xc2\xb0'
>>> len('°')
2
>>> '°'.decode('utf8')
u'\xb0'
>>> len('°'.decode('utf8'))
1

'°'(字节)字符串文字变为两个字节作为数据,但仍然伪装成字符串!如果对它进行编码并以unicode字符串结尾,那么它只是一个正确的单字符字符串。因此,当您将其放入字符类中时:

>>> 'f[°]oo'
'f[\xc2\xb0]oo'

这两个字节将像字符类中的两个字符一样工作,一个'\xc2',另一个'\xb0'。这意味着它将与目标字符串中插入的'\xc2\xb0'字节而不是另一个文字度数符号不匹配:

>>> re.search('f[°]oo', 'f°oo') is None
True
>>> re.search('f[\xc2\xb0]oo', 'f\xc2\xb0oo') is None # exact same thing as previous
True
>>> re.search('f[\xc2\xb0]oo', 'f\xc2oo') is None
False

因此,您意外使用python 2会导致正则表达式在非ascii字符上中断,这主要是由于python 2中的字符串是如何中断的。如果有人在python 2中使用代码,他们至少会在模式和目标中都切换到u'' Unicode文字,这将神奇地解决该问题。

以及有关您的正则表达式的两个一般说明:

  1. 您应该从角色类中删除所有这些管道。字符类的意思是“使用这个字符包中的一个字符”,这意味着

    (a)不需要管道来强制在字符类中的字符之间进行选择,并且

    (b)它将匹配目标中的实际管道:re.search('[a|b]','|') is not None

  2. 您应该使用 raw 字符串文字表示正则表达式,否则您有时会不得不在转义序列中转义反斜杠以获取正确的匹配并防止歧义。

所以我建议使用这种模式:

dms_regex = r"^([0-9]{1,2})[:° ]([0-9]{1,2})[:'′ ]?([0-9]{1,4}(?:\.[0-9]+){0,1})?[\"″ ]([NS])$"