【问题标题】:IPv6 Abbreviation(zero blocks compression) logic. I'm using c#IPv6 缩写(零块压缩)逻辑。我正在使用 C#
【发布时间】:2015-09-19 04:17:12
【问题描述】:

这是一个完整的未压缩 IP 地址 2001:0008:0000:CD30:0000:0000:0000:0101 我需要像这样压缩它 2001:8:0:CD30::101 但我只能像这样压缩块中的零 2001:8:0:CD30:0:0:0:101 使用此代码

 string output = "";
        string a = textBox1.Text;
        if (a.Length != 39  )
            MessageBox.Show("Invalid IP please enter the IPv6 IP in this format 6cd9:a87a:ad46:0005:ad40:0000:5698:8ab8");
        else
        {
            for (int i = 0; i < a.Length; i++)
            {
                if ((a[i] >= '1' && a[i] <= '9') || (Char.ToLower(a[i]) >= 'a' && Char.ToLower(a[i]) <= 'f') || ((i + 1) % 5 == 0 && a[i] == ':'))
                {
                    output = output + a[i];
                }
                else if ((a[i]=='0' && a[i-1]==':') || (a[i]=='0' && a[i-1]=='0' && a[i-2]==':') || (a[i]=='0' && a[i-1]=='0' && a[i-2]=='0' && a[i-3]==':')) 
                {

                }
                else if (a[i] == '0')
                {
                    output = output + a[i];
                }

                else
                {
                    MessageBox.Show("Invalid IP please enter the IPv6 IP in this format 6cd9:a87a:ad46:0005:ad40:0000:5698:8ab8");
                }
            }

            textBox2.Text = output;
        }

我正在使用 c#,但我只需要有关如何删除整个零块的编程逻辑问题是可能有超过 1 组包含 ip 中所有零的块,但只有一个应该缩写。

【问题讨论】:

  • 你只需要去掉多余的 0 对吗?
  • 是的,但问题是如果 IP 是这样的 2001:0000:0000:CD30:0000:0000:0000:a141 那么它将被缩写成这样 2001:0:0:CD30::a141和 nt 像这样 2001::CD30:0:0:0:a141 这意味着在 ip 中,整个零块只能压缩为两个冒号一次而且它必须来自连续的零块数量更多的地方,例如上面的示例 3 个零块被压缩,而其他块没有。
  • 好的,所以问题是最后一个不遵守规则的“块”
  • @Balder,参见 RFC 5952,第 4.2.3 节:tools.ietf.org/html/rfc5952#section-4.2.3,“当在放置“::”时有替代选择时,最长的连续 16 位 0字段必须缩短(即在 2001:0:0:1:0:0:0:1 中缩短三个连续零字段的序列)。当连续 16 位 0 字段的长度相等时(即, 2001:db8:0:0:1:0:0:1),第一个零位序列必须缩短。例如,2001:db8::1:0:0:1 是正确的表示。"

标签: c# ip logic ipv6 abbreviation


【解决方案1】:

比我预期的要复杂得多,但是在这里你可以使用正则表达式来做到这一点:

        private static string Compress(string ip)
        {
            var removedExtraZeros = ip.Replace("0000","*");

            //2001:0008:*:CD30:*:*:*:0101
            var blocks = ip.Split(':');

            var regex = new Regex(":0+");
            removedExtraZeros = regex.Replace(removedExtraZeros, ":");


            //2001:8:*:CD30:*:*:*:101

            var regex2 = new Regex(":\\*:\\*(:\\*)+:");
            removedExtraZeros = regex2.Replace(removedExtraZeros, "::");
            //2001:8:*:CD30::101

            return removedExtraZeros.Replace("*", "0");
        }

【讨论】:

  • 非常感谢它的作品和它的真棒但是请你解释一下这行 var regex2 = new Regex(":\*:\*(:\*)+:");它实际上在做什么??
  • 嗨,你可以看到我用 替换了第一步中的“压缩零”,在第二步中(从块中删除左边的 0)不会乱来。在第三步中,我只寻找正则表达式的块,我正在寻找以 ::* 开头的块,至少有一个或多个 :* 块并以 : 结尾
  • 我没有选择非常明智的用 替换 0 块,因为 * 是一个正则表达式元字符,当使用元字符时,你必须用 \ 转义它,但要让字符串理解它,你必须使用 \\METACHAR。如果我使用“o”而不是“”,那么正则表达式 2 会很简单:new Regex(":o:o(:o)+:");
【解决方案2】:

如果您想在不使用Regex 的情况下获得相同的结果:

public string Compress(string value)
{
    var values = value.Split(",");
    var ints = values.Select(i => int.Parse(i, System.Globalization.NumberStyles.HexNumber));
    var result = ints.Select(Conversion.Hex);
    return string.Join(":", result);
}

没有花时间进行微优化(stackalloc、spans 等),但这给出了一个想法。有关优化的参考,您可以查看 .net 核心中IPAddress.Parse 的实现。请注意IPAddress.Parse 的结果将给出与上述示例不同的结果:

Compress        -> 2001:8:0:CD30:0:0:0:101 
IPAddress.Parse -> 2001:8:0:cd30::101

这可以通过进入一些对象和其他想法来“清理”。

编辑:

在与我的一位同事聊天后,我花了一些时间写了一个“优化”版本。我没有花时间清理代码,所以也许未来的编辑之一会更干净。

public string Compress(string value)
{
    Span<char> chars = stackalloc char[value.Length];
    const char zero = '0';
    const char colon = ':';
    int index = 0;
    int positionInSegment = 0;
    bool startsWithZero;

    while (index < _originalValue.Length)
    {
        startsWithZero = value[index] == zero && positionInSegment == 0;
        positionInSegment++;
        if (startsWithZero)
        {
            if (index == value.Length - 1)
            {
                chars[index] = zero;
                break;
            }
                        
            if (value[index + 1] == colon)
            {
                chars[index] = zero;
                positionInSegment = 0;
                index++;
                continue;
            }
                        
            positionInSegment = 0;
            index++;
            continue;
        }

        if (value[index] == colon)
        {
            positionInSegment = 0;
            chars[index] = colon;
            index++;
            continue;
        }
                    
        chars[index] = value[index];
        index++;
    }

    return chars.ToString();
}

我还创建了一个公共要点以供将来参考: https://gist.github.com/DeanMilojevic/7b4f1d060ce8cfa191592694b11234d7

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-01
    • 1970-01-01
    • 2014-01-04
    • 1970-01-01
    • 2011-10-26
    • 2017-11-09
    • 1970-01-01
    • 2021-01-19
    相关资源
    最近更新 更多