2012-06-11 56 views
2

我想有一个函数,我可以传递一个空白修剪的字符串,它将返回
0为错误(不是字符串)1为ipv4 2为ipv6 3为一个字符串,这不是一个IP。
Lua函数检查是否ipv4或ipv6或字符串

IPv6有以下规则:

IPv6是由8组由冒号分隔的16位的十六进制值来表示(:)
十六进制数字是不区分大小写
缩写规则:
1 :省略在一个16位的值前导零
2:用双冒号替换连续零的一个或多个基团表示3种方式是全部相同的IPv6

维基示例:

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

回答

3

这似乎是一个很难解决的基本问题。我觉得这个函数,你需要什么...

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 

与此代码测试它:

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 

其产生这样的输出:

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不是个人代码编写服务。然而,我会给你带来怀疑的好处,因为你看起来很新,这是可以让其他人受益的东西。上面的代码是基本的,所以如果它不能捕获我不知道的附带测试用例,请随时更新它。

+0

我喜欢这种方法,但它说999.12345.0.0001是IPv4,它不能识别签约的IPv6地址: -/ –

+0

给了我一点点,我会尽量让答案更新以处理约定的IPv6格式,并且为IPv4地址格式中的每个IP块添加有效性检查。 –

+0

已更新为包含IPv4地址范围有效性检查 –

1

这似乎是可以通过使用正则表达式轻松完成的事情。卢阿有很多正则表达式库。

但是,如果你不愿意或无法使用他们,我会做这样的事情:

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代码,因为它看起来像功课/学习锻炼; Tibial完整的答案会对你有害,而不是对你有所帮助。

+0

感谢,但没有塔的t实际上是lua代码,所以如果你能想到一个完整的代码,它将无法工作。 –

+1

我以为我说得很清楚。它是伪代码 - 您需要将其转换为真实的lua源代码。 –

+0

我认为帮助请求是显而易见的,我知道如何做4个任务中的2个,但我坚持过滤ipv6,因为有三种可能的方式,包含信息的字符串可能是一个有效的地址和数量:我想要一个意见,如果只是检查3。并且所有数字对于ipv4都是足够的,如果你可以提供一些信息,那么如果没有其他任何人在那里,这将是有帮助的? –

5

迈克的解决方案很好,但它可以通过几种方式进行改进。在目前的形式下,它没有进入ipv6地址检查,但它很容易修复。 ipv6检查失败,如"[email protected]$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 

    -- 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 trailing chars 
    local chunks = {ip:match(("([a-fA-F0-9]*):"):rep(8):gsub(":$","$"))} 
    if #chunks == 8 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",  -- invalid ipv4 
    "1050:0:0:0:5:600:300c:326b",    -- ipv6 
    "[email protected]$300c#326b",    -- string 
    "1050:0:0:0:5:600:300c:326babcdef",   -- string 
    "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 

和输出:

128.1.0.1 IPv4 
223.255.254.254 IPv4 
999.12345.0.0001 string 
1050:0:0:0:5:600:300c:326b IPv6 
[email protected]$300c#326b string 
1050:0:0:0:5:600:300c:326babcdef string 
1050:0000:0000:0000:0005:0600:300c:326b IPv6 
1050:::600:5:1000:: IPv6 
129.garbage.9.1 string 
129.1 Error 
+2

谢谢!我会尝试在瑞典语维基百科上使用这个模板。这正是我所期待的! –

+0

完美!它也匹配localhost :: 1和许多其他。现在它也被用在葡萄牙维基百科上。 :) –

+1

这个或解决方案标记为接受的答案处理地址前缀/后缀随机垃圾(例如'xxx127.0.0.0'被认为是有效的)。 Imho'^ $'符号应该添加到模式中。 – JeFf

0

有趣的是,上述答案都没有采用原始q的测试例子题目了进去,因为使用它们,所有上述检查将失败(因为#3):

fe80:0000:0000:0000:0202:b3ff:fe1e:8329 
fe80:0:0:0:202:b3ff:fe1e:8329 
fe80::202:b3ff:fe1e:8329 (!) 

IPv6的表示规则说:

一个或多个零值的连续基团可以是使用两个连续的冒号(::),1替换为一个空组,但替换只能在地址中应用一次,因为多次出现会产生模糊表示。 https://en.wikipedia.org/wiki/IPv6_address#Representation

随着Lua的模式不具备Alternation支持,这是不可能的,了解IPv6与单一模式。您可能会看到大卫·M·Syzdek回答关于IPv6的正则表达式的复杂性:https://stackoverflow.com/a/17871737/1895269

不过,更符合标准的做法是保罗Kulchenko的回答如下改进:

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 max 8 'chunks' of numbers/letters 
    local addr = ip:match("^([a-fA-F0-9:]+)$") 
    if addr ~= nil and #addr > 1 then 
    -- address part 
    local nc, dc = 0, false  -- chunk count, double colon 
    for chunk, colons in addr:gmatch("([^:]*)(:*)") do 
     if nc > (dc and 7 or 8) then return R.STRING end -- max allowed chunks 
     if #chunk > 0 and tonumber(chunk, 16) > 65535 then 
     return R.STRING 
     end 
     if #colons > 0 then 
     -- max consecutive colons allowed: 2 
     if #colons > 2 then return R.STRING end 
     -- double colon shall appear only once 
     if #colons == 2 and dc == true then return R.STRING end 
     if #colons == 2 and dc == false then dc = true end 
     end 
     nc = nc + 1  
    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", -- invalid ipv4 
    "1050:0:0:0:5:600:300c:326b",   -- ipv6 
    "[email protected]$300c#326b",   -- string 
    "1050:0:0:0:5:600:300c:326babcdef",  -- string 
    "1050:0000:0000:0000:0005:0600:300c:326b", -- ipv6 
    "1050:::600:5:1000::", -- contracted ipv6 (invalid) 
    "fe80::202:b3ff:fe1e:8329", -- shortened ipv6 
    "fe80::202:b3ff::fe1e:8329", -- shortened ipv6 (invalid) 
    "fe80:0000:0000:0000:0202:b3ff:fe1e:8329:abcd", -- too many groups 
    "::1", -- valid IPv6 
    "::", -- valid IPv6 
    ":", -- string 
    "129.garbage.9.1", -- string 
    129.10  -- error 
} 
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  string 
1050:0:0:0:5:600:300c:326b  IPv6 
[email protected]$300c#326b  string 
1050:0:0:0:5:600:300c:326babcdef  string 
1050:0000:0000:0000:0005:0600:300c:326b IPv6 
1050:::600:5:1000::  string 
fe80::202:b3ff:fe1e:8329  IPv6 
fe80::202:b3ff::fe1e:8329  string 
fe80:0000:0000:0000:0202:b3ff:fe1e:8329:abcd string 
::1  IPv6 
::  IPv6 
:  string 
129.garbage.9.1 string 
129.1 Error 
相关问题