作為一個概念而言,正規表示式對於Python來說並不是獨有的。但是,Python中的正規表示式在實際使用過程中還是有一些細小的差異。
本文是一系列關於Python正規表示式文章的其中一部分。在這個系列的第一篇文章中,我們將重點放在如何使用Python中的正規表示式並突出Python中一些獨特的特性。
我們將介紹Python中對字串進行搜尋和尋找的一些方法。然後我們講討論如何使用分組來處理我們查找到的匹配對象的子項。
我們有興趣使用的Python中正規表示式的模組通常叫做‘re'。
>>> import re
1. Python中的原始型別字串
Python編譯器以‘'(反斜線)來表示字串常數中的轉義字元。
如果反斜線後面跟著一串編譯器能夠識別的特殊字符,那麼整個轉義序列將被替換成對應的特殊字符(例如,‘n'將被編譯器替換成換行符)。
但這給在Python中使用正規表示式帶來了一個問題,因為在‘re'模組中也使用反斜線來轉義正則表達式中的特殊字元(例如*和+)。
這兩種方式的混合意味著有時你必須轉義轉義字符本身(當特殊字符能同時被Python和正則表達式的編譯器識別的時候),但在其他時候你不必這麼做(如果特殊字元只能被Python編譯器辨識)。
與其將我們的心思放在去弄清楚到底需要多少個反斜杠,我們可以使用原始字串來替代。
原始類型字串可以簡單的透過在普通字串的雙引號前面加上一個字元‘r'來創建。當一個字串是原始類型時,Python編譯器不會對其嘗試做任何的替換。本質上來講,你在告訴編譯器完全不要去干涉你的字串。
>>> string = 'This is a\nnormal string' >>> rawString = r'and this is a\nraw string' >>> print string
這是一個普通字串
>>> print rawString and this is a\nraw string
這是一個原始型別。
在Python中使用正規表示式進行查找
‘re'模組提供了幾個方法對輸入的字串進行確切的查詢。我們將要討論的方法有:
•re.match() •re.search() •re.findall()
每一個方法都接收一個正規表示式和一個待找出符合的字串。讓我們更詳細的查看這每一個方法從而弄清楚他們是如何工作的以及他們各有什麼不同。
2. 使用re.match查找 – 匹配開始
讓我們先來看看match()方法。 match()方法的工作方式是只有當被搜尋字串的開頭匹配模式的時候它才能查找到匹配對象。
舉個例子,對字串‘dog cat dog'調用mathch()方法,查找模式‘dog'將會匹配:
>>> re.match(r'dog', 'dog cat dog') <_sre.SRE_Match object at 0xb743e720< >>> match = re.match(r'dog', 'dog cat dog') >>> match.group(0) 'dog'
我們稍後將更多的討論我們稍後將更多的討論我們稍後將更多的討論我們稍後將更多的討論。現在,我們只需要知道我們用0作為它的參數呼叫了它,group()方法傳回查找到的匹配的模式。
我還暫且略過了返回的SRE_Match對象,我們很快也會討論到它。
但是,如果我們對同一個字串呼叫math()方法,查找模式‘cat',則不會找到匹配。
>>> re.match(r'cat', 'dog cat dog') >>>
3. 使用re.search查找– 匹配任意位置
search()方法和match()類似,不過search()方法不會限制我們只從字符串的開頭匹配,因此在在我們的範例字串中查找'cat'會查找到一個符合:
search(r'cat', 'dog cat dog') >>> match.group(0) 'cat'
然而search()方法會在它查找到一個匹配項之後停止繼續查找,因此在我們的範例字串中用searc()方法找出'dog'只找到其首次出現的位置。
>>> match = re.search(r'dog', 'dog cat dog') >>> match.group(0) 'dog'
4. 使用 re.findall – 所有匹配對象
目前為止在Python中我使用的最多的查找方法是findall()方法。當我們呼叫findall()方法,我們可以非常簡單的得到一個所有匹配模式的列表,而不是得到match的物件(我們會在接下來更多的討論match物件)。對我而言這更加簡單。對範例字串呼叫findall()方法我們得到:
['dog', 'dog'] >>> re.findall(r'cat', 'dog cat dog') ['cat']
5. 使用match.start 和match.end 方法
那麼,先前search()和match()方法先前返回給我們的'match '物件”到底是什麼呢?
和只簡單的返回字串的匹配部分不同,search()和match()返回的“匹配對象”,實際上是一個關於匹配子串的包裝類。
先前你看到我可以透過呼叫group()方法來得到匹配的子字串,(我們將在下一個部分看到,事實上匹配對像在處理分組問題時非常有用),但是匹配對象還包含了更多關於匹配子字串的資訊。 group 透過數字分組
就像我之前提到的,匹配对象在处理分组时非常得心应手。
分组是对整个正则表达式的特定子串进行定位的能力。我们可以定义一个分组做为整个正则表达式的一部分,然后单独的对这部分对应匹配到的内容定位。
让我们来看一下它是怎么工作的:
>>> contactInfo = 'Doe, John: 555-1212'
我刚才创建的字符串类似一个从某人的地址本里取出来的一个片段。我们可以通过这样一个正则表达式来匹配这一行:
>>> re.search(r'\w+, \w+: \S+', contactInfo) <_sre.SRE_Match object at 0xb74e1ad8<
通过用圆括号来(字符‘('和‘)')包围正则表达式的特定部分,我们可以对内容进行分组然后对这些子组做单独处理。
>>> match = re.search(r'(\w+), (\w+): (\S+)', contactInfo)
这些分组可以通过用分组对象的group()方法得到。它们可以通过其在正则表达式中从左到右出现的数字顺序来定位(从1开始):
>>> match.group(1) 'Doe' >>> match.group(2) 'John' >>> match.group(3) '555-1212'
组的序数从1开始的原因是因为第0个组被预留来存放所有匹配对象(我们在之前学习match()方法和search()方法到时候看到过)。
>>> match.group(0) 'Doe, John: 555-1212'
7. 使用 match.group 通过别名来分组
有时候,特别是当一个正则表达式有很多分组的时候,通过组的出现次序来定位就会变的不现实。Python还允许你通过下面的语句来指定一个组名:
>>> match = re.search(r'(?P<last>\w+), (?P<first>\w+): (?P<phone>\S+)', contactInfo)
我们还是可以用group()方法获取分组的内容,但这时候我们要用我们所指定的组名而不是之前所使用的组的所在位数。
>>> match.group('last') 'Doe' >>> match.group('first') 'John' >>> match.group('phone') '555-1212'
这大大加强了代码的明确性和可读性。你可以想像当正则表达式变得越来越复杂,去弄懂一个分组到捕获了什么内容将会变得越来越困难。给你的分组命名将明确的告诉了你和你的读者你的意图。
尽管findall()方法不返回分组对象,它也可以使用分组。类似的,findall()方法将返回一个元组的集合,其中每个元组中的第N个元素对应了正则表达式中的第N个分组。
>>> re.findall(r'(\w+), (\w+): (\S+)', contactInfo) [('Doe', 'John', '555-1212')]
但是,给分组命名并不适用于findall()方法。
在本文中我们介绍了Python中使用正则表达式的一些基础。我们学习了原始字符串类型(还有它能帮你解决的在使用正则表达式中一些头痛的问题)。我们还学习了如何适使用match(), search(), and findall()方法进行基本的查询,以及如何使用分组来处理匹配对象的子组件。
和往常一样,如果想查看更多关于这个主题的内容,re模块的Python官方文档是一个非常好的资源。
在以后的文章中,我们将更深入的讨论Python中正则表达式的应用。我们将更加全面的学习匹配对象,学习如何使用它们在字符串中做替换,甚至使用它们从文本文件中去解析Python数据结构。