1.正則表達式html
正則表達式:是字符串的規則,只是檢測字符串是否符合條件的規則而已 1.檢測某一段字符串是否符合規則 2.將符合規則的匹配出來
re模塊:是用來操做正則表達式的
2.正則表達式組成正則表達式
字符組:[] 一個字符組描述的是一個位置上的字符規則,可是不能從大到小來規定範圍,字符組內全部的範圍都是ascii來排序的,字符組更靈活一點 [0-9] 匹配一個數字範圍 [a-z] 匹配一個小寫字母 [A-Z] 匹配一個大寫字母 [A-Za-z0-9] 匹配英文字母和大小寫 左邊必須是ascii最小的 注意:遇到在字符組當中的'-'是有特殊意義的,若是想取消'-'的特殊意義,要轉義一下 例如:[1-2] 是匹配不是1就是2的數據,可是我想匹配1,-,2那?須要轉義一下[1\-2] 元字符:匹配的一個字符的內容 \d: 使用\d表示匹配任意從0-9的數字,使用字符組能匹配到一個固定的範圍,可是\d表示的時從0-9太固定 \w:匹配全部的數字字母下劃線,標識符 -t:匹配tab製表符 \n:匹配換行符 \s:匹配全部的空格換行製表符 \b:表示一個單詞的邊界,要匹配以XX結尾的單詞 反義詞: \W:除了數字字母下劃線的全部 \D:除了數字以外的全部 \S:除了空白以外的全部 .:匹配換行符以外的全部字符 非字符組:[^123] 除了123的都匹配 ‘^’必須和[]組合才叫非字符組
開始符'^' 結束符'$'
一個字符串只有一個開始和一個結束,^永遠在一個規則的最前面,$永遠在一個字符串的最末尾
^hello$ -->匹配一個hello,規定了這個字符串的長度,在字符串檢測的時候一般加上^和$符號
[^123] :匹配的是不以123開頭的
| 或的意思,豎槓的左邊或右邊是一個規則,永遠把相對長的規則放在左邊
分組:()--> www\.(baidu|oldboy)\.com
量詞:表示的是匹配的次數,在量詞的範圍內儘量的多的匹配,叫貪婪匹配
{n} 表示出現n次
{n,} 表示出至少出現n次
{n,m}表示存出現n-m次
?:匹配額0次或1次
+:匹配1次或屢次
*:匹配0次或屢次
?和+的範圍等於*的範圍
匹配電話號碼:^1[3-9]\d{9}$:
匹配整數:^[1-9]\d*|0&
匹配小數:\d+\.\d+
匹配整數或者小數:\d+(\.\d+)? -->裏面的()是分組的意思,?表示要不()裏面的一塊兒出現,不要就都不出現 \d+\.?\d*
匹配15位身份證號碼:^[1-9]\d{14}$
匹配18位身份證號碼:^[1-9]\d{16}[\dx]$
#轉義字符:在字符串外部加上一個r來不轉義
貪婪匹配:儘量的多匹配 a.*x 回溯算法
惰性匹配:儘量的少匹配 .*? ,兩個量詞同時出現時表示非貪婪 a.*?x 從a開始匹配,遇到一個x就中止
就是量詞後面加上?就是惰性匹配,匹配到第一個就中止
re模塊算法
import re s='kobe123jordan46' re.findall(pattern,string,flags=0) ret = re.findall('\d+',s) print() 查看全部,返回一個列表 注意:在正則條件不同的狀況下返回的內容不同 '\d+'是貪婪的匹配全部數字組成一個字符串
re.search(pattern,string,flags=0) ret =re.search('\d+',s)
print(ret)
print(ret.group())
返回一個結果對象或結果集
經過group()取值只取到第一個,若是沒有符合條件的group就會報錯,通常用if判斷一下是否爲空
re.match(pattern,string,flags=0)
ret = re.match('\s+',s)
print(ret)
返回一個結果對象或結果集
使用match的話,至關於在正則表達式前面加上^,在程序裏面匹配的是'^\s',是找以字符串開頭的,沒有的話就返回None
使用search徹底能夠代替match,只要在search的表達式前面加上^就能夠
re.search('^\s+','kobe123') == re.match('\s+','kobe123')
re.sub(pattern,repl,string,count=0)
ret = re.sub('\d+','sb',s,count=1)
print(ret)
count不寫的話默認替換全部,返回一個字符串
re.subn(pattern,repl,string,count=0)
ret = re.sun('\d+','sb',s)
print(ret)
默認返回一個元組,而且返回被替換了多少次
re.split(pattern,string,maxsplit=1)
ret = re.split('\d+',s,maxsplit=1)
print(ret)
默認返回一個列表,不加maxsplit就所有分割
re.compile(pattern)
par = re.compile('\d+')
ret = par.findall(s)
print(ret)
對於一個常常重複使用的正則表達式,咱們能夠先進行一次編譯,以後只要在使用這個表達式就直接拿出來使用
就行了,這樣作節省時間和及其資源,減小解析時間個轉成機器碼的時間
re.compile()是一個優化函數,提高執行效率減小沒必要要的時間和性能的開銷
re.finditer(pattern,string)
par = re.compile('\d+')
ret = par.finditer('kob123kobe123kobe123kobe123'*200)
for item in ret:
print(item.group())
返回的是一個生成器結果集,經過group方法取出每個數據
看到iter應該能想到是生成器原理,經過循環每次使生成器返回一個數據,這樣和使用生成器讀取大文件同樣,節省內存
可以提早編譯一個正則表達式,當同一個正則表達式被屢次使用時,能夠直接使用節省時間
分組
s= """
<h1>哇哈哈哈<h1>
<h2>哈哈哈哈<h2>
<title>科比</title>
"""ide
findall()和分組:分組在findall當中會默認的優先被顯示出來
ret = re.findall('>\w+<',r'<title>科比<\title>')
print(ret[0].strip('<>'))
分組在findall當中會默認的優先被顯示出來,若是不想優先顯示出來就在分組中添加(?:正則規則)表示取消這個正則的優先顯示
ret = re.findall('>\w+<',r'<title>科比<\title>')
print(ret[0].strip('<>'))函數
ret = re.findall('>(\w+)<',r'<title>科比<\title>')
print(ret) # findall永遠優先顯示分組中的內容性能
ret = re.findall('www\.(?:baidu|nba)\.com',r'www.baidu.com')
print(ret)優化
ret = re.findall('\d+(?:\.\d+)?',r'1.23+2.34')
print(ret)編碼
split()和分組:會保留被切掉的在分組中內容
ret = re.split('\d(\d)','alex84wusir73')
print(ret)spa
search()和分組:不受到分組的影響
ret = re.search(r'<(\w+)>(\w+)<\\(\w+)>',r'<title>科比<\title>')
print(ret.group(0)) # 不受到分組的影響
print(ret.group(1))
print(ret.group(2))code
分組命名
#分組命名就是把一個要匹配的東西取一個名字,在之後調用返回的時候回方便,直接使用名字就OK了
#若是有取值的有兩個相同的名字的話能夠複製爲(?P=a),必需要寫的分組裏面,否則的不能叫分組命名了
ret = re.search(r'<(?P<tab1>\w+)>(?P<content>\w+)<\\(\w+)>',r'<title>科比<\title>')
print(ret.group(0)) # 不受到分組的影響
print(ret.group('tab1')) # 不受到分組的影響
print(ret.group('content')) # 不受到分組的影響
特殊的需求:把這個字符串所有匹配出來<h1>wahaha</h2></h1>
par = '<\w+>.*?</\w+>'
ret = re.search('<(?P<tag>\w+)>.*</(?P=tag)>','<h1>wahaha</h2></h1></h3>')
print(ret.group())
par = '<\w+>.*?</\w+>'
ret = re.search(r'<(\w+)>.*</\1(是使用第幾個分組名字)>','<h1>wahaha</h2></h1></h3>')
print(ret.group())
當咱們要匹配的內容混在不想匹配的內容中
只能把不想要的也匹配出來,而後去掉不想要的就是想要的
下列我只想取整數部分
ret = re.findall('\d+\.\d+|(\d+)','1-2*(60+(-40.35/5)-(-4*3))') #取出來不包含40.35,可是包含"",由於findall遇到分組是優先匹配,因此匹配到小數就放棄,可是必須得返回一個元素,就返回""
ret = re.findall('\d+\.\d+|\d+','1-2*(60+(-40.35/5)-(-4*3))') #取出來的包含40.35
ret.remove('')
print(ret)
碰見分組
findall 優先顯示分組中的內容
split 保留被切掉的分組內的內容
search 能夠經過組的索引取值
取消分組的特殊行爲(?:正則)
常見的使用正則解決問題的方式#
1.把整個結構描述下來,對想要的進行分組#
2.把不想要的也匹配出來,而後用手段刪掉
1. 數字:^[0-9]*$ 2. n位的數字:^\d{n}$ 3. 至少n位的數字:^\d{n,}$ 4. m-n位的數字:^\d{m,n}$ 5. 零和非零開頭的數字:^(0|[1-9][0-9]*)$ 6. 非零開頭的最多帶兩位小數的數字:^([1-9][0-9]*)+(.[0-9]{1,2})?$ 7. 帶1-2位小數的正數或負數:^(\-)?\d+(\.\d{1,2})?$ 8. 正數、負數、和小數:^(\-|\+)?\d+(\.\d+)?$ 9. 有兩位小數的正實數:^[0-9]+(.[0-9]{2})?$ 10. 有1~3位小數的正實數:^[0-9]+(.[0-9]{1,3})?$ 11. 非零的正整數:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$ 12. 非零的負整數:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$ 13. 非負整數:^\d+$ 或 ^[1-9]\d*|0$ 14. 非正整數:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$ 15. 非負浮點數:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ 16. 非正浮點數:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ 17. 正浮點數:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$ 18. 負浮點數:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$ 19. 浮點數:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$ 2.校驗字符的表達式 1. 漢字:^[\u4e00-\u9fa5]{0,}$ 2. 英文和數字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$ 3. 長度爲3-20的全部字符:^.{3,20}$ 4. 由26個英文字母組成的字符串:^[A-Za-z]+$ 5. 由26個大寫英文字母組成的字符串:^[A-Z]+$ 6. 由26個小寫英文字母組成的字符串:^[a-z]+$ 7. 由數字和26個英文字母組成的字符串:^[A-Za-z0-9]+$ 8. 由數字、26個英文字母或者下劃線組成的字符串:^\w+$ 或 ^\w{3,20}$ 9. 中文、英文、數字包括下劃線:^[\u4E00-\u9FA5A-Za-z0-9_]+$ 10. 中文、英文、數字但不包括下劃線等符號:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$ 11. 能夠輸入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+ 12. 禁止輸入含有~的字符:[^~\x22]+ 3.特殊需求表達式 1. Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$ 2. 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.? 3. InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ 4. 手機號碼(可根據目前國內收集號擴展前兩位開頭號碼):^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$ 5. 電話號碼("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$ 6. 國內電話號碼(0511-440522二、021-87888822):\d{3}-\d{8}|\d{4}-\d{7} 7.15位身份證號:^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$ 8.18位身份證號:^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$ 9. 賬號是否合法(字母開頭,容許5-16字節,容許字母數字下劃線):^[a-zA-Z][a-zA-Z0-9_]{4,15}$ 10. 密碼(以字母開頭,長度在6~18之間,只能包含字母、數字和下劃線):^[a-zA-Z]\w{5,17}$ 11. 強密碼(必須包含大小寫字母和數字的組合,不能使用特殊字符,長度在8-10之間):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$ 12. 日期格式:^\d{4}-\d{1,2}-\d{1,2} 13. 一年的12個月(01~09和1~12):^(0?[1-9]|1[0-2])$ 14. 一個月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$ 15. 錢的輸入格式: (1)有四種錢的表示形式咱們能夠接受:"10000.00" 和 "10,000.00", 和沒有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$ (2)這表示任意一個不以0開頭的數字,可是,這也意味着一個字符"0"不經過,因此咱們採用下面的形式:^(0|[1-9][0-9]*)$ (3)一個0或者一個不以0開頭的數字.咱們還能夠容許開頭有一個負號:^(0|-?[1-9][0-9]*)$ (4)這表示一個0或者一個可能爲負的開頭不爲0的數字.讓用戶以0開頭好了.把負號的也去掉,由於錢總不能是負的吧.下面咱們要加的是說明可能的小數部分:^[0-9]+(.[0-9]+)?$ (5)必須說明的是,小數點後面至少應該有1位數,因此"10."是不經過的,可是 "10" 和 "10.2" 是經過的:^[0-9]+(.[0-9]{2})?$ (6)這樣咱們規定小數點後面必須有兩位,若是你認爲太苛刻了,能夠這樣:^[0-9]+(.[0-9]{1,2})?$ (7)這樣就容許用戶只寫一位小數.下面咱們該考慮數字中的逗號了,咱們能夠這樣:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$ (8)1到3個數字,後面跟着任意個 逗號+3個數字,逗號成爲可選,而不是必須:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$ 備註:這就是最終結果了,別忘了"+"能夠用"*"替代若是你以爲空字符串也能夠接受的話(奇怪,爲何?)最後,別忘了在用函數時去掉去掉那個反斜槓,通常的錯誤都在這裏 16. xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$ 17. 中文字符的正則表達式:[\u4e00-\u9fa5] 18. 雙字節字符:[^\x00-\xff] (包括漢字在內,能夠用來計算字符串的長度(一個雙字節字符長度計2,ASCII字符計1)) 19. 空白行的正則表達式:\n\s*\r (能夠用來刪除空白行) 20. HTML標記的正則表達式:<(\S*?)[^>]*>.*?</\1>|<.*? /> (網上流傳的版本太糟糕,上面這個也僅僅能部分,對於複雜的嵌套標記依舊無能爲力) 21. 首尾空白字符的正則表達式:^\s*|\s*$或(^\s*)|(\s*$) (能夠用來刪除行首行尾的空白字符(包括空格、製表符、換頁符等等),很是有用的表達式) 22. 騰訊QQ號:[1-9][0-9]{4,} (騰訊QQ號從10000開始) 23. 中國郵政編碼:[1-9]\d{5}(?!\d) (中國郵政編碼爲6位數字) 24. IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址時有用) 25. IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))
other re.S和re.M
Python 的re模塊內置函數幾乎都有一個flags參數,以位運算的方式將多個標誌位相加。其中有兩個模式:單行(re.DOTALL, 或者re.S)和多行(re.MULTILINE, 或者re.M)模式。 它們初看上去很差理解,可是有時又會很是有用。這兩個模式在PHP和JavaScripts裏都有。 單行模式 re.DOTALL 在單行模式裏,文本被強制看成單行來匹配,什麼樣的文本不會被看成單行?就是裏面包含有換行符的文(或者是網頁源碼),好比: This is the first line.\nThis is the second line.\nThis is the third line. 點號(.)能匹配全部字符,換行符例外。如今咱們但願能匹配出整個字符串,當用點號(.)匹配上面這個字符串時,在換行符的地方,匹配中止。 1.在打印的時候直接打印出三行 print (a) This is the first line. This is the second line. This is the third line. 2.在不使用re.S的時候會按行匹配 import re ret = re.findall('^This.*line',a) print(ret) 在上面的例子裏,即便是默認貪婪(greedy)的匹配,仍然在第一行的結尾初中止了匹配. 3.使用re.S的時候 import re ret = re.findall('^This.*line',a,re.S) print(ret) 而在單行模式下,換行符被看成普通字符,被點號(.)匹配. 多行模式 re.MULTILINE 在多行模式裏,文本被強制看成多行來匹配。正如上面單行模式裏說的,默認狀況下,一個包含換行符的字符串老是被看成多行處理。可是行首符^和行尾符$僅僅匹配整個字符串的起始和結尾。 這個時候,包含換行符的字符串又好像被看成一個單行處理。 在下面的例子裏,咱們但願能將三句話分別匹配出來。用re.findall( )顯示全部的匹配項 a = 'This is the first line.\nThis is the second line.\nThis is the third line.' 1.在打印的時候直接打印出三行 print (a) This is the first line. This is the second line. This is the third line. 2.在不使用re.S的時候會按行匹配 import re ret = re.findall('^This.*line$',a) print(ret) 默認點號不匹配換行符,因此匹配的爲空 3.使用re.S的時候 import re ret = re.findall('^This.*line',a,re.M) ret = re.findall('^This.*?line',a,re.M) print(ret) 匹配出了整句話,由於默認是貪婪模式 4.用問號切換成非貪婪模式: 仍然是整句話,這是由於^和$只匹配整個字符串的起始和結束。 在多行模式下,^除了匹配整個字符串的起始位置,還匹配換行符後面的位置;$除了匹配整個字符串的結束位置,還匹配換行符前面的位置. 總結:在單行模式下,點號(.)匹配全部的字符,因此能夠說,單行模式改變了點號(.)的匹配行爲,在多行模式下,多行模式改變了^和$的匹配行爲