geekdoc-python-zh/docs/pythoncentral/more-about-python-regular-e...

4.0 KiB
Raw Permalink Blame History

关于 Python 正则表达式的更多信息

原文:https://www.pythoncentral.io/more-about-python-regular-expressions/

在本系列的第一部分中,我们看了正则表达式的基本语法和一些简单的例子。在这一部分中,我们将了解一些更高级的语法和 Python 必须提供的一些其他特性。

正则表达式捕获组

到目前为止,我们已经使用正则表达式在一个字符串中进行了搜索,并使用返回的MatchObject来提取匹配的整个子字符串。现在我们来看看如何从匹配的子字符串中提取部分。

这个正则表达式:


\d{2}-\d{2}-\d{4}

将匹配以下格式的日期:

  • 两位数的日期。
  • 一个连字符。
  • 两位数的月份。
  • 一个连字符。
  • 四位数的年份。

例如:


>>> s = 'Today is 31-05-2012'

>>> mo = re.search(r'\d{2}-\d{2}-\d{4}', s)

>>> print(mo.group())

31-05-2012

我们可以通过将这个正则表达式的各个部分放在括号中来捕获:


(\d{2})-(\d{2})-(\d{4})

如果 Python 匹配这个正则表达式,我们就可以分别检索每个捕获的组


>>> mo = re.search(r'(\d{2})-(\d{2})-(\d{4})', s)

>>> # Note: The entire matched string is still available

>>> print(mo.group())

31-05-2012

>>> # The first captured group is the date

>>> print(mo.group(1))

31

>>> # And this is its start/end position in the string

>>> print('%s %s' % (mo.start(1), mo.end(1)))

9 11

>>> # The second captured group is the month

>>> print(mo.group(2))

05

>>> # The third captured group is the year

>>> print(mo.group(3))

2012

当您开始编写更复杂的正则表达式时,使用有意义的名称而不是数字来引用它们会很有用。语法是(...),其中...是要捕获的正则表达式name 是要为组指定的名称。


>>> s = "Joe's ID: abc123"

>>> # A normal captured group

>>> mo = re.search(r'ID: (.+)', s)

>>> print(mo.group(1))

abc123

>>> # A named captured group

>>> mo = re.search(r'ID: (?P<id>.+)', s)

>>> print(mo.group('id'))

abc123

使用正则表达式重用捕获的组

我们还可以获取捕获的组,稍后在正则表达式中重用它们!(?P=name)表示匹配之前在命名组中匹配的任何内容。比如:


>>> s = 'abc 123 def 456 def 789'

>>> mo = re.search(r'(?P<foo>def) \d+', s)

>>> print(mo.group())

def 456

>>> print(mo.group('foo'))

def

>>> # Capture 'def' in a group

>>> mo = re.search(r'(?P<foo>def) \d+ (?P=foo)', s)

>>> print(mo.group())

def 456 def

>>> mo.group('foo')

def

Python 正则表达式断言

有时我们想匹配的东西只有后面有其他东西,这意味着 Python 在搜索字符串时需要提前查看。这被称为前瞻断言,语法为(?=...),其中...是需要跟随的内容的正则表达式。

在下面的例子中,正则表达式ham(?= and eggs)意味着匹配‘火腿’,但前提是它后面跟有‘和鸡蛋’


>>> s = 'John likes ham and eggs.'

>>> mo = re.search(r'ham(?= and eggs)', s)

>>> print(mo.group())

ham

注意匹配的子串只有火腿,没有火腿鸡蛋和鸡蛋部分只是对火腿部分进行匹配的要求。让我们看看如果不满足这个要求会发生什么。


>>> s = 'John likes ham and mushrooms.'

>>> mo = re.search(r'ham(?= and eggs)', s)

>>> print(mo)

None


>>> s = 'John likes ham, eggs and mushrooms.'

>>> mo = re.search(r'ham(?= and eggs)', s)

>>> print(mo)

None

可惜 Python 只做简单的字符匹配,只会匹配字符串火腿,只要后面跟和鸡蛋。人工智能和语义分析是另外一篇文章。🙂

我们还可以做否定前瞻断言,也就是说,一个元素只有在而不是后跟其他东西时才匹配。


>>> s = 'My name is John Doe.'

>>> # Syntax is (?!...)

>>> mo = re.search( r'John(?! Doe)', s)

>>> print(mo)

None


>>> s = 'My name is John Jones.'

>>> mo = re.search(r'John(?! Doe)', s)

>>> print(mo.group())

John