ip地址是用3個'.'號作為分隔符,分割4個數字,每個數字的取值在[0,255],一般日志文件中的ip地址都是有效的ip地址,不需要我們再去驗證,因此,若從日志文件中提取ip,那么可以簡單寫成這樣:
- >>> import re
- >>> s='kkk 192.168.1.136 kkk 192.168.1.137 kk 192.168.1.138 kk'
- >>> l=re.findall(r'\d+.\d+.\d+.\d+', s)
- >>> print l
- ['192.168.1.136', '192.168.1.137', '192.168.1.138']
如果s中的ip地址有可能是無效的,那我們就需要在匹配的過程中,增加判斷是否有效的操作,
正確的ip地址是以'.'作為分隔符,如果以','或者其他的字符作為分隔符是不對的,因此我們需要對分隔符進行驗證:
- >>> s='kkk 192,168,1,136 kkk 192.168.1.137 kk 192.168.1.138 kk' #第一個ip地址以','作為分隔符,這是無效的ip地址
- >>> l=re.findall(r'\d+.\d+.\d+.\d+', s)# '.'能夠匹配除了'\n'之外的任意一個字符(因此'.'可以匹配上',')
- >>> print l
- ['192,168,1,136', '192.168.1.137', '192.168.1.138'] #顯然,第一個ip地址無效
- >>> l=re.findall(r'\d+\.\d+\.\d+\.\d+',s) # '\.'可以精確的匹配'.'
- >>> print l
- ['192.168.1.137', '192.168.1.138']
ip地址中每個數字的取值在[0,255],因此需要驗證每個數字的取值對否有效:
- >>> s='kkk 192.168.1.336 kkk 192.168.1.137 kk 192.168.1.138 kk'
- >>> l=re.findall(r'\d+\.\d+\.\d+\.\d+',s) #並沒有驗證每個數字的大小,導致第一個錯誤的ip地址也匹配上了
- >>> print l
- ['192.168.1.336', '192.168.1.137', '192.168.1.138'] #第一個ip地址是無效的,但錯誤的匹配上了
下面的匹配方法可以驗證數字的大小:
- >>> s='kkk 192.288.1.136 kkk 192.168.1.137 kk 192.168.1.138 kk'
- >>> l=re.findall(r'(?:25[0-5]\.|2[0-4]\d\.|[01]?\d\d?\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)',s)
- >>> print l
- ['192.168.1.137', '192.168.1.138']
- #或者這樣:
- >>> l=re.findall(r'(?:(?:25[0-5]|2[0-4]\d|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)',s)
- >>> print l
- ['192.168.1.137', '192.168.1.138']
但是上述匹配在下面的情況下依然會出錯:(ip地址中超出范圍的數字是該ip地址最后一個或第一個)
- >>> s='kkk 192.137.1.336 kkk 1192.168.1.137 kk 192.168.1.138 kk' #第一個和第二個ip地址都無效,不應該匹配出來
- >>> l=re.findall(r'(?:25[0-5]\.|2[0-4]\d\.|[01]?\d\d?\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)',s)
- >>> print l
- ['192.137.1.33', '192.168.1.137', '192.168.1.138']#截取了第一個和第二個ip地址的一部分
這時應如何解決呢?下面是匹配ip地址的常用版本1:
- >>> s='kkk 192.137.1.336 kkk 1192.168.1.137 kk 192.168.1.138 kk'
- >>> l=re.findall(r'\b(?:25[0-5]\.|2[0-4]\d\.|[01]?\d\d?\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b',s)
- >>> l
- ['192.168.1.138']
- >>> l=re.findall(r'\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b',s)
- >>> l
- ['192.168.1.138']
- # '\b'表示符合要求的子串的第一個字符的前面和最后一個字符的后面不可以是'\w'字符(不可以是大小字母,數字,下划線)
- #上述版本比較常用,但也存在一點問題:
- >>> s='kkk 192.137.1.336 kkk 192.168.1.137.123 kk 192.168.1.138 kk'
- #第二個ip地址以'.'號作為分隔符,且每個數字在[0,255]之間,但該ip地址無效(多了一個數字)!!
- >>> l=re.findall(r'\b(?:25[0-5]\.|2[0-4]\d\.|[01]?\d\d?\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b',s)
- >>> print l
- ['192.168.1.137', '192.168.1.138'] #將第二個ip地址,截取了前4個數字,但顯然第二個ip地址本應是無效的!!
這種情況可這樣解決,使用常用版本2:
- >>> s='kkk 192.137.1.336 kkk 192.168.1.137.123 kk 192.168.1.138 kk'
- >>> l=re.findall(r'(?<![\.\d])(?:25[0-5]\.|2[0-4]\d\.|[01]?\d\d?\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)(?![\.\d])',s)
- >>> print l
- ['192.168.1.138'] #准確的提取了ip地址!
綜上所述:
1》若從日志文件中提取ip,那么可以簡單寫成這樣:
- re.findall(r'\d+\.\d+\.\d+\.\d+',s) # 適用於不需要驗證ip地址的場合
2》如需要驗證ip地址,一般使用下面2種方法:
- #2.1>
- re.findall(r'\b(?:25[0-5]\.|2[0-4]\d\.|[01]?\d\d?\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b',s)
- #或:
- re.findall(r'\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b',s)
- #2.2>
- re.findall(r'(?<![\.\d])(?:25[0-5]\.|2[0-4]\d\.|[01]?\d\d?\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)(?![\.\d])',s)
- #或:
- re.findall(r'(?<![\.\d])(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)(?![\.\d])',s)
