python中利用正則表達式匹配ip地址


現在有一道題目,要求利用python中re模塊來匹配ip地址,我們應如何着手?

首先能想到的是ip地址是數字,正則表達式是如何匹配數字的呢?

\d或[0-9]

對於這個問題,不要一下子上來就寫匹配模式,應該一步步分解,把復雜的問題簡單化

比如ip地址,我們可以總結一下規律

1. 它是一個字符串

2. 字符串內部是由4個1-3位的數字和3個.組成

3. 數字的范圍是0-255

接下來,我們先試一下匹配第1個數字

第一步:嘗試匹配192.168.100.123中的192

>>> import re
>>> re.search(r"\d\d\d", "192.168.100.123")
<_sre.SRE_Match object; span=(0, 3), match='192'>

第二步:嘗試匹配192.168.100.123中的192.

值得注意的是,由於正則表達式中的元字符 . 表示除了\n之外的任意一個字符,我們需要匹配 . 本身,就需要用 \ 進行轉義

>>> re.search(r"\d\d\d\.", "192.168.100.12")
<_sre.SRE_Match object; span=(0, 4), match='192.'>

第三步:嘗試匹配192.168.100.123的整體

>>> re.search(r"\d\d\d\.\d\d\d\.\d\d\d\.\d\d\d", "192.168.100.123")
<_sre.SRE_Match object; span=(0, 15), match='192.168.100.123'>

這樣寫有什么問題呢?

1. 我們的數字並不都是3位,像192.168.100.1這樣的,我們的匹配模式就失效了

>>> re.search(r"\d\d\d\.\d\d\d\.\d\d\d\.\d\d\d", "192.168.100.1")
>>> 

2. 不夠美觀

第四步:優化誤區一

很多人一上手,就寫成了[0-255],這不就是數字的范圍0-255嗎?我們說,這樣是不對的

正則表達式中,真正要匹配的永遠是字符串,一個字符串內部是由三位的數字構成的,如果需要匹配三位數字的形式,就需要用到[0-9][0-9][0-9]或\d\d\d,用一個[0-9]表示的只能匹配一位,[0-255]這種錯誤的寫法也只能匹配到一位0-9之間的數字

>>> re.search(r"[0-255]", "255")
<_sre.SRE_Match object; span=(0, 1), match='2'>

如下圖,第一個[0-255]匹配到了1, \.匹配到了.

這個ip地址中根本沒有 1. 這種形式的,所以返回了None

>>> re.search(r"[0-255]\.[0-255]\.[0-255]\.[0-255]", "192.168.100.1")
>>> 

優化誤區二:

既然上面的不對,那能不能把255分解成 2, 5, 5, 我們匹配時能否寫成[0-2][0-5][0-5],看似是沒問題的,我們來試試

>>> re.search(r"[0-2][0-5][0-5]", "192.168.100.1")
<_sre.SRE_Match object; span=(8, 11), match='100'>
>>> 

為什么192沒有匹配到?168也沒有匹配到?因為數字的十位和個位最大只能是5,超過5的肯定沒法匹配

第五步:繼續優化

我們來看下0-255這個范圍,當百位是0或者1時,十位和個位可以是[0-9],也就是\d,當百位是2時,十位是[0-4]時,個位可以是\d,當百位是2時,十位是5時,個位只能是[0-5],那么,我們是不是可以這樣來寫,比如匹配192,匹配模式可以寫成

[01]\d\d|2[0-4]\d|25[0-5]

如果有重復的,我們可以給上面的模式加上 {n} 表示重復匹配前面的字符n次

>>> re.search(r"(([01]\d\d|2[0-4]\d|25[0-5]\d)\.){3}([01]\d\d|2[0-4]\d|25[0-5]\d)", "192.168.100.123")
<_sre.SRE_Match object; span=(0, 15), match='192.168.100.123'>

看似正確了,但是還是匹配不到數字 1 ,因為我們的百位是[01],意味這如果是 1 的情況下,我們的結果是001,但ip地址是不能寫成001, 002的

>>> re.search(r"(([01]\d\d|2[0-4]\d|25[0-5]\d)\.){3}([01]\d\d|2[0-4]\d|25[0-5]\d)", "192.168.100.1")
>>> 
>>> re.search(r"(([01]\d\d|2[0-4]\d|25[0-5]\d)\.){3}([01]\d\d|2[0-4]\d|25[0-5]\d)", "192.168.100.001")
<_sre.SRE_Match object; span=(0, 15), match='192.168.100.001'>
>>> 

可以通過{0,1}來優化,表示前面的字符重復0-1次,也可以用 ?

>>> re.search(r"(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]\d)\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]\d)", "192.168.100.1")
<_sre.SRE_Match object; span=(0, 13), match='192.168.100.1'>

>>> re.search(r"(([01]?\d?\d|2[0-4]\d|25[0-5]\d)\.){3}([01]?\d?\d|2[0-4]\d|25[0-5]\d)", "192.168.100.1")
<_sre.SRE_Match object; span=(0, 13), match='192.168.100.1'>

這樣,當數字只有個位時,百位的0匹配0次,十位的0匹配0次,只留下個位數字[0-9]

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM