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 将读取到下一个空格字符;它不知道寻找冒号。因此,改为:首先使用strchrhostName 中定位:,然后才使用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) 检查来自strtolother 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++ 字符串匹配(主机名和端口)的主要内容,如果未能解决你的问题,请参考以下文章

获取本地主机名和 IP 地址的 C++ Windows 函数调用

c++标准库中没有关于正则匹配字符串的函数么

tomcat对请求路径的匹配过程

C++ string 字符串查找匹配

字符串匹配——KMP算法(C++)

数据结构(c++)字符串 模式匹配算法问题,对高手来说只要写一点点