目前的解决方法可以归为以下三类:
1、自己动手写:以'.'将IP字符串分割成子串,再依次判断每个子串的每个字符是否都是数字,最后转换成值,判断是否在0~255的范围。
/*
功能:
判断IP地址是否有效
接口函数:
booli sIPAddressValid ( const char * pszIPAddr )
输入:
pszIPAddr 字符串
输出:
true 有效的IP地址,false,无效的IP地址
约束:
1.输入IP为XXX.XXX.XXX.XXX格式
2.字符串两端含有空格认为是合法IP
3.字符串中间含有空格认为是不合法IP
4.类似于 01.1.1.1, 1.02.3.4 IP子段以0开头为不合法IP
5.子段为单个0 认为是合法IP,0.0.0.0也算合法I
*/
#include <iostream>
#include <cstring>
using namespace std;
bool isIPAddressValid(const char* pszIPAddr)
{
if (!pszIPAddr) return false; //若pszIPAddr为空
char IP1[100],cIP[4];
int len = strlen(pszIPAddr);
int i = 0,j=len-1;
int k, m = 0,n=0,num=0;
//去除首尾空格(取出从i-1到j+1之间的字符):
while (pszIPAddr[i++] == ' ');
while (pszIPAddr[j--] == ' ');
for (k = i-1; k <= j+1; k++)
{
IP1[m++] = *(pszIPAddr + k);
}
IP1[m] = '\0';
char *p = IP1;
while (*p!= '\0')
{
if (*p == ' ' || *p<'0' || *p>'9') return false;
cIP[n++] = *p; //保存每个子段的第一个字符,用于之后判断该子段是否为0开头
int sum = 0; //sum为每一子段的数值,应在0到255之间
while (*p != '.'&&*p != '\0')
{
if (*p == ' ' || *p<'0' || *p>'9') return false;
sum = sum * 10 + *p-48; //每一子段字符串转化为整数
p++;
}
if (*p == '.') {
if ((*(p - 1) >= '0'&&*(p - 1) <= '9') && (*(p + 1) >= '0'&&*(p + 1) <= '9'))//判断"."前后是否有数字,若无,则为无效IP,如“1.1.127.”
num++; //记录“.”出现的次数,不能大于3
else
return false;
};
if ((sum > 255) || (sum > 0 && cIP[0] =='0')||num>3) return false;//若子段的值>255或为0开头的非0子段或“.”的数目>3,则为无效IP
if (*p != '\0') p++;
n = 0;
}
if (num != 3) return false;
return true;
}
void main()
{
char IP[] = " 254.1.1.1 ";
//char IP[100];
//cin >> IP;
bool tf = isIPAddressValid(IP);
cout << tf<<endl;
system("pause");
}
别人给的一个解决方案也很不错,充分利用了atoi函数的特性:遇到有字符的时候,只转换字符前的数字;转换完毕把字符串数组指针向后移。
2、使用inet_addr(const char * str)函数。inet_addr()的功能是将一个点分十进制的IP转换成一个长整数型数(u_long类型)。丢给这个函数一个字符串,能成功转换就是合法的IP地址字符串,转换失败返回INADDR_NONE。若是不允许非标准形式的IP地址,则再加上对'.'的个数的判断。另外,INADDR_NONE即为255.255.255.255,因此此地址字符串不能正确转换。
3、利用正则表达式!这个编写代码的效率又高又容易保证正确性,又容易维护。需要用boost中的regex库。唯一的缺点是,这是个静态链接库,编译的时候会慢一点,打包的时候体积也会增加。
// boostTest.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <boost/xpressive/xpressive_dynamic.hpp>
//BOOST用正则表达式验证ip地址合法
bool CheckIP(const char *ip)
{
using namespace boost::xpressive;
/* 定义正则表达式 */
cregex reg_ip = cregex::compile("(25[0-4]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])[.](25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])[.](25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])[.](25[0-4]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])");
return regex_match(ip, reg_ip);
}
int _tmain(int argc, _TCHAR* argv[])
{
std::wcout<<"ip:"<<CheckIP("1247.0.0.1");
getchar();
return 0;
}
perl正则表达式语法
perl正则表达式语法可参见《perl语言入门》第7、8、9章或boost的文档。这里列出的语法是不全面的,而且部分说明可能并不清楚。
. 任意字符;使用match_no_dot_null标志时不匹配NULL字符; 使用match_not_dot_newline时不匹配换行字符
^ 匹配行的开始
$ 匹配行的结束
* 重复零次或则更多,例如a*b可匹配b,ab,aab,aaaaaaab
+ 重复一次以上,例如a+b可匹配ab,aab,aaaaaaaab。但不能匹配b了
? 零次或则一次,例如ca?b匹配cb,cab但不匹被caab
a{n} 匹配字符''a''重复n次
a{n,},字符a重复n次以上(含n次)
a{n,m} a重复n到m次(含)
*? 匹配前一个原子零次以上
+? 匹配前一个原子一次以上
?? 匹配前一个原子零次以上
{n,}? 匹配前一个原子n次以上(含)
{n,m? 匹配前一个原子n到m次(含)
| 或操作,例如ab(d|ef)匹配abd或则abef
[] 字符集操作,例如[abc]将匹配任何单个字符''a'',''b'',''c''
[a-d],表示a、b、c、d
^否操作,例如[^a-c]表示a至c之外的所有字符
4、swscanf()函数,简洁高效
BOOL isIpFormatRight(LPTSTR ipAddress)
{//判断IP地址是否合法
int a,b,c,d;
if ((swscanf(ipAddress,L"%d.%d.%d.%d",&a,&b,&c,&d)==4)
&&(a>=0&&a<=255)
&&(b>=0&&b<=255)
&&(c>=0&&c<=255)
&&(d>=0&&d<=255))
{
return TRUE;
}
return FALSE;
}