C++ 字符串匹配(主机名和端口)
Posted
技术标签:
【中文标题】C++ 字符串匹配(主机名和端口)【英文标题】:C++ string matching(hostname and port) 【发布时间】:2011-07-20 16:34:33 【问题描述】:我想将 "hostName:port" 形式的 const char* hostName 与 const char* hostNameFinal 和数字端口分开。
我目前有以下代码:
const char* hostName = "localhost:643246";
long int port;
char hostNameChar[256];
sscanf(hostName, "%s:%d", hostNameChar, &port);
hostNameChar 的输出为:localhost:643246 端口的输出是一个疯狂的数字,但不是 643246
有时port的值太大,我应该使用哪种数据类型? 如何正确匹配主机名,获得 2 个具有所需信息的变量?
【问题讨论】:
【参考方案1】:由于您的问题标题中有 C++,我建议您不要使用 char 数组并使用 std::string。
#include <string>
#include <sstream>
std::string hostName = "localhost:643246";
size_t colonPos = hostName.find(':');
if(colonPos != std::string::npos)
std::string hostPart = hostName.substr(0,colonPos);
std::string portPart = hostName.substr(colonPos+1);
std::stringstream parser(portPart);
int port = 0;
if( parser >> port )
// hostname in hostPart, port in port
// could check port >= 0 and port < 65536 here
else
// port not convertible to an integer
else
// Missing port?
【讨论】:
【参考方案2】:sscanf
和 %s
将读取到下一个空格字符;它不知道寻找冒号。因此,改为:首先使用strchr
在hostName
中定位:
,然后才使用sscanf
(或者,更好的是atoi
)来解析端口号。 unsigned int
或任何类型的 long
对任何平台上的端口号都足够长; int
在任何东西上都足够长,除了带有 16 位整数的小嵌入式事物(其中设置了最高位的端口号将变成负数,您可能不想要)。
(643246 不是合法的端口号,端口号只有 16 位,范围从 0 到 65535。)
编辑添加一些实际代码,以防我不清楚我的建议:
const char * colon = strchr(hostName, ':');
memcpy(hostNameChar, hostName, colon-hostName);
hostNameChar[colon-hostName];
port = atoi(colon+1);
再次编辑以确认 Mark Loeser 的正确观察,即 atoi
不进行任何错误检查。为了使上述代码具有生产价值,您应该(1)检查来自strchr
的返回值,以免在字符串中没有冒号时失败,(2)再次检查,以免在有冒号时失败但它超过 256 个字符(或动态分配 hostNameChar
或其他东西),(3)使用 strtol
而不是 atoi
,(4)检查来自 strtol
的返回值以确保端口号是合法的, 和 (5) 检查来自strtol
的 other kinda-return-value 以确保端口号后面没有尾随垃圾。然而,上面的代码应该给出了一般的想法。
【讨论】:
是的,这只是我初学者的一个例子,sscanf(hostName, "%s:%ld", hostNameChar, &port);不工作 不,使用%ld
不会比使用%d
更好;问题不在于数字的大小。问题是sscanf
正在读取主机名、冒号和端口;它无法知道您希望它在结肠处停止。因此,改为使用 strchr
手动查找冒号。
不要使用atoi
,它不会做任何错误检查。 strol
会是更安全的选择。
如果您要坚持使用 C,那么您应该使用 scanf(),它可以自动完成以上所有操作,并且是可移植的(与 atoi() 不同)并且只有一行。您只需要使用正确的转换说明符 %[]
而不是 %s
我很好奇 - 是什么让 atoi 不便携?【参考方案3】:
试试这个:
#include <stdio.h>
#include <stdlib.h>
int main()
const char* hostName = "localhost:643246";
long int port;
char hostNameChar[256];
if (sscanf(hostName, "%[^:]:%d", hostNameChar, &port) != 2)
// It did not work.
// scanf() returns the number of matched tokens.
fprintf(stdout, "Fail\n");
exit(1);
fprintf(stdout, "Host(%s) Port(%d)\n", hostNameChar, port);
这是因为 %s 扫描了一个单词。单词由空格分隔。
%[
【讨论】:
【参考方案4】:您可以使用 UrlGetPart http://msdn.microsoft.com/en-us/library/bb773781(v=VS.85).aspx
如果缓冲区太小,则返回 E_POINTER,并将 pcchOut 指向的值设置为缓冲区必须能够包含的最小字符数,包括终止 NULL 字符。
【讨论】:
【参考方案5】:另一种 C++ 解决方案(与 C 相比糟糕:)
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
const char* hostName = "localhost:643246";
long int port;
char hostNameChar[256];
istringstream iss(hostName);
string hostNameString;
getline(iss, hostNameString, ':');
strcpy(hostNameChar, hostNameString.c_str());
iss >> port;
cout << hostNameChar << "-" << port << endl;
【讨论】:
【参考方案6】:试试这个:
sscanf(hostName, "%s:%ld", hostNameChar, &port);
ld = 长符号整数
但是,我认为端口号不能> 65536
【讨论】:
以上是关于C++ 字符串匹配(主机名和端口)的主要内容,如果未能解决你的问题,请参考以下文章