3

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.

4

4 回答 4

2

来自 std.socket 的 parseAddress怎么样?

于 2012-02-23T02:43:03.920 回答
1

@tjameson:很久以前,我已经破解了我自己的uri模块。这是代码:http ://codepad.org/PBm5BEVP 。我一直想回到那个模块,改进它,然后在 GitHub 上提交一个拉取请求,但从来没有时间这样做...... URI RFC 还有一个用于解析 URI 中的 IPv6 地址的正则表达式,这绝对是我会输入这段代码。

于 2012-02-22T23:15:27.470 回答
0

您可以使用操作系统提供的 inet_pton() 函数。它会解析一个地址并告诉你它是否错误。见http://www.kernel.org/doc/man-pages/online/pages/man3/inet_pton.3.html

它将解析 IPv4 和 IPv6 地址,并且 inet_ntop() 可用于将解析后的地址转换回其规范表示法。

于 2012-02-22T21:56:32.747 回答
0

尝试:

IPv4

/^(((2[0-4]|1\d|[1-9])?\d|25[0-5])(\.(?!$)|$)){4}$

IPv6

/^((?=(?=(.*?::))\2(?!.+::))(::)?([\dA-F]{1,4}:(:|(?!$))|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:(?!$)|$))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])(\.(?!$)|$)){4})$/i

(使用 ECMAscript 语法)

来自: http ://home.deds.nl/~aeron/regex/

于 2012-03-16T21:06:17.667 回答