首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Lua函数检查是否为ipv4、ipv6或string

Lua函数检查是否为ipv4、ipv6或string
EN

Stack Overflow用户
提问于 2012-06-11 15:22:54
回答 5查看 9.4K关注 0票数 6

我希望有一个函数,我可以将一个经过空格修剪的字符串传递给它,它将返回

0表示错误(不是字符串),1表示ipv4 2,ipv6 3表示不是ip的字符串。

Ipv6有以下规则:

Ipv6由8组以冒号(:)分隔的16位十六进制值表示

十六进制数字不区分大小写

缩写规则:

代码语言:javascript
复制
 1: Omit leading zeroes in a 16-bit value  
代码语言:javascript
复制
 2: Replace one or more groups of consecutive zeroes by a double colon  

维基示例显示了3种都是相同ipv6的方式:

代码语言:javascript
复制
fe80:0000:0000:0000:0202:b3ff:fe1e:8329
fe80:0:0:0:202:b3ff:fe1e:8329
fe80::202:b3ff:fe1e:8329 

我相当确定,对于ipv4,您只需检查三个。然后检查字符串是否全部

数字和.被算作数字,最后一次检查只是一个字符串

将位于if语句的末尾,因此如果它不是ipv4/6并且它是一个字符串,那么

它返回3

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-06-12 00:36:26

这似乎是一个需要解决的非常基本的问题。我认为这个函数可以满足您的需求。

代码语言:javascript
复制
function GetIPType(ip)
    -- must pass in a string value
    if ip == nil or type(ip) ~= "string" then
        return 0
    end

    -- check for format 1.11.111.111 for ipv4
    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

    -- check for ipv6 format, should be 8 'chunks' of numbers/letters
    local _, chunks = ip:gsub("[%a%d]+%:?", "")
    if chunks == 8 then
        return 2
    end

    -- if we get here, assume we've been given a random string
    return 3
end

使用以下代码对其进行测试:

代码语言:javascript
复制
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",     -- invalid ipv4
    "1050:0:0:0:5:600:300c:326b",               -- ipv6
    "1050:0000:0000:0000:0005:0600:300c:326b",  -- ipv6
    "1050:::600:5:1000::",  -- contracted ipv6
    "129.garbage.9.1",  -- string
    129.10              -- error
}

for k,v in pairs(ips) do
    print(v, IPType[GetIPType(v)])
end

它生成了以下输出:

代码语言:javascript
复制
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

将来,如果您实际发布了您试图编写的解决特定问题的代码,您将获得更多有用的反馈,并让我们知道您在哪里需要帮助。所以不是个人代码编写服务,如faq中所述。然而,由于你看起来是新的,这可能会让其他人受益,所以我会给你怀疑的好处。上面的代码是基本的,所以如果它没有捕捉到我不知道的边缘测试用例,请随时更新它。

票数 4
EN

Stack Overflow用户

发布于 2013-05-20 14:17:17

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为十六进制数):

代码语言:javascript
复制
function GetIPType(ip)
  local R = {ERROR = 0, IPV4 = 1, IPV6 = 2, STRING = 3}
  if type(ip) ~= "string" then return R.ERROR end

  -- check for format 1.11.111.111 for 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

  -- check for ipv6 format, should be 8 'chunks' of numbers/letters
  -- without leading/trailing chars
  -- or fewer than 8 chunks, but with only one `::` group
  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

要检查的脚本:

代码语言:javascript
复制
local IPType = {[0] = "Error", "IPv4", "IPv6", "string"}
local ips = {
    "128.1.0.1", -- ipv4
    "223.255.254.254", -- ipv4
    "999.12345.0.0001", -- invalid ipv4
    "1050:0:0:0:5:600:300c:326b", -- ipv6
    "1050!0!0+0-5@600$300c#326b", -- string
    "1050:0:0:0:5:600:300c:326babcdef", -- string
    "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::", -- contracted ipv6
    "::", -- ipv6
    "::1", -- ipv6
    "::1::", -- string
    "129.garbage.9.1", -- string
    "xxx127.0.0.0", -- error
    "xxx1050:0000:0000:0000:0005:0600:300c:326b", -- string
    129.10 -- error
}
for k,v in pairs(ips) do
    print(v, IPType[GetIPType(v)])
end

和输出:

代码语言:javascript
复制
128.1.0.1   IPv4
223.255.254.254 IPv4
999.12345.0.0001    string
1050:0:0:0:5:600:300c:326b  IPv6
1050!0!0+0-5@600$300c#326b  string
1050:0:0:0:5:600:300c:326babcdef    string
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::   string
129.garbage.9.1 string
xxx127.0.0.0    string
xxx1050:0000:0000:0000:0005:0600:300c:326b  string
129.1   Error

2018年9月6日更新,添加了对地址前/后垃圾的处理,并检查收缩的ipv6,允许少于8个组,其中一个空组包含两个连续的冒号。

票数 9
EN

Stack Overflow用户

发布于 2012-06-11 15:34:40

这似乎可以通过使用正则表达式轻松地完成。有很多用于lua的regex库。

但是,如果您不愿意或无法使用它们,我会这样做:

代码语言:javascript
复制
Start in ipv4 state
Take a character until string ends
    switch(state)
    ipv4:
        if it's a dot, check if we loaded at least one number
        if it's a number, check if it isn't the 4th in row
        if it's anything else, set state to ipv6 and proceed in this state
    ipv6:
        if it's a ':', check if we didnt exceed maximum number of segments
        if it's a number or letter<a;f> check if it isn't 5th in row
        in case anything breaks, return 3
    end

我不会发布完整的lua代码,因为它看起来家庭作业/学习练习和完整的答案对你的伤害大于它对你的帮助。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10975935

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档