1. LeetCode468题:验证IP地址
编写一个函数来验证输入的字符串是否是有效的IPv4或IPv6地址。
IPv4地址由十进制数和点来表示,每个地址包含4个十进制数,其范围为0-255,用(".")分割。比如,172.16.254.1;同时,IPv4地址内的数不会以0开头。比如,地址172.16.254.01 是不合法的。
IPv6地址由8组16进制的数字来表示,每组表示16比特。这些组数字通过(":")分割。
比如, 2001:0db8:85a3:0000:0000:8a2e:0370:7334是一个有效的地址。而且,我们可以加入一些以0开头的数字,字母可以使用大写,也可以是小写。所以,2001:db8:85a3:0:0:8A2E:0370:7334也是一个有效的IPv6地址(忽略0开头,忽略大小写)。
然而,我们不能因为某个组的值为0,而使用一个空的组,以至于出现("::")的情况。
比如,2001:0db8:85a3::8A2E:0370:7334是无效的IPv6地址。
同时,在IPv6地址中,多余的0也是不被允许的。比如,02001:0db8:85a3:0000:0000:8a2e:0370:7334是无效的。
说明: 你可以认为给定的字符串里没有空格或者其他特殊字符。
示例 1:
输入: “172.16.254.1”
输出: “IPv4”
解释: 这是一个有效的 IPv4 地址, 所以返回 “IPv4”。
示例 2:
输入: “2001:0db8:85a3:0:0:8A2E:0370:7334”
输出: “IPv6”
解释: 这是一个有效的 IPv6 地址, 所以返回 “IPv6”。
示例 3:
输入: “256.256.256.256”
输出: “Neither”
解释: 这个地址既不是 IPv4 也不是 IPv6 地址。
2. Python正则表达式
正则表达式是一个特殊的字符序列,它能帮助你方便地检查一个字符串是否与某种模式匹配。
2.1 正则表达式模式
模式字符串使用特殊的语法来表示一个正则表达式:
- 字母和数字表示它们自身。一个正则表达式模式中的字母和数字匹配同样的字符。
- 多数字母和数字前加一个反斜杠时会拥有不同的含义。
- 多数标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
本文涉及到的Python正则表达式模式如下表所示。
模式 | 功能描述 |
---|---|
$ | 匹配字符串的末尾 |
[…] | 用来表示一组字符,单独列出:[amk] 匹配 ‘a’, ‘m’ 或 ‘k’ |
\d | 匹配任意数字,等价于 [0-9] |
\. | 匹配 ‘.’ |
(re) | 对正则表达式分组并记住匹配的文本 |
a | b | 匹配a或b |
re{m, n} | 匹配m到n次由前面的正则表达式定义的片段,贪婪方式 |
re{n} | 精确匹配n个表达式。例如,o{2} 不能匹配 ‘Bob’ 中的 ‘o’,但是能匹配 ‘food’ 中的 ‘oo’ |
2.2 re.match函数
re是正则表达式的英文regular expression的缩写。Python 自1.5版本起增加了re模块,它提供 Perl 风格的正则表达式模式。re模块使Python语言拥有全部的正则表达式功能。
re.match从字符串的起始位置开始与模式进行匹配,若匹配成功,则返回一个匹配对象,若匹配失败,则返回None。
函数语法:
re.match(pattern, string)
函数参数说明:
pattern表示正则表达式模式,string表示要匹配的字符串。
3. Pyhton代码实现
import re
def validIPAddress(IP):
pattern_0_255 = '(\d|([1-9]\d)|(1\d\d)|(2[0-4]\d)|(25[0-5]))'
pattern_IPv4 = '(' + pattern_0_255 + '\.){3}' + pattern_0_255 + '$'
pattern_IPv6 = '([\dA-Fa-f]{1,4}\:){7}[\dA-Fa-f]{1,4}$'
if re.match(pattern_IPv4, IP):
return 'IPv4'
if re.match(pattern_IPv6, IP):
return 'IPv6'
return 'Neither'
print(validIPAddress('172.16.254.1'))
print(validIPAddress('2001:0db8:85a3:0:0:8A2E:0370:7334'))
print(validIPAddress('256.256.256.256'))
实验结果:
IPv4
IPv6
Neither
4. 正则表达式解析:
1)pattern_0_255 = '(\d|([1-9]\d)|(1\d\d)|(2[0-4]\d)|(25[0-5]))'
pattern_0_255分段匹配0-255的整数:
模式 | \d | [1-9]\d | 1\d\d | 2[0-4]\d | 25[0-5] |
---|---|---|---|---|---|
匹配字符串 | 0-9 | 10-99 | 100-199 | 200-249 | 250-255 |
2)pattern_IPv4 = '(' + pattern_0_255 + '\.){3}' + pattern_0_255 + '$'
因为IPv4地址用4个0-255的整数来表示,数与数之间通过‘.’来分割,所以前3个数中的每个数之后都是‘.’,因此其模式为'(' + pattern_0_255 + '\.){3}'
;
最后1个数之后是字符串结束符,需要单独表示,因此最终的模式字符串为'(' + pattern_0_255 + '\.){3}' + pattern_0_255 + '$'
。
3)pattern_IPv6 = '([\dA-Fa-f]{1,4}\:){7}[\dA-Fa-f]{1,4}$'
因为16进制数字是由0-9和A-F共16个字符组成,并且字母不区分大小写,所以1个16进制数字的模式为'[\dA-Fa-f]'
;
因为一组数字可以是1-4位,所以其模式为'[\dA-Fa-f]{1,4}'
;
因为IPv6地址用8组16进制的数字来表示,组与组之间通过‘:’来分割,所以前7组中的每一组之后都是‘:’,因此其模式为'([\dA-Fa-f]{1,4}\:){7}'
;
最后1组之后是字符串结束符,需要单独表示,因此最终的模式字符串为'([\dA-Fa-f]{1,4}\:){7}[\dA-Fa-f]{1,4}$'
。