C++字符串匹配(主机名和端口)

4

我希望将以"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 port的输出是一个很大的数字,但不是643246

有时候port的值太大了,我应该使用哪种数据类型? 如何正确匹配hostName,以便获得2个带有所需信息的变量?

6个回答

4

既然你在问题标题中提到了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
使用 %ssscanf 只会读取到下一个空格字符; 它并不知道要查找冒号。所以,首先使用 strchrhostName 中定位到 :,然后再使用 sscanf (或更好的选择是 atoi) 解析端口号。在任何平台上,一个 unsigned int 或任何类型的 long 都足够长,可以存储您的端口号;除了具有 16 位整数的小型嵌入式设备(其中具有设置顶部位的端口号将变成负数,这可能不是您想要的),int 也足够长。
(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) 再次检查strchr的返回值,以免在有冒号但超过256个字符时失败(或者动态分配hostNameChar之类的),(3) 使用strtol而不是atoi,(4) 检查strtol的返回值,以确保端口号合法,(5) 检查strtol的其他类型返回值,以确保端口号后面没有多余的内容。然而,上面的代码应该给出一般的想法。


是的,这只是一个例子,我是个初学者。sscanf(hostName,“%s:%ld”,hostNameChar,&port)不起作用。 - luac
不,使用“%ld”并不比使用“%d”更好;问题不在于数字的大小。问题在于“sscanf”正在读取主机名、冒号和端口;它无法知道您希望它在冒号处停止。因此,最好使用“strchr”手动查找冒号。 - Gareth McCaughan
2
不要使用 atoi,它不会进行任何错误检查。strol 是一个更安全的替代方案。 - Mark Loeser
如果你要坚持使用C语言,那么你应该使用scanf()函数,它可以自动完成上述所有操作,并且是可移植的(不像atoi()函数),而且只需要一行代码。你只需要使用正确的转换说明符,即%[]而不是%s - Martin York
我很好奇 - 什么使得atoi不具备可移植性? - Adam Bowen

2

试试这个:

#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 扫描单词。单词由空格分隔。
%[<BLA>] 匹配包含字符 <BLA> 的字符串。除非第一个字符是 ^。在这种情况下,它匹配不包含 <BLA> 字符的字符串。


0
另一个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;
}

0

-1

试试这个:

sscanf(hostName, "%s:%ld", hostNameChar, &port);

ld = 长有符号整数

然而,我认为端口号不能大于65536


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接