如何在C ++中验证字符串是否为有效的IPv4地址?

时间:2008-11-25 17:37:30

标签: c++ string

我不需要验证IP地址是否可访问或类似的任何内容。我只是想验证该字符串是否为dotted-quad(xxx.xxx.xxx.xxx)IPv4格式,其中xxx介于0和255之间。

17 个答案:

答案 0 :(得分:51)

您可能需要inet_pton,其中无效AF参数返回-1,无效地址返回0,有效IP地址返回+1。它支持IPv4和未来的IPv6地址。如果您仍需要编写自己的IP地址处理,请记住标准的32位十六进制数是有效的IP地址。并非所有IPv4地址都采用点分十进制表示法。

此功能既可以验证地址,也可以在相关的套接字调用中使用相同的地址。

答案 1 :(得分:44)

Boost.Asio提供了课程ip::address。如果您只想验证字符串,可以像这样使用它:

std::string ipAddress = "127.0.0.1";
boost::system::error_code ec;
boost::asio::ip::address::from_string( ipAddress, ec );
if ( ec )
    std::cerr << ec.message( ) << std::endl;

这也适用于十六进制和八进制四边形。这也是一种更便携的解决方案。

答案 2 :(得分:34)

我解决的解决方案是:

bool Config::validateIpAddress(const string &ipAddress)
{
    struct sockaddr_in sa;
    int result = inet_pton(AF_INET, ipAddress.c_str(), &(sa.sin_addr));
    return result != 0;
}

这适用于其他答案中提到的大多数情况。它无法识别具有八进制或十六进制格式的IP地址,但这对我的应用程序来说是可接受的。

答案 3 :(得分:17)

这看起来很简单,但有一些陷阱。例如,前面答案中公布的许多解决方案都假设四边形位于基数10中 - 但以零开头的四边形必须被视为基数8(八进制)数,因此例如任何以零开头并包含数字8或9的四边形部分无效。即,IP号192.168.1.010 192.168.1.10但实际上是192.168.1.8,并且IP号192.168.019.14自第三个四元组起无效包含无效的基数8位9。

我强烈建议您使用操作系统或编译器环境中包含的套接字库提供的功能。

编辑:(认为它是隐含的,但是)当然,你也可以使用十六进制四边形,一个la 192.168.1.0x0A用于192.168.1.10,当然你可以使用鞋面快乐地混合和匹配你的虐待狂内容小写,la 0xC0.0xa8.1.010为192.168.1.8。如果你想玩得开心,请尝试使用ping的一些例子。这可以很好地跨平台工作(在Linux,NetBSD和Win32下发誓的同时测试一段时间。)

进一步编辑以响应KaluSingh Gabbar的请求:例如,您可以将192.168.1.10指定为0xc0a8010a,它仍然代表有效的IP号码,la:

[mihailim@home ~]$ ping 0xc0a8010a
PING 0xc0a8010a (192.168.1.10) 56(84) bytes of data.
^C
--- 0xc0a8010a ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2479ms

答案 4 :(得分:8)

这是一种简单明了的方法。

bool IsIPAddress(std::string & ipaddr)
    {    

    StringTokenizer quads(ipaddr,".");

    if (quads.countTokens() != 4) return false;

    for (int i=0; i < 4; i++)
      {
      std::string quad = quads.nextToken();
      for (int j=0; j < quad.length(); j++
         if (!isdigit(quad[j])) return false;

      int quad = atoi(quads.GetTokenAt(i));
      if (quad < 0) || (quad > 255)) return false;
      }

    return true;
    }

答案 5 :(得分:5)

如果你在Windows上,你可以使用WSAStringToAddress并根据我们知道的返回值,如果传递的参数是有效的IP。这支持IPv4和&amp;从Windows 2000开始的IPv6。

答案 6 :(得分:2)

Boost.Regex是合适的。

bool validate_ip_address(const std::string& s)
{
   static const boost::regex e("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
   return regex_match(s, e);
}

答案 7 :(得分:2)

如果您想自己编写,而不是使用库,那么

atoi()将字符转换为int将让你测试每个数字的范围,并在“。”之间测试一些strcmp。您还可以进行一些快速检查,例如字符串的长度(应少于16个字符(不包括空终止符),点数等。

但是,使用现有代码可能会更容易。

答案 8 :(得分:2)

我只使用C stdlib函数完成了同样的操作,尽管它不支持如上所述的八进制四边形,但这应该不是问题,我可以轻松添加该部分并将其提供给您。作为初学者(学生),我甚至不知道直到现在才能在你的ip中得到一个八进制数。我认为它必须是小数。

答案 9 :(得分:2)

这是验证给定IPV4地址的C程序。我假设IP地址是十进制格式。请告诉我你对此的看法。

  // strTokenFunction.cpp : Check if the specified address is a valid numeric IP address.
  // This function is equavalent to the IPAddress.TryParse() method in C#

#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
#include <string.h>

bool isValidIpAddress(char *st)
{
    int num, i, len;
    char *ch;

    //counting number of quads present in a given IP address
    int quadsCnt=0;

    printf("Split IP: \"%s\"\n", st);

    len = strlen(st);

    //  Check if the string is valid
    if(len<7 || len>15)
        return false;

    ch = strtok(st, ".");

    while (ch != NULL) 
    {
        quadsCnt++;
        printf("Quald %d is %s\n", quadsCnt, ch);

        num = 0;
        i = 0;

        //  Get the current token and convert to an integer value
        while(ch[i]!='\0')
        {
            num = num*10;
            num = num+(ch[i]-'0');
            i++;
        }

        if(num<0 || num>255)
        {
            printf("Not a valid ip\n");
            return false;
        }

        if( (quadsCnt == 1 && num == 0) || (quadsCnt == 4 && num == 0))
        {
            printf("Not a valid ip, quad: %d AND/OR quad:%d is zero\n", quadsCnt, quadsCnt);
            return false;
        }

        ch = strtok(NULL, ".");
    }

    //  Check the address string, should be n.n.n.n format
    if(quadsCnt!=4)
    {
        return false;
    }

    //  Looks like a valid IP address
    return true;
}

int main() 
{
    char st[] = "192.255.20.30";
    //char st[] = "255.255.255.255";
    //char st[] = "0.255.255.0";

    if(isValidIpAddress(st))
    {
        printf("The given IP is a valid IP address\n"); 
    }
    else
    {
        printf("The given IP is not a valid IP address\n");
    }
}

答案 10 :(得分:1)

您可以使用boost tokenizer和boost char_separator轻松完成此任务。

http://www.boost.org/doc/libs/1_37_0/libs/tokenizer/char_separator.htm

答案 11 :(得分:1)

您可以编写自己的函数:

bool isValidIPv4(const char *IPAddress)
{
   unsigned char a,b,c,d;
   return sscanf(IPAddress,"%d.%d.%d.%d", &a, &b, &c, &d) == 4;
}

sscanf()sprintf()在某些情况下非常有用。 :))

答案 12 :(得分:1)

修复某些案例的一些小修复,如127..0.1,127.0.0 ..如果有,则删除空格:




    #include <iostream>
    #include <vector>
    #include <string>
    #include <sstream>
    #include <algorithm>
    #include <iterator>
    #include <stdio.h>

    using namespace std;

    vector split(char* str, char delimiter)
    {
        const string data(str);
        vector elements;
        string element;
        for(int i = 0; i  0) {//resolve problem: 127.0..1
                    elements.push_back(element);
                    element.clear();
                }
            }
            else if (data[i] != ' ')
            {
                element += data[i];
            }

        }
        if (element.length() > 0)//resolve problem: 127.0..1
            elements.push_back(element);
        return elements;
    }

    bool toInt(const string& str, int* result)
    {
        if (str.find_first_not_of("0123456789") != string::npos)
            return false;

        stringstream stream(str);
        stream >> *result; // Should probably check the return value here
        return true;
    }

    /** ipResult: the good ip address, e.g. spaces are removed */
    bool validate(char* ip, string *ipResult)
    {
        const static char delimiter = '.';
        const vector parts = split(ip, delimiter);
        *ipResult = "";
        if (parts.size() != 4)
            return NULL;

        for(int i = 0; i  255)
                return NULL;

            if (i == 3) {
                *ipResult += parts[i];
            } else {
                *ipResult += (parts[i] +".");
            }

        }
        return true;
    }

    int main()
    {
        string ip;
        printf("right %d\n", validate("127.0.0.1", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("wrong %d\n", validate("127.0.0.-1", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("wrong %d\n", validate("127..0.1", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("wrong %d\n", validate("...0.1", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("wrong %d\n", validate("127.0.0.", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("right %d\n", validate("192.168.170.99", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("right %d\n", validate("127.0 .0  .1", &ip));
        printf("good ip: %s\n", ip.c_str());
        printf("\n");

        system("pause");

        return 0;
    }

答案 13 :(得分:1)

vector<string> &split(const string &s, char delim, vector<string> &elems) {
    stringstream ss(s);
    string item;
    while(getline(ss, item, delim)) {
       elems.push_back(item);
    }
    return elems;
}

vector<string> split(const string &s, char delim) {
   vector<string> elems;
   return split(s, delim, elems);
}


bool isIPAddress(string  ipaddr){

    if (ipaddr.length()){
            vector<string> _ip=split(ipaddr,'.');
            if (_ip.size()==4){
                    for (int i=0; i < 4; i++){
                            for (int j=0; j < _ip[i].length(); j++)
                                    if (!isdigit(_ip[i][j])) return false;
                            if ((atoi(_ip[i].c_str()) < 0) || (atoi(_ip[i].c_str()) > 255)) return false;
                    }
            return true;
            }
    }
    return false;
 }

答案 14 :(得分:1)

如果你不想要Boost或TR1的开销,你可以搜索这些点并检查它们之间的字符是否是0到255之间的数字。

答案 15 :(得分:0)

如果您希望以常规形式(例如8.8.8.8192.168.1.1等接收IP地址) 然后,我编写了以下代码,扩展了比约恩的答案:

void validateIP(const std::string &IPv4_address)
{
    boost::system::error_code error_code;
    auto raw_ipv4_address = boost::asio::ip::address::from_string(IPv4_address, error_code);
    if (error_code)
    {
        throw std::invalid_argument(error_code.message());
    }

    std::string raw_to_string_form = raw_ipv4_address.to_string();
    if (raw_to_string_form.compare(IPv4_address))
    {
        throw std::invalid_argument("Input IPv4 address is invalid");
    }
}

原因是,如果您传递8.88.8或12345 (十进制)之类的IP,Bjorn的回答不会抛出错误。 (至少提高了1.68) 我的代码将任何形式转换为Boost中的内部结构,然后将其转换回点分十进制格式,然后将其与接收到的第一个IP进行比较,看它们是否相等,如果不相等,我们肯定知道输入不是我们想要的方式。

答案 16 :(得分:0)

void validate_ip_address(const std::string& s) {
    const std::string number_0_255 = "((([0-9])|([1-9][0-9])|(1[0-9][0-9]|2[0-4][0-9]|25[0-5])){1})";
    const std::string dot = "(\\.){1}";
    static const boost::regex e(number_0_255 + dot + number_0_255 + dot + number_0_255 + dot + number_0_255);
    if (!regex_match(s, e)) {
        throw std::runtime_error(std::string("Uncorrect address IP: ") + s);
    }
}