Lua函数检查是否为IPv4或IPv6或字符串
我想要一个函数,可以传入一个经过去除空格的字符串,该函数将返回:
0 表示错误(不是字符串)
1 表示 IPv4
2 表示 IPv6
3 表示非 IP 字符串
IPv6 有以下规则:
IPv6 由 8 个以冒号(:)分隔的 16 位十六进制值组成
十六进制数不区分大小写
缩写规则:
1:省略 16 位值中的前导零
2:通过双冒号替换一个或多个连续的零组
维基百科例子显示了三种方式,这三种方式都代表同一个 IPv6:
fe80:0000:0000:0000:0202:b3ff:fe1e:8329
fe80:0:0:0:202:b3ff:fe1e:8329
fe80::202:b3ff:fe1e:8329
我相当肯定,对于 IPv4,只需检查是否有三个“.”,然后检查字符串是否全为数字,“.” 也被视为数字。最后,如果既不是 IPv4/6 也不是字符串,则放在 if 语句的结尾处,返回 3。
这似乎是一个相当基本的问题,可以解决。我认为以下函数可以做到你需要的...
function GetIPType(ip)
-- 必须传入字符串值
if ip == nil or type(ip) ~= "string" then
return 0
end
-- 检查ipv4格式1.11.111.111
local chunks = {ip:match("(%d+)%.(%d+)%.(%d+)%.(%d+)")}
if (#chunks == 4) then
for _,v in pairs(chunks) do
if (tonumber(v) < 0 or tonumber(v) > 255) then
return 0
end
end
return 1
else
return 0
end
-- 检查ipv6格式,应该是8组数字/字母
local _, chunks = ip:gsub("[%a%d]+%:?", "")
if chunks == 8 then
return 2
end
-- 如果到这里,假设我们被给了一个随机字符串
return 3
end
使用以下代码进行测试:
local IPType = {
[0] = "Error",
[1] = "IPv4",
[2] = "IPv6",
[3] = "string",
}
local ips = {
"128.1.0.1", -- ipv4
"223.255.254.254", -- ipv4
"999.12345.0.0001", -- 无效的ipv4
"1050:0:0:0:5:600:300c:326b", -- ipv6
"1050:0000:0000:0000:0005:0600:300c:326b", -- ipv6
"1050:::600:5:1000::", -- 简写的ipv6
"129.garbage.9.1", -- 字符串
129.10 -- 错误
}
for k,v in pairs(ips) do
print(v, IPType[GetIPType(v)])
end
输出:
128.1.0.1 IPv4
223.255.254.254 IPv4
1050:0:0:0:5:600:300c:326b IPv6
1050:0000:0000:0000:0005:0600:300c:326b IPv6
129.garbage.9.1 string
129.1 Error
将来,如果您实际发布您尝试编写的代码以解决您的特定问题,并告诉我们您需要帮助的地方,您将获得更有帮助的反馈。如常见问题解答中所述,SO不是个人代码编写服务。不过,我会给你一些优惠,因为你看起来很新,并且这可能对其他人有益。上面的代码很基本,如果它不能捕获我不知道的边缘测试用例,请随意更新它。
Mike 的解决方案很好,但是它可以通过多种方式进行改进。在当前形式下它不能检测到 IPv6 地址,但可以轻松修复。IPv6 检查会因诸如 "1050!0!0+0-5@600$300c#326b" 和 "1050:0:0:0:5:600:300c:326babcdef"(将两者都识别为有效地址)以及 "1050:::600:5:1000::"(将其识别为字符串)而失败。
这是改进后的版本(IPv4 假定是十进制数,IPv6 假定是十六进制数):
function GetIPType(ip)
local R = {ERROR = 0, IPV4 = 1, IPV6 = 2, STRING = 3}
if type(ip) ~= "string" then return R.ERROR end
-- 检查格式 1.11.111.111 对于 ipv4
local chunks = {ip:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$")}
if #chunks == 4 then
for _,v in pairs(chunks) do
if tonumber(v) > 255 then return R.STRING end
end
return R.IPV4
end
-- 检查 ipv6 格式,应该是 8 个数字 / 字母的“块”
-- 没有前导 / 后续字符
-- 或少于 8 个块,但只有一个 `::` 组
local chunks = {ip:match("^"..(("([a-fA-F0-9]*):"):rep(8):gsub(":$","$")))}
if #chunks == 8
or #chunks < 8 and ip:match('::') and not ip:gsub("::","",1):match('::') then
for _,v in pairs(chunks) do
if #v > 0 and tonumber(v, 16) > 65535 then return R.STRING end
end
return R.IPV6
end
return R.STRING
end
要检查的脚本:
local IPType = {[0] = "Error", "IPv4", "IPv6", "string"}
local ips = {
"128.1.0.1", -- ipv4
"223.255.254.254", -- ipv4
"999.12345.0.0001", -- 无效 ipv4
"1050:0:0:0:5:600:300c:326b", -- ipv6
"1050!0!0+0-5@600$300c#326b", -- 字符串
"1050:0:0:0:5:600:300c:326babcdef", -- 字符串
"1050:0000:0000:0000:0005:0600:300c:326b", -- ipv6
"fe80:0000:0000:0000:0202:b3ff:fe1e:8329", -- ipv6
"fe80:0:0:0:202:b3ff:fe1e:8329", -- ipv6
"fe80::202:b3ff:fe1e:8329", -- ipv6
"1050:::600:5:1000::", -- 缩写 ipv6
"::", -- ipv6
"::1", -- ipv6
"::1::", -- 字符串
"129.garbage.9.1", -- 字符串
"xxx127.0.0.0", -- 错误
"xxx1050:0000:0000:0000:0005:0600:300c:326b", -- 字符串
129.10 -- 错误
}
for k,v in pairs(ips) do
print(v, IPType[GetIPType(v)])
end
输出如下:
128.1.0.1 IPv4
223.255.254.254 IPv4
999.12345.0.0001 字符串
1050:0:0:0:5:600:300c:326b IPv6
1050!0!0+0-5@600$300c#326b 字符串
1050:0:0:0:5:600:300c:326babcdef 字符串
1050:0000:0000:0000:0005:0600:300c:326b IPv6
fe80:0000:0000:0000:0202:b3ff:fe1e:8329 IPv6
fe80:0:0:0:202:b3ff:fe1e:8329 IPv6
fe80::202:b3ff:fe1e:8329 IPv6
1050:::600:5:1000:: IPv6
:: IPv6
::1 IPv6
::1:: 字符串
129.garbage.9.1 字符串
xxx127.0.0.0 字符串
xxx1050:0000:0000:0000:0005:0600:300c:326b 字符串
129.1 错误
在 2018 年 9 月 6 日更新,添加了地址前后的垃圾处理,并检查缩写 ipv6,它允许不到 8 个组仅具有两个连续冒号的空组。
由于Lua的正则表达式不够表达性,您必须使用迭代算法进行。
我建议您检查我在意大利维基百科上发布的一个(经过完全测试):
local R = {ERROR = 0, IPV4 = 1, IPV6 = 2, STRING = 3}
function is_ipv4(str)
local s = str:gsub("/[0-9]$", ""):gsub("/[12][0-9]$", ""):gsub("/[3][0-2]$", "")
if not s:find("^%d+%.%d+%.%d+%.%d+$") then
return nil
end
for substr in s:gmatch("(%d+)") do
if not substr:find("^[1-9]?[0-9]$")
and not substr:find("^1[0-9][0-9]$")
and not substr:find( "^2[0-4][0-9]$")
and not substr:find("^25[0-5]$") then
return nil
end
end
return R.IPV4
end
function is_ipv6(str)
local s = str
if not (s:find("^%w+:%w+:%w+:%w+:%w+:%w+:%w+:%w+$") -- there are exactly seven ":"
or (s:find("^%w*:%w*:%w*:?%w*:?%w*:?%w*:?%w*$") -- otherwise there are two to six sei ":"
and s:find("::"))) -- and there must be the substring "::"
or s:find("::.*::") -- but there cannot be neither two substrings "::"
or s:find(":::") then -- nor a substring ":::"
return nil
end
for substr in s:gmatch("(%w+)") do
if not substr:find("^[0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?$") then
return nil
end
end
return R.IPV6
end
function ip_type(str)
if type(str) ~= "string" then
return R.ERROR
else
return is_ipv4(str) or is_ipv6(str) or R.STRING
end
end
编辑:根据OP的要求,我改变了ip_type()函数的输出。
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
这似乎是通过使用正则表达式可以轻松完成的事情。Lua 有很多正则表达式库。
然而,如果您不愿意或无法使用它们,我会这样做:
从 ipv4 状态开始 取一个字符直到字符串结束 switch(state) ipv4: 如果是一个点,则检查我们是否加载了至少一个数字。 如果是数字,请检查它是否不是第 4 个数字。 如果是其他字符,请将状态设置为 ipv6 并在该状态下继续。 ipv6: 如果是“:”,请检查我们是否未超过最大段数。 如果是数字或字母<a;f>,请检查它是否不是第 5 个字符。 如果有任何错误,请返回 3。 end我不会发布完整的Lua代码,因为它看起来像是作业/学习练习,完整的答案会对您的帮助不大,反而会有害处。