D-如何验证IP地址是否有效
我正在编写一个 HTTP 解析库(因为我在纯 D 中找不到一个好的解析库),并且我需要能够验证 IP 地址(对于 URI 字段),因此我编写了几个函数来验证 IP 地址:
对于 IPv4:
bool isIPv4(string addr) {
int parts;
ulong idx;
foreach (i, c; addr) {
if (c == '.') {
if (i == 0) {
return false;
}
if (to!int(addr[idx..i]) > 255) {
return false;
}
parts++;
if (parts > 3) {
return false;
}
idx = i + 1;
} else if (!isDigit(c)) {
return false;
}
}
if (to!int(addr[idx..addr.length]) > 255) {
return false;
}
if (parts != 3) {
return false;
}
return true;
}
对于 IPv6:
bool isIPv6(string addr) {
bool isColon, hasSeparator, hasIPv4;
int leftChunks, rightChunks, digits;
foreach (i, c; addr) {
if (isHexDigit(c)) {
digits = isColon ? 1 : digits + 1;
isColon = false;
if (digits == 1) {
if (hasSeparator) {
rightChunks++;
} else {
leftChunks++;
}
} else if (digits > 4) {
return false;
}
} else if (c == ':') {
if (isColon) {
// multiple :: separators not allowed
// as is :::
if (hasSeparator) {
return false;
}
hasSeparator = true;
} else {
isColon = true;
}
} else if (c == '.') {
if (hasSeparator) {
rightChunks--;
} else {
leftChunks--;
}
if (!isIPv4(addr[i - digits .. addr.length])) {
return false;
}
hasIPv4 = true;
break;
}
}
if (hasIPv4) {
if (hasSeparator) {
if (rightChunks + leftChunks > 5) {
return false;
}
} else if (leftChunks != 6) {
return false;
}
} else if (digits > 0) {
if (hasSeparator) {
if (rightChunks + leftChunks > 7) {
return false;
}
} else if (leftChunks != 8) {
return false;
}
}
return true;
}
我最初尝试为 IPv6 制作一个正则表达式,但这很痛苦,特别是因为有很多特殊情况(::
),而且我想我遇到了正则表达式编译错误,因为它太长了。显然,我想使用一些标准函数来为我做到这一点。
FWIW,我使用 std.arrays.split 实现了 IPv4 验证器,然后我决定这样做,因为否则我将不得不检测或捕获 std.conv.to!int 的异常。
非常感谢!
注意
我最终想尝试将我编写的一些代码写入 Phobos,所以我希望代码尽可能可靠。
I'm writing an HTTP parsing library (because I couldn't find a good one in pure D), and I needed to be able to validate IP addresses (for the URI field), so I wrote a couple functions to validate IP addresses:
For IPv4:
bool isIPv4(string addr) {
int parts;
ulong idx;
foreach (i, c; addr) {
if (c == '.') {
if (i == 0) {
return false;
}
if (to!int(addr[idx..i]) > 255) {
return false;
}
parts++;
if (parts > 3) {
return false;
}
idx = i + 1;
} else if (!isDigit(c)) {
return false;
}
}
if (to!int(addr[idx..addr.length]) > 255) {
return false;
}
if (parts != 3) {
return false;
}
return true;
}
And for IPv6:
bool isIPv6(string addr) {
bool isColon, hasSeparator, hasIPv4;
int leftChunks, rightChunks, digits;
foreach (i, c; addr) {
if (isHexDigit(c)) {
digits = isColon ? 1 : digits + 1;
isColon = false;
if (digits == 1) {
if (hasSeparator) {
rightChunks++;
} else {
leftChunks++;
}
} else if (digits > 4) {
return false;
}
} else if (c == ':') {
if (isColon) {
// multiple :: separators not allowed
// as is :::
if (hasSeparator) {
return false;
}
hasSeparator = true;
} else {
isColon = true;
}
} else if (c == '.') {
if (hasSeparator) {
rightChunks--;
} else {
leftChunks--;
}
if (!isIPv4(addr[i - digits .. addr.length])) {
return false;
}
hasIPv4 = true;
break;
}
}
if (hasIPv4) {
if (hasSeparator) {
if (rightChunks + leftChunks > 5) {
return false;
}
} else if (leftChunks != 6) {
return false;
}
} else if (digits > 0) {
if (hasSeparator) {
if (rightChunks + leftChunks > 7) {
return false;
}
} else if (leftChunks != 8) {
return false;
}
}
return true;
}
I tried initially to craft a regex for IPv6, but that was painful, especially since there are so many special cases (the ::
), and I think I ran into a regex compile bug because it was so long. Obviously, I would like to use some standard function to do this for me.
FWIW, I had the IPv4 validator implemented using std.arrays.split, then I decided to just do it this way, because otherwise I would have to detect or catch exceptions from std.conv.to!int.
Thanks so much!
Note
I would eventually like to try to get some of the code I've written into Phobos, so I would like the code to be as solid as possible.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
从 std.socket 解析地址怎么样?
How about parseAddress from std.socket?
@tjameson:很久以前我就破解了我自己的
uri
模块。这是代码: http://codepad.org/PBm5BEVP 。我一直想回到那个模块,改进它,并在 GitHub 上提交拉取请求,但从来没有时间这样做……URI RFC 也有一个正则表达式,用于解析 URI 内的 IPv6 地址,这绝对是东西我会输入这段代码。@tjameson: Long, ago I've hacked my own
uri
module. Here is the code: http://codepad.org/PBm5BEVP . I always wanted to go back to that module, improve it, and submit a pull request at GitHub, but never had time to do it... The URI RFC also has a regular expression for parsing IPv6 addresses inside URIs, that is definitely something I would put in this code.您可以使用操作系统提供的 inet_pton() 函数。它会解析一个地址并告诉你它是否错误。请参阅 http://www.kernel.org/ doc/man-pages/online/pages/man3/inet_pton.3.html
它将解析 IPv4 和 IPv6 地址,并且 inet_ntop() 可用于将解析后的地址转换回其规范表示法。
You could use the OS provided inet_pton() function. It will parse an address and tell you if it's wrong. See http://www.kernel.org/doc/man-pages/online/pages/man3/inet_pton.3.html
It will parse both IPv4 and IPv6 addresses, and inet_ntop() can be used to convert the parsed address back to its canonical notation.
尝试:
IPv4
IPv6
(使用 ECMAscript 语法)
来自:
http://home.deds.nl/~aeron/regex/
Try:
IPv4
IPv6
(Using ECMAscript syntax)
From:
http://home.deds.nl/~aeron/regex/