6

空白でトリミングされた文字列を渡すことができる関数が
欲しいのですが、エラーの場合は0(文字列ではない)を返します。ipv4の場合は1、ipv6の場合は2、ipではない文字列の場合は3を返します。

Ipv6には次のルールがあります。

Ipv6は、コロン(:)で区切られた16ビット16進値の8つのグループで表されます
。16進数字は大文字と小文字を区別 しません。省略
規則:
1:16ビット値の先行ゼロを省略します
。2:連続するゼロの1つ以上のグループを次のように置き換えます。二重コロン

すべて同じipv6である3つの方法を示すwikiの例:

fe80:0000:0000:0000:0202:b3ff:fe1e:8329
fe80:0:0:0:202:b3ff:fe1e:8329
fe80::202:b3ff:fe1e:8329 

私はあなたがちょうど3つをチェックするipv4のために合理的に確信しています。次に、文字列がすべての
数値であり、。が数値としてカウントされ、文字列のみの最後のチェックが
ifステートメントの最後にあることを確認します。したがって、ipv4 / 6でなく、文字列である場合 は、
3を返します 。

4

5 に答える 5

9

マイクのソリューションは優れていますが、いくつかの方法で改善できます。現在の形式では、ipv6アドレスチェックは行われませんが、修正は簡単です。ipv6チェックは、and(両方を有効なアドレスとして認識する)および(文字列として認識する)などで失敗"1050!0!0+0-5@600$300c#326b""1050:0:0:0:5:600:300c:326babcdef"ます"1050:::600:5:1000::"

改善されたバージョンは次のとおりです(IPv4は10進数であり、IPv6は16進数であると想定されています)。

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

チェックするスクリプト:

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

そして出力:

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のチェックが追加されました。これにより、2つの連続するコロンの1つの空のグループで8グループ未満が可能になります。

于 2013-05-20T06:17:16.710 に答える
4

これは解決すべきかなり基本的な問題のようです。私はこの関数があなたが必要とすることをするだろうと思います...

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は個人的なコード作成サービスではありません。しかし、あなたが新しく見えるので、私はあなたに疑いの利益を与えます、そしてこれは潜在的に他の人々に利益をもたらすかもしれない何かです。上記のコードは基本的なものなので、わからないフリンジテストケースが見つからない場合は、遠慮なく更新してください。

于 2012-06-11T16:36:26.433 に答える
2

これは、正規表現を使用して簡単に実行できるもののようです。lua用の正規表現ライブラリはたくさんあります。

ただし、それらを使用する意思がない、または使用できない場合は、次のようにします。

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コードを投稿していません。

于 2012-06-11T07:34:40.210 に答える
1

興味深いことに、上記の回答はいずれも元の質問のテスト例を考慮に入れていません。これらを使用すると、上記のすべてのチェックが失敗するためです(#3のため)。

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

IPv6表現ルールによると:

ゼロ値の1つ以上の連続するグループは、2つの連続するコロン(::) 1を使用して、単一の空のグループに置き換えることができますが、複数回出現するとあいまいな表現が作成されるため、置換はアドレスで1回だけ適用できます。 https://en.wikipedia.org/wiki/IPv6_address#Representation

LuaパターンはAlternationをサポートしていないため、単一のパターンでIPv6をチェックすることはできません。IPv6正規表現の複雑さに関するDavidM.Syzdekの回答が表示される場合があります:https ://stackoverflow.com/a/17871737/1895269

それでも、より標準に準拠したアプローチは、PaulKulchenkoの回答を次のように改善したものです。

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
  "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
  "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
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
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
于 2017-07-12T10:55:55.543 に答える
0

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

編集:ip_type()OPの要求に応じて関数の出力を変更しました。

于 2020-07-22T12:45:34.370 に答える