对于字符串匹配的问题,正则表达式绝对是一个大杀器,同时在实际的项目中正则表达式也是很好的一个工具,比方说,在语音处理方面,如果NLU的模型训练的不好,其实际的效果甚至不如正则表达式。
正则表达式规则
or
| 可以用来表示or的关系,例如:gray|grey can match “gray” or “grey”.
Grouping
括号用来定义区域的范围,例如:gray|grey and gr(a|e)y are equivalent patterns which both describe the set of “gray” or “grey”.
Quantificaton
? 匹配零个或一个在?之前的字符。例如:colou?r matches both “color” and “colour”.
匹配零个或多个在之前的字符。例如:ab*c matches “ac”, “abc”, “abbc”, “abbbc”, and so on.
+ 匹配一个或多个在+之前的字符
{n}匹配在其之前的字符n次
{min,}匹配在其之前的字符至少min次
{min,max}匹配在其之前的字符至少min次,至多max次
Wildcard 通配、
.(点)可以匹配除了换行符之外的所有字符
Example
a|b* denotes {ε, “a”, “b”, “bb”, “bbb”, …}(a|b)* denotes the set of all strings with no symbols other than “a” and “b”, including the empty string: {ε, “a”, “b”, “aa”, “ab”, “ba”, “bb”, “aaa”, …}ab*(c|ε) denotes the set of strings starting with “a”, then zero or more “b”s and finally optionally a “c”: {“a”, “ac”, “ab”, “abc”, “abb”, “abbc”, …}(0|(1(01*0)*1))* denotes the set of binary numbers that are multiples of 3: { ε, “0”, “00”, “11”, “000”, “011”, “110”, “0000”, “0011”, “0110”, “1001”, “1100”, “1111”, “00000”, … }
例题
468. 验证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 address地址 (即,忽略 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 地址。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/validate-ip-address
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
Python提供了专门的库用来判断是否是IPv4或是IPv6
from ipaddress import ip_address, IPv6Addressclass Solution:def validIPAddress(self, IP: str) -> str:try:return "IPv6" if type(ip_address(IP)) is IPv6Address else "IPv4"except ValueError:return "Neither"
正则表达式
import reclass Solution:chunk_IPv4 = r'([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'patten_IPv4 = re.compile(r'^(' + chunk_IPv4 + r'\.){3}' + chunk_IPv4 + r'$')chunk_IPv6 = r'([0-9a-fA-F]{1,4})'patten_IPv6 = re.compile(r'^(' + chunk_IPv6 + r'\:){7}' + chunk_IPv6 + r'$')def validIPAddress(self, IP: str) -> str:if self.patten_IPv4.match(IP):return "IPv4"return "IPv6" if self.patten_IPv6.match(IP) else "Neither"
时间复杂度O(1), 空间复杂度O(1)
分治法
class Solution:def validate_IPv4(self, IP: str) -> str:nums = IP.split('.')for x in nums:# Validate integer in range (0, 255):# 1. length of chunk is between 1 and 3if len(x) == 0 or len(x) > 3:return "Neither"# 2. no extra leading zeros# 3. only digits are allowed# 4. less than 255if x[0] == '0' and len(x) != 1 or not x.isdigit() or int(x) > 255:return "Neither"return "IPv4"def validate_IPv6(self, IP: str) -> str:nums = IP.split(':')hexdigits = '0123456789abcdefABCDEF'for x in nums:# Validate hexadecimal in range (0, 2**16):# 1. at least one and not more than 4 hexdigits in one chunk# 2. only hexdigits are allowed: 0-9, a-f, A-Fif len(x) == 0 or len(x) > 4 or not all(c in hexdigits for c in x):return "Neither"return "IPv6"def validIPAddress(self, IP: str) -> str:if IP.count('.') == 3:return self.validate_IPv4(IP)elif IP.count(':') == 7:return self.validate_IPv6(IP)else:return "Neither"
时间复杂度O(N),空间复杂度O(1)
笔者在做这道题时,采用C++费了半天劲才通过。但代码依旧不是特别的优雅
class Solution {public:bool isIPV4(string IP){if(IP.size() < 7 || IP[0] == '.' || IP[IP.size() - 1] == '.')return false;stringstream ss(IP);string item;vector<std::string>splitstr;while(getline(ss, item,'.')){splitstr.push_back(item);}if(splitstr.size() != 4)return false;for(auto &str : splitstr){if(str.size() > 3 || str.size() == 0 || (str[0] == '0' && str.size() != 1))return false;for(auto &ch : str){if(!(ch >= '0' && ch <= '9'))return false;}int tmp = stoi(str);if(tmp < 0 || tmp > 255)return false;}return true;}bool isIPV6(string IP){if(IP.size() < 15 || IP[0] == ':' || IP[IP.size() - 1] == ':')return false;stringstream ss(IP);string item;vector<std::string>splitstr;while(getline(ss, item,':')){splitstr.push_back(item);}if(splitstr.size() != 8)return false;for(auto &str : splitstr){if(str.size() > 4 || str.size() == 0)return false;for(auto &ch : str){if(!((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')))return false;}}return true;}string validIPAddress(string IP) {if(IP.size() <= 4)return "Neither";if(isIPV4(IP))return "IPv4";if(isIPV6(IP))return "IPv6";return "Neither";}};
