給一個字串 IP ,回傳其屬於 IPv4 或 IPv6 或都不是 Neighter。
如果要找「合格」的字串,會想到用 re 去解決,這是在一般的情況下。如果是LeetCode,也許就不會用它。
不過官方的解法是有用到 re 的,直接傻眼,但那確實是最正當的解法。
通過「正則表達式(Regex)」是最嚴謹的做法,但也要有支持這項功能,在未知跟沒有的情況下,只能土炮出來。
這裡要從根本講,不論IPv6或是IPv4對電腦來說都是連續的二進位,IPv4長度為32bit,IPv6為128bit。
給人看的十進位跟十六進位是經由轉換而來的,如果換回原來的二進位形式,就只要留意是否長度是否合格就好。
所以把 string IP 轉換成連續二進位,就能輕而易舉去找出是否為合格的IP位置。(但是寫轉換的過程不容易)
在 IPv4 中用「.」做分隔,是用十進位的數字,分四段,每一段要有8bit。
在 IPv6 中用「:」做分隔,是用十六進位的數字,分八段,每一段要有32bit。
寫成IP轉換版,轉 IPv6 或 IPv4 的流程是大同小異的,甚至可以只用一個函數修改一些傳入參數就能變成IPv4或IPv6皆可的式子。
class Solution: def validIPAddress(self, IP: str) -> str: deci = {*"0123456789"} hexdeci = {*"0123456789abcdef"} def checkIPv4(IP): group = IP.split(".") if len(group) != 4: return False for seg in group: if not(3 >= len(seg) >= 1): return False if any([c not in deci for c in seg]): return False if not(255 >= int(seg) >= 0): return False if str(int(seg)) != seg: return False return True def checkIPv6(IP): group = IP.lower().split(":") if len(group) != 8: return False for seg in group: if not(4 >= len(seg) >= 1): return False if any([c not in hexdeci for c in seg]): return False return True if checkIPv4(IP): return "IPv4" if checkIPv6(IP): return "IPv6" return "Neither"Python(IP轉換版)
class Solution: def validIPAddress(self, IP: str) -> str: decimal = {*"0123456789"} def covertIPv4(IP): IPv4 = "" seg = "" segCount = 0 for c in IP: if c == ".": segCount += 1 if segCount >= 4 or not seg: return False if len(seg) > 1 and seg[0] == '0': return False seg = "{:0>8}".format(bin(int(seg))[2:]) if len(seg) > 8: return False IPv4 += seg seg = "" elif c in decimal: seg += c else: return False if seg: if len(seg) > 1 and seg[0] == '0': return False seg = "{:0>8}".format(bin(int(seg))[2:]) if len(seg) > 8: return False IPv4 += seg return len(IPv4) == 32 hexadecimal = {*"0123456789abcdefABCDEF"} def covertIPv6(IP): IPv6 = "" seg = "" segCount = 0 for c in IP: if c == ":": segCount += 1 if segCount >= 8 or not seg: return False seg = "{:0>16}".format(seg) if len(seg) > 16: return False IPv6 += seg seg = "" elif c in hexadecimal: seg += "{:0>4}".format(bin(int(c, 16))[2:]) else: return False if seg: seg = "{:0>16}".format(seg) if len(seg) > 16: return False IPv6 += seg return len(IPv6) == 128 if covertIPv4(IP): return "IPv4" if covertIPv6(IP): return "IPv6" return "Neither"Python(IP轉換合一版)
class Solution: def validIPAddress(self, IP: str) -> str: decimal = {*"0123456789"} hexadecimal = {*"0123456789abcdef"} def covertIP(strIP, Segs, PerSegBit, Carry, Delimiter): def addSeg(IP, seg): if segCount >= Segs or not seg: return False if Delimiter == "." and len(seg) > 1 and seg[0] == '0': return False if Delimiter == ":" and len(seg) > 4: return False try: seg = ("{:0>"+str(PerSegBit)+"}").format(bin(int(seg, len(Carry)))[2:]) except: return False if len(seg) > PerSegBit: return False return IP + seg IP = seg = "" segCount = 0 for c in strIP.lower(): if c == Delimiter: segCount += 1 IP = addSeg(IP, seg) if not IP: return False seg = "" elif c in Carry: seg += c else: return False if not seg: return False IP = addSeg(IP, seg) if not IP: return False return len(IP) == Segs * PerSegBit if covertIP(IP, 4, 8, decimal, "."): return "IPv4" if covertIP(IP, 8, 16, hexadecimal, ":"): return "IPv6" return "Neither"C#
public class Solution { public string ValidIPAddress(string IP) { if(IsIPv4(IP)){return "IPv4";} if(IsIPv6(IP)){return "IPv6";} return "Neither"; } private bool IsIPv4(string IP) { var parts = IP.Split('.'); if(parts.Length != 4){return false;} int dec = 0; foreach(var part in parts) { if(!(Int32.TryParse(part, out dec))){return false;} if(dec < 0 || dec > 255 || (dec.ToString().Length != part.Length)){return false;} } return true; } private bool IsIPv6(string IP) { var parts = IP.Split(':'); if(parts.Length != 8){return false;} int hex; foreach(var part in parts) { if(part.Length > 4){return false;} if(!Int32.TryParse(part, System.Globalization.NumberStyles.HexNumber, null, out hex)){return false;} if(hex < 0){return false;} } return true; } }TestCase
"1.1.1.01" "01.01.01.01" "001.001.001.001" "301.301.301.301" "12..33.4" "1.0.1." "1.-1.1.1" "0.0.0.0" "172.16.254.1" "256.256.256.256" "2001:0db8:85a3:0:0:8A2E:0370:7334" "2001:0db8:85a3::8A2E:0370:7334" "2001:db8:85a3:0:0:8A2E:0370:7334" "20EE:FGb8:85a3:0:0:8A2E:0370:7334" "2001:0db8:85a3:00000:0:8A2E:0370:7334" "1081:db8:85a3:01:-0:8A2E:0370:7334" "2001:0db8:85a3:0:0:8A2E:0370:7334:"