我正在重构我的代码并希望使用IPAddress.TryParse
方法验证字符串是否是有效的IPv4地址而不是使用正则表达式:
public static bool IsIPv4(string value)
{
IPAddress address;
if (IPAddress.TryParse(value, out address))
{
if (address.AddressFamily == AddressFamily.InterNetwork)
{
return true;
}
}
return false;
}
我的单元测试现在失败了,因为这些输入值返回true
并被解析为以下IPAddress
个对象:
value = "0.0.0.0" -> address = {0.0.0.0}
value = "255.255.255" -> address = {255.255.0.255}
value = "65536" -> address = {0.1.0.0}
这有意义吗?我可以看到0.0.0.0
在技术上是一个有效的IPv4地址,即使用户输入它也没有意义。那两个呢?为什么他们以他们的方式进行转换,我应该将它们视为有效,即使它对用户可能不透明,也可能只是忘记输入句点(65536
而不是6.5.5.36
)。
非常感谢任何帮助。
答案 0 :(得分:21)
IPAddress.TryParse()的工作不是检查字符串是是否是有效的IP地址,而是否可以解析字符串的内容 (即;转换)到有效的IP地址。
您的测试用例中的所有选项实际上都可以解析为表示和IP。它归结为您的测试用例是有效的。问题是您的测试用例的数据无效,或者您没有在测试用例中使用正确的工具来获得预期的结果。
如果你专门测试一个有效的IPv4,只有4个四边形(每个是一个0到255之间的整数),并且想要避免正则表达式,你可以改为拆分然后解析并验证。
public static bool IsIPv4(string value)
{
var quads = value.Split('.');
// if we do not have 4 quads, return false
if (!(quads.Length==4)) return false;
// for each quad
foreach(var quad in quads)
{
int q;
// if parse fails
// or length of parsed int != length of quad string (i.e.; '1' vs '001')
// or parsed int < 0
// or parsed int > 255
// return false
if (!Int32.TryParse(quad, out q)
|| !q.ToString().Length.Equals(quad.Length)
|| q < 0
|| q > 255) { return false; }
}
return true;
}
答案 1 :(得分:9)
看起来IPAddress.Parse
的文档通过指出输入更少的部分来方便输入A类和B类地址来使这种行为合理化。如果你想强制使用一个由四部分组成的地址,你可能只想检查地址中有三个句点,然后再将它提供给IPAddress.TryParse
,我猜。
一些代码供您参考:
// verify that IP consists of 4 parts
if (value.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries).Length == 4)
{
IPAddress ipAddr;
if (IPAddress.TryParse(value, out ipAddr))
{
// IP is valid
}
else
// invalid IP
}
else
// invalid IP
答案 2 :(得分:6)
如果您想对输入非常严格,那么您可以比较解析后的ToString()
的{{1}}版本,如果输入不同,则拒绝输入。
全零地址和其他此类事情必须作为特殊情况处理。
答案 3 :(得分:5)
我建议:
public bool IsValidIp(string addr)
{
IPAddress ip;
bool valid = !string.IsNullOrEmpty(addr) && IPAddress.TryParse(addr, out ip);
return valid;
}
答案 4 :(得分:4)
public static bool IsIPv4(string ipAddress)
{
return Regex.IsMatch(ipAddress, @"^\d{1,3}(\.\d{1,3}){3}$") &&
ipAddress.Split('.').SingleOrDefault(s => int.Parse(s) > 255) == null;
}
其他答案要么允许IPv6,要么允许输入“1.-0.1.1”。
答案 5 :(得分:2)
ipString中的部分数量(每个部分用句点分隔)决定了IP地址的构造方式。单部分地址直接存储在网络地址中。两部分地址,便于指定A类地址,将前导部分放在网络地址的最右边三个字节的第一个字节和尾部。三部分地址,便于指定B类地址,将第一部分放在第一个字节中,第二部分放在第二个字节中,最后部分放在网络地址的最右边两个字节中。例如:
零件数量和示例ipString IP地址的IPv4地址
1 - “65536” 0.0.255.255
2 - “20.2” 20.0.0.2
2 - “20.65535” 20.0.255.255
3 - “128.1.2” 128.1.0.2
您可能需要参考MSDN文档 http://msdn.microsoft.com/en-us/library/system.net.ipaddress.parse.aspx
您最好的选择是IPAddress.ToString()或正则表达式。
答案 6 :(得分:1)
是的,这些是有效的地址。有关详细信息,请参阅http://en.wikipedia.org/wiki/IPv4#Address_representations。
答案 7 :(得分:1)
尽管这个问题在两年前得到了解答,但我认为提出我今天在寻找同样的事情时想出的问题是相关的,在找到这个页面之后我决定我太懒了进行验证。
如果通过Form
和TextBox
接受信息,则最好使用MaskedTextBox
。您可以强制用户以IP地址格式输入信息,而不必自己进行猜测。
用于此类验证的掩码是990.990.990.990
,其中OptionalNumber, OptionalNumber, MandatoryNumber
表示1.1.1.1
,10.10.10.10
和123.123.123.123
都是有效的IP地址格式。这些掩码与Microsoft在Access中使用的格式相同。
答案 8 :(得分:0)
这是有道理的,因为65536等于0x00010000或0.1.0.0。我猜TryParse也会接受十六进制数字。无论如何,我认为你不想接受普通用户的这样的价值,但我想这取决于最终用户。
答案 9 :(得分:0)
以下代码使用正则表达式,由 Roshe
建议 string txt = textBox1.Text;
string ValidIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"; // IP validation
Regex r = new Regex(ValidIpAddressRegex, RegexOptions.IgnoreCase | RegexOptions.Singleline);
Match m = r.Match(txt);
if (!m.Success)
{
//Not a valid IP
}
else
{
//A valid IP
}