【python文法】Regex

來源:互聯網
上載者:User

標籤:串連   代碼   英文   輸入   尋找   post   特殊字元   用途   匹配   

為什麼要用Regex

對字串進行操作幾乎是每種程式設計語言中最重要的功能之一。很簡單就可以理解,因為人類進行資訊傳播主要靠的是文字,也就是字串,但是這麼多資訊並不完全是我們所要的,所以我們會通過編程來提取或者驗證字串的部分。

Regex就是用來匹配字串的工具,其實它定義了一套文法,用若干描述字元就可以匹配出某段字串的特徵來。凡是符合種描述規則的,我們就認為它匹配

所以比如我們要判斷一串字元是否為合法的Email地址的方法就是:

  • 建立一個符合Email特徵的Regex
  • 然後使用該Regex去匹配輸入的字串,以判斷是否合法。
Regex元字元

用\d可以匹配一個數字,\w可以匹配一個字母或數字

元字元 匹配
. 任一字元(但是不包括分行符號\n\r等
\w 字母 or 數字 or 底線
\s 空白符(包括Tab等)
\d 數字

舉個例子 ‘py.‘可以匹配‘pyc‘‘pyo‘‘py!‘等等。因為.表示的是任一字元,所以可以匹配正常的字母,也可以匹配!

注意一個元字元只代表一個字元,比如\w只代表一個字母或者數字。

可以用[]表示範圍,比如[0-9]表示匹配0~9之間的任意一個數字

  • [0-9a-zA-Z\_]可以匹配一個數字、字母或者底線,可以等價於\w

有時需要尋找不屬於某個能簡單定義的字元類的字元,這就是反義

代碼/文法 匹配
[^x] 除了x以外的任一字元
[^aeiou] 除了aeiou這幾個字母以外的任一字元
匹配變長的

如果好匹配變長的字元,用*表示0個或者以上的字元,用+表示1個或者以上的字元,用?表示0個或者1個字元。

還可以用大括弧來表示,用{n}表示n個字元,用{n,m}表示n-m個字元。

代碼/文法 說明
* 重複0次以上,等價於{0,}
+ 重複1次以上,等價於{1,}
? 重複0次或者1次,等價於{0,1}
{n} 重複n次
{n,} 重複n次以上
{n,m} 重複n到m次

所以比如\d{3}\s+\d{3,8}可以匹配哪些類型的字串呢?
從左至右讀一下:

  • \d{3}表示匹配3個數字,例如‘010‘;
  • \s可以匹配一個空格(也包括Tab等空白符),所以\s+表示至少有一個空格,例如匹配‘ ‘,‘ ‘等;
  • \d{3,8}表示3-8個數字,例如‘1234567‘。

如果要匹配‘010-12345‘這樣的號碼呢?由於‘-‘是特殊字元,在Regex中,要用‘‘轉義,所以,上面的正則是\d{3}-\d{3,8}。

  • [0-9a-zA-Z\_]+可以匹配至少由一個數字、字母或者底線組成的字串,比如‘a100‘‘0_Z‘‘Py3000‘等等;

  • [a-zA-Z\_][0-9a-zA-Z\_]*可以匹配由字母或底線開頭,後接任意個由一個數字、字母或者底線組成的字串,也就是Python合法的變數;

  • [a-zA-Z\_][0-9a-zA-Z\_]{0, 19}更精確地限制了變數的長度是1-20個字元(前面1個字元+後面最多19個字元)。

注意與萬用字元區分,linux的bash命令列中可以使用萬用字元,用*來代理任意個的字元。對於Regex而言,必須使用.*來表示任意個字元

那麼對之前電話號碼的那個例子,我們可以用更複雜的運算式來匹配\(?0\d{2}[) -]?\d{8}。\(?0\d{2}[) -]?\d{8}。,可以匹配(010)88886666,或022-22334455,或02912345678等。

  • 首先是一個逸出字元(,它能出現0次或1次(?),
  • 然後是一個0,後面跟著2個數字(\d{2}),
  • 然後是)或-或空格中的一個,它出現1次或不出現(?),
  • 最後是8個數字(\d{8}

但是這個運算式也能匹配010)12345678或(022-87654321這樣的“不正確”的格式。後面會說怎麼樣修改就可以解決這個問題。

邊界限定符
邊界限定 匹配
^ 字串的開始
$ 字串的結束

比如^\d{5,12}$表示以數字開頭,以數字結尾,整行匹配,同時間長度度在5~12位一串數字。

分支條件

所謂分支條件就類似邏輯中的“或”,滿足任意一個條件即匹配。具體方法是用|把不同的規則分隔開

比如之前講過的匹配電話號碼的例子。

  • 0\d{2}-\d{8}|0\d{3}-\d{7}這個運算式能匹配
    • 三位區號,8位本地號(如010-12345678),
    • 4位區號,7位本地號(0376-2233445)。
  • \(0\d{2}\)[- ]?\d{8}|0\d{2}[- ]?\d{8}:這個運算式被|分為兩個條件
    • 左邊的運算式:\(0\d{2}\)可以匹配(010),[- ]?表示之間的串連符可以為-,也可以用空格間隔,也可以沒有。
    • 右邊的運算式0\d{2}[- ]?\d{8}:表示區號不用小括弧括起來。

注意:匹配分枝條件時,將會從左至右地測試每個條件,如果滿足了某個分枝的話,就不會去再管其它的條件了。

分組

之前提到的是怎麼重複單個字元(直接在字元後面加上限定符就行了);
但如果想要重複多個字元又該怎麼辦?可以用小括弧來指定子運算式(也叫做分組),然後你就可以指定這個子運算式的重複次數了

比如(\d{1,3}\.){3}\d{1,3}可以按順序進行分析,

  • \d{1,3}匹配1到3位的數字,
  • (\d{1,3}.){3}匹配三位元字加上一個英文句號(這個整體也就是這個分組)重複3次,
  • 最後再加上一個一到三位的數字(\d{1,3})。
總結

相信突然一下出現這麼的符號大家一定是懵逼的。下面我們來總結一下{}[]()這幾種符號的用途。

  • {2,3}:需要與它前面的字元結合,比如a{2,3}表示a出現2~3次
  • []:有3層含義
    • [a-z]:表示一個範圍,也就是a~z之間的一個字元
    • [.*]:只要放入了[]裡面的.*都不表示之前的含義,只是單純作為一個普通的符號而已。比如這裡面就表示要麼為點號要麼為星號的符號。
    • [^a]:表示非a的所有字元。主要不要和^a混淆,^a表示以a開頭的一行。
貪婪匹配與懶惰匹配

a.*b來說 ,它將匹配最長的以a開始,以b結束的字串,比如用它來搜尋aabab的時候,會匹配整個字串aabab,這就是貪婪匹配,也就是儘可能多的匹配

那麼懶惰匹配指的就是儘可能少的匹配字元。在.*後面加上一個?以後,可以轉換為懶惰匹配模式,那麼.*?意味著使匹配成功的前提下使用最少的重複。比如把它應用於aabab,會匹配aab和ab

為什麼第一個匹配是aab而不是ab?因為Regex有一條規則:最先開始的匹配擁有最高的優先權

代碼/文法
*?
+?
??
{n,m}?
{n,}?
匹配漢字

匹配漢字的運算式為[\u4E00-\u9FA5],這是漢字的UTF-8編碼的範圍。

python調用Regex

Python提供re模組,包含所有Regex的功能。由於Python的字串本身也用\轉義,所以要特別注意:
比如python字串s = ‘ABC\\-001‘對應的Regex變成‘ABC\-001‘
所以最好把python字串上加上r首碼,就不用考慮轉義的問題,比如s = r‘ABC\-001‘ # Python的字串

如何判斷Regex是否匹配:

  • 引入re模組:import re
  • 使用match方法,如果匹配成功,返回一個Match對象,否則返回None
    test = ‘使用者輸入的字串‘

    if re.match(r‘Regex‘, test):print(‘ok‘)else:print(‘failed‘)
切分字串

使用Regex後,切分字元變得更靈活。

如下使用split 的正常切分代碼,可以看出無法識別連續的空格

>>> ‘a b   c‘.split(‘ ‘)[‘a‘, ‘b‘, ‘‘, ‘‘, ‘c‘]

使用Regex可以實現更複雜的切分:

>>> re.split(r‘[\s\,\;]+‘, ‘a,b;; c  d‘)[‘a‘, ‘b‘, ‘c‘, ‘d‘]
分組

除了判斷是否匹配之外,Regex可以提取子串的強大功能。用()表示的就是要提取的分組(Group)。
比如

m = re.match(r‘^(\d{3})-(\d{3,8})$‘, ‘010-12345‘)

這個Regex定義了兩個分組,可以匹配-前後的兩個運算式。

  • m.group(0):獲得的是‘010-12345‘
  • m.group(1):獲得是“010”
  • m.group(2):獲得是‘12345‘

group(0)永遠是原始字串,group(1)、group(2)……表示第1、2、……個子串。

貪婪匹配

Regex預設就是貪婪匹配的。比如

>>> re.match(r‘^(\d+)(0*)$‘, ‘102300‘).groups()#結果是(‘102300‘, ‘‘),\d+採用貪婪匹配,直接把後面的0全部匹配了,結果0*只能匹配Null 字元串了

必須讓\d+採用非貪婪匹配(也就是儘可能少匹配),才能把後面的0匹配出來,加個?就可以讓\d+採用非貪婪匹配:

>>> re.match(r‘^(\d+?)(0*)$‘, ‘102300‘).groups()(‘1023‘, ‘00‘)

再比如

import re line = "boooooobby123";reg_str = ".*(b.*b).*";match_obj = re.match (reg_str , line);if match_obj:    print (match_obj.group(1));

因為.*是貪婪匹配的,所以它會一直匹配到booooooboooooo,那麼小括弧裡面實際只匹配了bb

如果使用非貪婪模式,也就是在.*後面加一個?

import re line = "boooooobby123";reg_str = ".*?(b.*?b).*";match_obj = re.match (reg_str , line);if match_obj:    print (match_obj.group(1)); 

例子:提取日期

下面我們希望能自動化的把一段文字中的生日給提取出來,但是如果之前沒有規定格式的話,大家會隨心所欲的寫日期,比如

  • 出生於2018年1月23日
  • 出生於2018/1/23
  • 出生於2018-1-23
  • 出生於2018-01-23
  • 出生於2018-01
  • 出生於2018年01月

下面我們需要給一個Regex,要求他能匹配上面所有的日期格式。

  • 首先匹配日期中的年的部分,從上面的文本可以看出,只有2018年2018-
    2018/這幾種形式。也就是可以先用\d{4}表示數字,再用[年-\]來表示符號。湊起來就是

    regex = r"出生於(\d{4}[年/-])"
  • 再來看月份的數字部分只可能有011兩種形式:\d{1,2}
  • 月份後面的部分就相對比較複雜了。同樣的,我們可以進行分類列舉,然後使用分支條件即可統一表達。
    • 匹配2018年1月23日2018-01-23以及2018/1/23後面的部分:[月/-]\d{1,2}日?
    • 匹配2018年01月這種的後面的部分:[月/-]$
    • 匹配2018-01後面的部分,當然是直接用結尾符:$
    • 最後用()括起來,使用|進行分類討論。

      ([月/-]\d{1,2}日?|[月/-]$|$)

最後把所有的部分合并起來。

import re lines = [ "出生於2018年1月23日", "出生於2018/1/23", "出生於2018-1-23", "出生於2018-01-23", "出生於2018-01", "出生於2018年01月"]regex = r"出生於(\d{4}[年/-]\d{1,2}([月/-]\d{1,2}日?|[月/-]$|$))"for line in lines :    m = re.match(regex  , line )    if m :        print(m.group(1));

編譯

使用Regex時,re模組內部會幹兩件事情:

  • 編譯Regex,此時會進行文法分析,如果運算式本身不合法,會報錯;
  • 用編譯後的Regex去匹配字串。
    那麼如果一個Regex要使用非常多次,可以先行編譯該Regex

    # 編譯:>>> re_telephone = re.compile(r‘^(\d{3})-(\d{3,8})$‘)# 使用:>>> re_telephone.match(‘010-12345‘).groups()(‘010‘, ‘12345‘)
參考

廖雪峰-Regex
Regex30分鐘入門教程

【python文法】Regex

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.