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
这是一个完整的未压缩 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