【发布时间】:2010-10-21 23:25:16
【问题描述】:
确定字符串是否包含 IPv4 地址的好方法是什么?我应该使用isdigit() 吗?
【问题讨论】:
-
你的意思是确定一个字符串是一个有效的IPV4地址,还是包含一个有效的ipv4地址?
-
我说的是它是否包含有效的 ipv4 地址
确定字符串是否包含 IPv4 地址的好方法是什么?我应该使用isdigit() 吗?
【问题讨论】:
我会使用这个正则表达式(Regular Expression Examples 提供):
`\b(?:\d{1,3}\.){3}\d{1,3}\b`
【讨论】:
我问了a similar question for C++。您应该可以使用我当时想出的稍微修改过的(用于 C 的)版本。
bool isValidIpAddress(char *ipAddress)
{
struct sockaddr_in sa;
int result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
return result != 0;
}
您需要#include <arpa/inet.h> 才能使用inet_pton() 功能。
基于 cmets 更新问题:如果您想知道 C 风格的字符串是否包含 IP 地址,那么您应该结合目前给出的两个答案。使用正则表达式查找与 IP 地址大致匹配的模式,然后使用上面的函数检查匹配是否是真实的。
【讨论】:
inet_pton 可能会在出错时返回 -1。你的测试应该是result == 1 或至少result > 0
我会给出“不想要两个问题”的解决方案:
#include <string.h>
int isIp_v4( char* ip){
int num;
int flag = 1;
int counter=0;
char* p = strtok(ip,".");
while (p && flag ){
num = atoi(p);
if (num>=0 && num<=255 && (counter++<4)){
flag=1;
p=strtok(NULL,".");
}
else{
flag=0;
break;
}
}
return flag && (counter==3);
}
编辑:strtok 可能不是线程安全的(感谢 Adam Rosenfield)
【讨论】:
counter==3 应该是 counter==4。除此之外,一个不错的简单解决方案。我会自己编辑代码,但我
在 url/uri rfc 3986 中,Augmented Backus-Naur Form (ABNF) ipv4 地址定义为:
IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
dec-octet = DIGIT ; 0-9
/ %x31-39 DIGIT ; 10-99
/ "1" 2DIGIT ; 100-199
/ "2" %x30-34 DIGIT ; 200-249
/ "25" %x30-35 ; 250-255
我用正则表达式实现了以下形式的检查:
// Although the RFC says ipv6 octects like 001 are not valid, it would be risky
// not to accept those
#define decoct "([01]?[0-9]?[0-9]|2[0-4][0-0]|25[0-5])"
#define ipv4 "(" decoct "\\." decoct "\\." decoct "\\." decoct ")"
【讨论】:
这是我不久前为嵌入式系统编写的一个例程,它在网络上生成各种可疑模式。因此,它绝对no 使用网络库甚至标准 C 库之类的花哨的东西,宁愿避开所有现代的东西,例如字符串标记和(颤抖)正则表达式库 :-)最后,它几乎适用于您可以找到的任何环境,而且速度非常快。
不过,如果您处于类似 checkIp4Addess() 的环境中,我建议您改用它。这表明你在做嵌入式的东西时有时不得不忍受的东西(尽管它是一个真正的解决方案)。
int isValidIp4 (char *str) {
int segs = 0; /* Segment count. */
int chcnt = 0; /* Character count within segment. */
int accum = 0; /* Accumulator for segment. */
/* Catch NULL pointer. */
if (str == NULL)
return 0;
/* Process every character in string. */
while (*str != '\0') {
/* Segment changeover. */
if (*str == '.') {
/* Must have some digits in segment. */
if (chcnt == 0)
return 0;
/* Limit number of segments. */
if (++segs == 4)
return 0;
/* Reset segment values and restart loop. */
chcnt = accum = 0;
str++;
continue;
}
/* Check numeric. */
if ((*str < '0') || (*str > '9'))
return 0;
/* Accumulate and check segment. */
if ((accum = accum * 10 + *str - '0') > 255)
return 0;
/* Advance other segment specific stuff and continue loop. */
chcnt++;
str++;
}
/* Check enough segments and enough characters in last segment. */
if (segs != 3)
return 0;
if (chcnt == 0)
return 0;
/* Address okay. */
return 1;
}
【讨论】:
if ((chcnt > 0) && (accum == 0)) return 0; before /* Accumulate and check segment. */ 会阻止像 01 这样的前导零。
这是我尝试使用非常低级的 C 编程(实际上在我的一个 PIC 微控制器程序中使用)。 它不使用 string.h 库。 它不使用指针,因为我使用的这个编译器不能很好地使用它们,无论如何你可以使用它们。 考虑到这一点并预先定义一个变量来处理传入的数据缓冲区,如下所示:
#define isdigit(x) isamong(x,"0123456789")
char IPACK_Buff[IPACK_SIZE];
// Check if string is a valid IP
int IPACK_is_valid_ip(int len)
{
int i = 0;
int j = 0;
int NumDots = 0;
char number[4] = "000\0";
// Check first char is numeric
if (!isdigit(IPACK_Buff[0]))
return 0;
for (i = 0 ; i< len; i++)
{
if (isdigit(IPACK_Buff[i]))
{
number[j] = IPACK_Buff[i];
j++;
if (j>3)
return 0;
}
else if (IPACK_Buff[i] == '.')
{
if (atof(number)> 255) return 0;
memset(number, '\0', 4);
j = 0;
NumDots++;
if(NumDots>3)
return 0;
}
}
if (NumDots == 3)
{
return 1;
}
else
return 0;
}//
希望这个功能对大家有帮助。 同样,请考虑到此函数在批评之前编程的低级别。
【讨论】:
我认为下面的 C 代码 sn-p 应该可以工作
bool validate_ip4(const char* buffer)
{
if (NULL == buffer) return false;
register const char* pos = buffer;
register unsigned char ch = *pos;
register unsigned short count = 0;
while (ch != NULL)
{
if (!((ch >= '0' && ch <= '9') || ch == '.')) return false;
if (ch == '.')
if (++count > 3) return false;
ch = *++pos;
}
if (count == 3 && *--pos != '.') return true;
return false;
}
【讨论】:
我需要确定传入的字符串是否“包含”有效的 IP 地址,如果是,则返回指向传入字符串的有效 IP 地址部分的指针。如果不是,则返回一个空指针。
这是似乎可以工作的代码,虽然还没有经过很好的测试,但我只是写了它并快速尝试了一下。我还没有添加检查以将数字限制为一字节值,但请检查以确保它们限制为三位数。
int IsDigit(char ch)
{
int is_digit = 0;
if ( ch >= '0' && ch <= '9' )
{
is_digit = 1;
}
return is_digit;
}
#define FIND_IP_START 0
#define FIND_IP_DIGIT 1
#define FIND_IP_DIG_OR_DEC 2
#define FIND_IP_DECIMAL 3
#define FIND_IP_DIG_OR_END 4
#define FIND_IP_END 5
#define FIND_IP_DONE 6
char * StringContainsValidIpAddress(char * input_buf_pointer)
{
char * pos = input_buf_pointer;
int octets = 0;
int digits = 0;
int state = FIND_IP_START;
char * ip_string = 0;
char ch = *pos;
while ( (ch != NULL) && (state != FIND_IP_DONE) )
{
switch ( state )
{
case FIND_IP_START:
if ( IsDigit(ch) )
{
ip_string = pos; //potential start of ip string
digits = 1; // first digit
octets = 1; // of first octet
state = FIND_IP_DIG_OR_DEC;
}
break;
case FIND_IP_DIGIT:
if ( IsDigit(ch) )
{
digits = 1; // first digit
octets++; // of next octet
if ( octets == 4 )
{
state = FIND_IP_DIG_OR_END;
}
else
{
state = FIND_IP_DIG_OR_DEC;
}
}
else
{
// Start over
state = FIND_IP_START;
}
break;
case FIND_IP_DIG_OR_DEC:
// Here we are looking for another digit
// of the same octet or the decimal between
// octets.
if (ch == '.')
{
state = FIND_IP_DIGIT;
}
else if ( IsDigit(ch) )
{
digits++; // next digit
if ( digits == 3 )
{
state = FIND_IP_DECIMAL;
}
}
else
{
// Start over
state = FIND_IP_START;
}
break;
case FIND_IP_DECIMAL:
if (ch == '.')
{
state = FIND_IP_DIGIT;
}
break;
case FIND_IP_DIG_OR_END:
// Here we are looking for another digit
// of the same octet or the end (which could
// be a space or CR or LF or really any
// non-digit).
if ( IsDigit(ch) )
{
digits++; // next digit
if ( digits == 3 )
{
state = FIND_IP_END;
}
}
else
{
*pos = 0; // Null terminate the IP address string
state = FIND_IP_DONE;
}
break;
case FIND_IP_END:
if ( !IsDigit(ch) )
{
*pos = 0; // Null terminate the IP address string
state = FIND_IP_DONE;
}
break;
case FIND_IP_DONE:
break;
default:
break;
}
// Fetch the next character
ch = *++pos;
}
if (state == FIND_IP_DONE)
{
return ip_string;
}
else
{
return 0;
}
}
【讨论】:
inet_addr() 在数字和点表示法表示 IPv4 IP 地址检查方面比 inet_aton() 好得多。
【讨论】:
int validateIP4Dotted(const char *s)
{
int len = strlen(s);
if (len < 7 || len > 15)
return 0;
char tail[16];
tail[0] = 0;
unsigned int d[4];
int c = sscanf(s, "%3u.%3u.%3u.%3u%s", &d[0], &d[1], &d[2], &d[3], tail);
if (c != 4 || tail[0])
return 0;
for (int i = 0; i < 4; i++)
if (d[i] > 255)
return 0;
return 1;
}
【讨论】:
像这样从头开始。此代码包含检查字符串是否包含 IPv4 IP 地址的工具。
#define MAX_HEX_NUMBER_COUNT 8
int ishexdigit(char ch)
{
if((ch>='0'&&ch<='9')||(ch>='a'&&ch<='f')||(ch>='A'&&ch<='F'))
return(1);
return(0);
}
int IsIp6str(char *str)
{
int hdcount=0;
int hncount=0;
int err=0;
int packed=0;
if(*str==':')
{
str++;
if(*str!=':')
return(0);
else
{
packed=1;
hncount=1;
str++;
if(*str==0)
return(1);
}
}
if(ishexdigit(*str)==0)
{
return(0);
}
hdcount=1;
hncount=1;
str++;
while(err==0&&*str!=0)
{
if(*str==':')
{
str++;
if(*str==':')
{
if(packed==1)
err=1;
else
{
str++;
if(ishexdigit(*str)||*str==0&&hncount<MAX_HEX_NUMBER_COUNT)
{
packed=1;
hncount++;
if(ishexdigit(*str))
{
if(hncount==MAX_HEX_NUMBER_COUNT)
{
err=1;
} else
{
hdcount=1;
hncount++;
str++;
}
}
} else
{
err=1;
}
}
} else
{
if(!ishexdigit(*str))
{
err=1;
} else
{
if(hncount==MAX_HEX_NUMBER_COUNT)
{
err=1;
} else
{
hdcount=1;
hncount++;
str++;
}
}
}
} else
{
if(ishexdigit(*str))
{
if(hdcount==4)
err=1;
else
{
hdcount++;
str++;
}
} else
err=1;
}
}
if(hncount<MAX_HEX_NUMBER_COUNT&&packed==0)
err=1;
return(err==0);
}
int IsIp4str(char *str)
{
int nnumber=0;
int value=0;
int err=0;
if(*str>='0'&&*str<='9')
{
value=*str-'0';
str++;
} else
return(0);
nnumber=1;
while(err==0&&*str!=0)
{
if(*str>='0'&&*str<='9')
{
if(255/value>=10)
{
value*=10;
if(255-value>=(*str-'0'))
{
value+=(*str-'0');
str++;
} else
err=1;
} else
err=1;
} else
{
if(*str=='.')
{
str++;
if(*str>='0'&&*str<='9')
{
if(nnumber==4)
err=1;
else
{
if(*str=='0')
{
*str++;
if(*str!='.'&&*str!=0)
err=1;
else
{
nnumber++;
value=0;
}
} else
{
nnumber++;
value=*str-'0';
str++;
}
}
} else
{
err=1;
}
} else
if(*str!=0)
err=1;
}
}
if(nnumber!=4)
err=1;
return(err==0);
}
函数 IsIp4str(char *str) 测试字符串是否包含 IP 地址版本四地址格式。 IsIp6str(char *str) 函数测试字符串是否包含IP地址版本六地址格式。
函数 IsIp4str(char *str) 和 IsIp6str(char *str) 如果字符串 str 包含 IP 地址,则返回 true;如果字符串 str 不包含 IP 地址,则返回 false。
如果你需要检查字符串是否包含IP地址IPv6格式,它可以做int IsIp6str(char *str)函数。它的工作方式与
相同【讨论】:
这是我一直在研究的一个功能的开始,虽然不完整,但它可能会激发想法或 cmet。该函数背后的思想是;
我认为这取决于您想深入了解问题,了解可能发生的问题的深度。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
int isIP(char *ip)
{
char *data_ptr = ip; // Create a pointer to passed data
int orig_str_size = 0; // Create an int to hold passed data size
int str_index = 0; // Create an int to iterate individual ip characters
int dot_count = 0; // Create an int to check for the number of dots
// Count the number of characters in data_ptr
while (*data_ptr++ != '\0'){ orig_str_size++; }
if(orig_str_size <= 0) // If nothing
{
printf("Get a grip, ip is empty\n\n");
exit(0);
}
else // If within IPv4 size range
if(orig_str_size >= 7 && orig_str_size <= INET_ADDRSTRLEN)
{
char *data1_ptr = ip; // Create a pointer to passed data
printf("Within IPv4 range, %i characters in length\n\n", orig_str_size);
// Count the number of dots in the string, 3 for IPv4
for(str_index; str_index < orig_str_size; str_index++)
{
if(data1_ptr[str_index] == '.'){ dot_count++; }
}
// If theres 3 dots, while ignoring dots, check each char is a digit
if(dot_count == 3)
{
printf("There's three dots in the string\n\n");
data1_ptr = ip;
str_index = 0;
// Iterate the string char by char
for(str_index; str_index < orig_str_size; str_index++)
{
// Ignoring dots
if(data1_ptr[str_index] != '.')
{
// If isdigit() is happy its a digit and isalpha() happy not alphabetic
if(isdigit(data1_ptr[str_index]) && !isalpha(data1_ptr[str_index]))
{
printf("Digit found and is not alphabetic\n\n");
continue;
}
else
if(!isdigit(data1_ptr[str_index]) && isalpha(data1_ptr[str_index]))
{
printf("Not a recognised IPv4 address, character detected in string\n\n");
exit(0);
}
}
}
return 0;
}
}
else // If IPv6
if(orig_str_size > 0 && orig_str_size > INET_ADDRSTRLEN && orig_str_size <= INET6_ADDRSTRLEN)
{
printf("Within IPv6 range %i\n\n", orig_str_size);
return 0;
}
else
{
printf("Unknown target format, the format you provided as a target is not implemented\n\n");
exit(0);
}
}
TCP/IP 互联
RFC791 - 互联网协议 - https://www.rfc-editor.org/rfc/rfc791
思科互联网络手册http://docwiki.cisco.com/wiki/Internetworking_Technology_Handbook
开放系统互连参考模型http://docwiki.cisco.com/wiki/Internetworking_Basics#Open_Systems_Interconnection_Reference_Model
思科 TCP/IP 网络故障排除https://www.cisco.com/en/US/docs/internetworking/troubleshooting/guide/tr1907.pdf
What is the largest TCP/IP network port number allowable for IPv4?
【讨论】:
// you can even use the v value array to return the unsigned int
// version of the IP if desired in an unsigned int reference.
bool isvalidip(const char * s)
{
char t[8];
int p = 0;
int v[8];
int numnum = 0;
for (int i = 0; i < (int) strlen(s); i++) {
char c = s[i];
int cgood = 0;
if (c >= '0' && c <= '9' && p < 4) {
t[p++] = c;
t[p] = 0;
cgood++;
continue;
}
if (p == 4) return false;
if (c == '.') {
if (!p) return false;
v[numnum++] = atoi(t);
p = 0;
cgood++;
continue;
}
if (!cgood) return false; // not a valid character
if (numnum > 4) return false; // we have a lot of dots....
}
v[numnum++] = atoi(t); // we did not have a dot, we had a NULL.....
if (numnum != 4) return false; // we must have had 4 valid numbers....
for (int i = 0; i < 4; i++)
{
if (v[i] < 0 || v[i] > 255) return false; // octet values out-of-range
}
return true; //we good..
}
【讨论】:
我修改了一个答案,使其更完整,并附上所有代码(包括测试)
#include <stdio.h>
#include <assert.h>
#include <string.h>
int validateIP4Dotted(char *str, unsigned int pIPAddress[])
{
int segs = 0; /* Segment count. */
int chcnt = 0; /* Character count within segment. */
int accum = 0; /* Accumulator for segment. */
/* Catch NULL pointer. */
if (str == NULL)
return 0;
/* Process every character in string. */
while (*str != '\0')
{
/* Segment changeover. */
if (*str == '.')
{
pIPAddress[segs] = accum;
/* Must have some digits in segment. */
if (chcnt == 0 || chcnt > 3)
return 0;
/* Limit number of segments. */
if (++segs == 4)
return 0;
/* Reset segment values and restart loop. */
chcnt = accum = 0;
str++;
continue;
}
/* Check numeric. */
if ((*str < '0') || (*str > '9'))
return 0;
/* Accumulate and check segment. */
if ((accum = accum * 10 + *str - '0') > 255)
return 0;
/* Advance other segment specific stuff and continue loop. */
chcnt++;
str++;
}
/* Check enough segments and enough characters in last segment. */
pIPAddress[segs] = accum;
if (segs != 3)
return 0;
if (chcnt == 0 || chcnt > 3)
return 0;
if (pIPAddress[0] >=224)
return 0;
/* Address okay. */
return 1;
}
int main()
{
unsigned int IpAddress[4];
char str_ip[128];
strcpy(str_ip, "192.168.1.10");
assert(validateIP4Dotted(str_ip, IpAddress));
assert(
IpAddress[0] == 192 && IpAddress[1] == 168 && IpAddress[2] == 1
&& IpAddress[3] == 10);
strcpy(str_ip, "0.0.0.0");
assert(validateIP4Dotted(str_ip, IpAddress));
assert(
IpAddress[0] == 0 && IpAddress[1] == 0 && IpAddress[2] == 0
&& IpAddress[3] == 0);
strcpy(str_ip, "/192.168.1.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "192..168.1.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, ".192.168.1.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "192.168.1.10.");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "192.168.1.10.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "192.168.1.");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "192.168.1");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "255.168.1.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "10.260.1.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "10.200.0001.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
return 0;
}
【讨论】:
试试这个代码:
int ipValid(char *ip) {
int i,j,start,dotcount=0,x=0,end,c=0;
int n= strlen(ip);
start=0;
for(i=0;i<n;i++)
{
if(ip[i]=='.'||i==n-1)
{
c=0;x=0;
if(ip[i]=='.')
{
dotcount++;
end=i-1;
}
else if(i==n-1)
end=i;
for(j=start;j<=end;j++)
{
c++;
x=x*10+(ip[j]-48);
}
if(c<4&&x>=0&&x<=255)
{
if(i==n-1)
break;
else
start=i+1;
}
else
{
return 0;
}
}
}
if(dotcount==3)
return 1;
else
return 0;}
【讨论】: