SQL-leetcode—3451. 查找无效的 IP 地址

3451. 查找无效的 IP 地址

表:logs

±------------±--------+

| Column Name | Type |

±------------±--------+

| log_id | int |

| ip | varchar |

| status_code | int |

±------------±--------+

log_id 是这张表的唯一主键。

每一行包含服务器访问日志信息,包括 IP 地址和 HTTP 状态码。

编写一个解决方案来查找 无效的 IP 地址。一个 IPv4 地址如果满足以下任何条件之一,则无效:

任何 8 位字节中包含大于 255 的数字

任何 8 位字节中含有 前导零(如 01.02.03.04)

少于或多于 4 个 8 位字节

返回结果表分别以 invalid_count,ip 降序 排序。

结果格式如下所示。

示例:

输入:

logs 表:

±-------±--------------±------------+

| log_id | ip | status_code |

±-------±--------------±------------+

| 1 | 192.168.1.1 | 200 |

| 2 | 256.1.2.3 | 404 |

| 3 | 192.168.001.1 | 200 |

| 4 | 192.168.1.1 | 200 |

| 5 | 192.168.1 | 500 |

| 6 | 256.1.2.3 | 404 |

| 7 | 192.168.001.1 | 200 |

±-------±--------------±------------+

输出:

±--------------±-------------+

| ip | invalid_count|

±--------------±-------------+

| 256.1.2.3 | 2 |

| 192.168.001.1 | 2 |

| 192.168.1 | 1 |

±--------------±-------------+

解释:

256.1.2.3 是无效的,因为 256 > 255

192.168.001.1 是无效的,因为有前导零

192.168.1 是非法的,因为只有 3 个 8 位字节

输出表分别以 invalid_count,ip 降序排序。

题解

先判断 ip 是不是四段的,使用 LENGTH(ip) - LENGTH(REPLACE(ip, '.', '')) + 1 != 4

使用 SUBSTRING_INDEX 嵌套,分割出 ip 的每个段

转换数据类型,可通过 + 0 转换成数值类型,判断是否大于 255

通过 RLIKE 正则表达式判断是不是 0 开头,如果是 0 , ^0[0-9]+ 表示前导 0 后面还有至少一个数字

方法一 拆解判断

复制代码
SELECT
    ip
    ,COUNT(*) AS invalid_count
FROM logs
WHERE
    LENGTH(ip) - LENGTH(REPLACE(ip, '.', '')) + 1 != 4 OR
    SUBSTRING_INDEX(ip, '.', 1) + 0 > 255 OR SUBSTRING_INDEX(ip, '.', 1) RLIKE '^0[0-9]+'
    OR SUBSTRING_INDEX(SUBSTRING_INDEX(ip, '.', 2), '.', -1) + 0 > 255 OR SUBSTRING_INDEX(SUBSTRING_INDEX(ip, '.', 2), '.', -1) RLIKE '^0[0-9]+'
    OR SUBSTRING_INDEX(SUBSTRING_INDEX(ip, '.', 3), '.', -1) + 0 > 255 OR SUBSTRING_INDEX(SUBSTRING_INDEX(ip, '.', 3), '.', -1) RLIKE '^0[0-9]+'
    OR SUBSTRING_INDEX(ip, '.', -1) + 0 > 255 OR SUBSTRING_INDEX(ip, '.', -1) RLIKE '^0[0-9]+'
GROUP BY ip
ORDER BY invalid_count DESC, ip DESC

方法二 正则

复制代码
select t.ip,count(1) invalid_count
  from logs t
 where concat(t.ip,'.') not regexp
       -- 1-9  | 10-99    | 100-199 | 200-249   | 250-255
      '^(([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){4}$'
 group by t.ip
 order by invalid_count desc,t.ip desc