可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm refactoring my code and wanted to use the IPAddress.TryParse
method to validate if a string is a valid IPv4 address instead of using regular expressions:
public static bool IsIPv4(string value)
{
IPAddress address;
if (IPAddress.TryParse(value, out address))
{
if (address.AddressFamily == AddressFamily.InterNetwork)
{
return true;
}
}
return false;
}
My unit test is now failing because these input values return true
and get parsed to the following IPAddress
objects:
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}
Does this make sense? I can see that 0.0.0.0
is technically a valid IPv4 address, even if it makes no sense for the user to enter that. What about the other two? Why are they converted in the way they are and should I treat them as valid even if it might not be transparent for the user, who maybe just forgot to enter the periods (65536
instead of 6.5.5.36
).
Any help is most appreciated.
回答1:
It looks like the docs for IPAddress.Parse
rationalize this behavior by pointing out that entering fewer parts is convenient for entering class A and B addresses. If you want to force a four-part address, you might just want to check that there are three periods in the address before feeding it to IPAddress.TryParse
, I guess.
Some code for your reference:
// 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:
The job of IPAddress.TryParse() is not to check if the string is a valid IP address, but whether or not the content of the string can be parsed (i.e.; converted) to a valid IP address.
All of the options in your test cases can in fact be parsed to represent and IP. What it comes down to is that your test cases are valid. The issue is that the data for your test cases are not valid, or you're not using the right tool(s) in your test case to get the expected result.
If you're specifically testing for a valid IPv4, with exactly 4 quads (each being an integer between 0 - 255), and want to avoid regex your could instead split then parse and validate.
public static bool IsIPv4(string value)
{
var octets = value.Split('.');
// if we do not have 4 octets, return false
if (octets.Length!=4) return false;
// for each octet
foreach(var octet in octets)
{
int q;
// if parse fails
// or length of parsed int != length of octet string (i.e.; '1' vs '001')
// or parsed int < 0
// or parsed int > 255
// return false
if (!Int32.TryParse(octet, out q)
|| !q.ToString().Length.Equals(octet.Length)
|| q < 0
|| q > 255) { return false; }
}
return true;
}
回答3:
If you want to be very strict about your input, then you can compare the ToString()
version of the parsed IPAddress
, and reject the input if they are different.
The all-zero address, and other such things, would have to be handled as special cases.
回答4:
I suggest:
public bool IsValidIp(string addr)
{
IPAddress ip;
bool valid = !string.IsNullOrEmpty(addr) && IPAddress.TryParse(addr, out ip);
return valid;
}
回答5:
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;
}
Other answers either allow IPv6 or allow input like "1.-0.1.1".
回答6:
The number of parts (each part is separated by a period) in ipString determines how the IP address is constructed. A one part address is stored directly in the network address. A two part address, convenient for specifying a class A address, puts the leading part in the first byte and the trailing part in the right-most three bytes of the network address. A three part address, convenient for specifying a class B address, puts the first part in the first byte, the second part in the second byte, and the final part in the right-most two bytes of the network address. For example:
Number of parts and example ipString
IPv4 address for IPAddress
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
You may want to refer MSDN documentation
http://msdn.microsoft.com/en-us/library/system.net.ipaddress.parse.aspx
Your best bet will be IPAddress.ToString() or regular expressions.
回答7:
Yes, those are valid addresses. See http://en.wikipedia.org/wiki/IPv4#Address_representations for more information.
回答8:
Although this question was answered like two years ago, I think it is relevant to bring up what I figured out when I was looking for the same thing today, and after finding this page decided I was far too lazy to go through all the validation progmatically.
If the information is being accepted through a Form
and a TextBox
, it would be in your best interest to use a MaskedTextBox
instead. You can force the user to put in information in IP Address format instead of having to do the guesswork yourself.
The mask to be used for such validation is 990.990.990.990
which says OptionalNumber, OptionalNumber, MandatoryNumber
because 1.1.1.1
, 10.10.10.10
, and 123.123.123.123
are all valid IP Address formats. The masks are the same format that Microsoft uses in Access.
回答9:
It makes sense, as 65536 is equal to 0x00010000, or 0.1.0.0. I'm guessing TryParse will also accept hex numbers. In any case, I don't think that you'd want to accept such a value from a normal user, but I suppose that depends on the end user.
回答10:
The below code is using regex, suggested by 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
}