IPv6 缩写(零块压缩)逻辑。我正在使用 C#

IPv6 Abbreviation(zero blocks compression) logic. I'm using c#

这是一个完整的未压缩 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 中所有零的块,但只有一个应该被缩写。

比我预期的要棘手得多,但在这里您找到了使用正则表达式来完成它的方法:

        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");
        }

如果您想在不使用 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、span 等),但这提供了一个想法。有关优化的参考,您可以查看.net core 中 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();
}

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