(#字符串处理)判断字符串是否为有效IPv4地址

一、题目理解

IPv4地址格式要求

  1. 必须是 4段数字 ,用点(.) 分隔
  2. 每段必须是 0-255 之间的整数
  3. 不能有前导零(比如"01"、"001"无效,但单个"0"有效)
  4. 每段必须是纯数字,不能有其他字符

有效示例

  • "192.168.1.1"
  • "10.0.0.1"
  • "0.0.0.0"
  • "255.255.255.255"

无效示例

  • "192.168.1"(只有3段)
  • "192.168.1.1.1"(5段)
  • "192.168.001.1"(001有前导零)
  • "256.0.0.1"(256超过255)
  • "192.168.1.a"(包含字母)
  • "192.168..1"(有空段)

二、解法一:模拟法(逐步验证)

这是最直观的方法,按步骤验证每个条件。

完整代码:

python 复制代码
def is_valid_ipv4_simulation(ip: str) -> bool:
    """
    使用模拟法验证IPv4地址
    """
    # 1. 按点号分割字符串
    parts = ip.split('.')
    
    # 2. 验证是否有4段
    if len(parts) != 4:
        return False
    
    # 3. 验证每一段
    for part in parts:
        # 3.1 验证是否为纯数字
        if not part.isdigit():
            return False
        
        # 3.2 验证长度不超过3
        if len(part) > 3:
            return False
        
        # 3.3 将字符串转为整数
        num = int(part)
        
        # 3.4 验证范围0-255
        if num < 0 or num > 255:
            return False
        
        # 3.5 验证没有前导零(除非就是0)
        if len(part) > 1 and part[0] == '0':
            return False
    
    # 4. 所有验证通过
    return True

逐行详细解释:

第1步:分割字符串
python 复制代码
parts = ip.split('.')
  • split('.'):按点号分割字符串
  • 例如:"192.168.1.1"["192", "168", "1", "1"]
第2步:验证段数
python 复制代码
if len(parts) != 4:
    return False
  • IPv4必须是4段
  • 注意:split('.')会把连续的点号变成空字符串
    • "192.168..1"["192", "168", "", "1"](长度为4但有空段)
第3步:验证每一段
3.1 验证是否为纯数字
python 复制代码
if not part.isdigit():
    return False
  • isdigit():判断字符串是否只包含数字字符
  • 可以过滤掉:空字符串""、字母、符号等
  • 注意:""不是数字,所以会返回False
3.2 验证长度不超过3
python 复制代码
if len(part) > 3:
    return False
  • 最大数字是255,长度最多3位
3.3 转为整数
python 复制代码
num = int(part)
  • 将数字字符串转为整数
  • 注意:前面已经验证过isdigit(),所以这里不会出错
3.4 验证范围0-255
python 复制代码
if num < 0 or num > 255:
    return False
  • IPv4每段范围是0-255
  • 注意:0是允许的(比如"0.0.0.0"
3.5 验证没有前导零
python 复制代码
if len(part) > 1 and part[0] == '0':
    return False
  • len(part) > 1:长度大于1(不是单个数字)
  • part[0] == '0':第一个字符是0
  • 这样会排除:"01""001""012"
  • 但允许:"0"(单个0是合法的)

测试验证:

python 复制代码
# 测试用例
test_cases = [
    ("192.168.1.1", True),
    ("0.0.0.0", True),
    ("255.255.255.255", True),
    ("10.0.0.1", True),
    ("192.168.01.1", False),  # 前导零
    ("192.168.1", False),     # 只有3段
    ("192.168.1.1.1", False), # 5段
    ("256.0.0.1", False),     # 超过255
    ("192.168.1.a", False),   # 包含字母
    ("192.168..1", False),    # 有空段
    ("-1.0.0.1", False),      # 负数
]

for ip, expected in test_cases:
    result = is_valid_ipv4_simulation(ip)
    print(f"ip: {ip:20} expected: {expected} result: {result} {'✓' if result == expected else '✗'}")

三、解法二:正则表达式法

正则表达式可以一次性验证所有条件,代码更简洁。

先理解IPv4的正则规则

IPv4的每段数字可以分解为:

  1. 0-9(1位数字,可以是0-9)
  2. 10-99(2位数字,第一位1-9,第二位0-9)
  3. 100-199(3位数字,第一位1,第二位0-9,第三位0-9)
  4. 200-249(3位数字,第一位2,第二位0-4,第三位0-9)
  5. 250-255(3位数字,第一位2,第二位5,第三位0-5)

把这些情况用正则表达式写出来:

正则表达式分解学习:

1. 先看单段的正则:
regex 复制代码
(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])

分解:

  • 25[0-5]:匹配 250-255
  • 2[0-4][0-9]:匹配 200-249
  • 1[0-9][0-9]:匹配 100-199
  • [1-9][0-9]:匹配 10-99(第一位1-9,第二位0-9)
  • [0-9]:匹配 0-9(允许0,但不允许前导0,因为前面已经有[1-9][0-9])

注意:这个正则已经自动排除了前导零,因为:

  • 一位数可以是0-9
  • 两位数第一位必须是1-9(不能是0)
  • 三位数第一位必须是1或2(也不能是0)
2. 完整的IPv4正则:
regex 复制代码
^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$

分解:

  • ^:字符串开始
  • ( ... \.){3}:重复3次(三段数字+点号)
  • ( ... ):第4段数字(没有点号)
  • $:字符串结束

完整代码(正则版):

python 复制代码
import re

def is_valid_ipv4_regex(ip: str) -> bool:
    """
    使用正则表达式验证IPv4地址
    """
    # 编译正则表达式
    pattern = re.compile(r'^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$')
    
    # 匹配整个字符串
    return bool(pattern.match(ip))

测试正则版:

python 复制代码
# 使用相同的测试用例
for ip, expected in test_cases:
    result = is_valid_ipv4_regex(ip)
    print(f"ip: {ip:20} expected: {expected} result: {result} {'✓' if result == expected else '✗'}")

四、正则表达式详细讲解(给初学者的)

如果你对正则表达式不熟悉,让我详细解释每个部分:

正则表达式基础语法:

  • ^:匹配字符串开始
  • $:匹配字符串结束
  • |:或(选择)
  • ():分组
  • []:字符集合,匹配其中任意一个字符
  • {n}:重复n次
  • \.:点号(.在正则中有特殊含义,需要转义)

分部分理解:

1. 匹配250-255:
regex 复制代码
25[0-5]
  • 25:匹配字符"25"
  • [0-5]:匹配0-5中任意一个数字
  • 组合:250、251、252、253、254、255
2. 匹配200-249:
regex 复制代码
2[0-4][0-9]
  • 2:匹配字符"2"
  • [0-4]:匹配0-4中任意一个数字
  • [0-9]:匹配0-9中任意一个数字
  • 组合:200-249
3. 匹配100-199:
regex 复制代码
1[0-9][0-9]
  • 1:匹配字符"1"
  • 两个[0-9]:各匹配0-9中任意一个数字
  • 组合:100-199
4. 匹配10-99:
regex 复制代码
[1-9][0-9]
  • [1-9]:匹配1-9中任意一个数字(不能是0)
  • [0-9]:匹配0-9中任意一个数字
  • 组合:10-99
5. 匹配0-9:
regex 复制代码
[0-9]
  • [0-9]:匹配0-9中任意一个数字
  • 组合:0-9

为什么这个正则能排除前导零?

看看10-99的情况:

  • 第一位是[1-9],不能是0
  • 所以"01"、"02"等不会被匹配

三位数的情况:

  • 100-199:第一位是1,不是0
  • 200-249:第一位是2,不是0
  • 250-255:前两位是25,不是0

这样,"001"、"012"等都不会被匹配。

五、两种方法的比较

方法 优点 缺点 适用场景
模拟法 逻辑清晰,易于理解和调试 代码较长,多个if语句 面试中展示逻辑思维,适合初学者
正则法 代码简洁,一行搞定 正则表达式难写难懂,调试困难 实际项目中,追求代码简洁

六、面试回答建议

如果面试官问这道题:

  1. 先讲思路:"我会用点号分割字符串,然后验证4个条件..."
  2. 写代码:用模拟法写,边写边解释
  3. 优化:"其实也可以用正则表达式,正则表达式更简洁,但可读性稍差"
  4. 测试:给出几个测试用例

示例回答:

复制代码
"这道题验证IPv4地址,主要看4点:1.是否4段;2.每段是否纯数字;3.是否在0-255;4.是否没有前导零。
我会先用split按点分割,然后逐一验证。比如先看长度是否为4,然后每段用isdigit判断是否为数字,
再转成整数看范围,最后检查长度大于1时首位不能是0。
也可以用正则表达式,比如^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}...$
但正则可能不太直观。"

七、力扣实战

现在请你:

  1. 题目链接:468. 验证IP地址
  2. 测试所有示例
  3. 尝试自己写一个测试函数,随机生成IP测试

IPv6地址格式要求

必须是 8段数字,用点(.) 分隔

每段长度1-4个字符

合法字符:0,1,2,...,9,a,b,c,d,e,f,A,B,C,D,E,F

允许前导零

bash 复制代码
class Solution:
    def validIPAddress(self, queryIP: str) -> str:
        # 情况1:检查是否是IPv4
        if '.' in queryIP:
            parts = queryIP.split('.')
            # 必须正好有4段
            if len(parts) != 4:
                return "Neither"
            
            for part in parts:
                # 1. 每段不能为空
                if not part:
                    return "Neither"
                
                # 2. 每段必须都是数字
                if not part.isdigit():
                    return "Neither"
                
                # 3. 检查数字范围 (0-255)
                num = int(part)
                if num < 0 or num > 255:
                    return "Neither"
                
                # 4. 检查前导零:如果长度>1且第一个字符是'0',无效
                if len(part) > 1 and part[0] == '0':
                    return "Neither"
            
            # 所有检查通过
            return "IPv4"
        
        # 情况2:检查是否是IPv6
        elif ':' in queryIP:
            parts = queryIP.split(':')
            # 必须正好有8段
            if len(parts) != 8:
                return "Neither"
            
            # 定义合法的十六进制字符
            hex_digits = set("0123456789abcdefABCDEF")
            
            for part in parts:
                # 1. 每段长度必须在1-4之间
                if len(part) < 1 or len(part) > 4:
                    return "Neither"
                
                # 2. 每个字符必须是十六进制字符
                for char in part:
                    if char not in hex_digits:
                        return "Neither"
            
            # 所有检查通过
            return "IPv6"
        
        # 情况3:既不是IPv4也不是IPv6
        else:
            return "Neither"

随机测试代码:

python 复制代码
import random

def generate_random_ip():
    """生成随机IP地址(可能无效)"""
    parts = []
    for _ in range(4):
        # 随机生成数字或字母
        if random.random() < 0.8:  # 80%概率生成数字
            num = random.randint(0, 300)  # 可能超过255
            parts.append(str(num))
        else:  # 20%概率生成字母
            parts.append(chr(random.randint(97, 122)))  # a-z
    
    return ".".join(parts)

# 测试随机IP
for i in range(10):
    ip = generate_random_ip()
    result1 = is_valid_ipv4_simulation(ip)
    result2 = is_valid_ipv4_regex(ip)
    if result1 != result2:
        print(f"不一致: {ip} 模拟法:{result1} 正则法:{result2}")

八、常见陷阱和注意事项

  1. 空字符串split('.')可能产生空字符串
  2. 负数isdigit()对于负数返回False(因为"-"不是数字)
  3. 前导零的判断:要小心"0"是合法的
  4. 大数字:虽然长度超过3可以直接排除,但转int前最好先判断长度
  5. 边界值:0和255都是有效的

记住:面试时模拟法更安全,因为你可以边写边解释思路。正则表达式虽然简洁,但如果写错或解释不清,可能扣分。

相关推荐
楼田莉子2 小时前
Linux进程间通信——管道
linux·运维·服务器·c++·学习
gettingolder2 小时前
haproxy的简单负载均衡实现
运维·服务器·负载均衡
智慧化智能化数字化方案2 小时前
安全生产——解读数字政府网络安全运营建设指南【附全文阅读】
网络·安全
七夜zippoe2 小时前
Python网络编程实战:从TCP/IP到WebSocket的协议演进与核心技术解析
网络·python·websocket·tcp/ip·socket·心跳机制
Selenium-Wang2 小时前
静态IP是什么意思?一文解析原理、用途与优势
网络·网络协议·tcp/ip
henujolly2 小时前
区块链p2p
服务器·区块链·p2p
礼拜天没时间.2 小时前
《Docker实战入门与部署指南:从核心概念到网络与数据管理》:初识Docker——概念与优势
linux·运维·网络·docker·容器·centos
阿钱真强道2 小时前
05 thingsboard-4.3-ubuntu20-rk3588-部署
linux·运维·服务器·鸿蒙
驱动探索者2 小时前
Intel Xeon 服务器 CPU 学习
运维·服务器·学习·xeon