【问题标题】:Using sscanf to extract an int from a string in C++使用 sscanf 从 C++ 中的字符串中提取 int
【发布时间】:2016-02-25 03:15:55
【问题描述】:

我的函数必须处理看起来像 say hello y(5) 或 data |x(3)| 的字符串,并且我需要能够提取显示的整数并将其存储到一个名为 address 的单独 int 变量中。但是,某些通过的字符串不会有任何整数,对于这些,地址必须默认为 0。当字符串包含整数时,它总是在括号之间。我曾尝试使用 sscanf,但由于对 sscanf 非常陌生,我遇到了一些问题。由于某种原因,地址始终读取为 0。这是我的代码:

void process(string info)
{
int address = 0; // set to 0 in case info contains no digits
sscanf(info.c_str(), "%d", address);
.
.
.
// remainder of code makes other function calls using the address, etc
}

关于为什么 sscanf 无法找到括号之间的整数的任何想法?谢谢!

【问题讨论】:

  • hello 不匹配 %d 。在应用%d 之前,您需要找到一种方法可以跳到整数的开头。 strchr 函数可能是一种方式。你在address之前忘记了&
  • 您不能使用标准解析技术来构造一些AST 或嵌入一些现有的解释器(如GuileLua...)吗?

标签: c++ c scanf


【解决方案1】:

为什么 sscanf 找不到括号之间的整数

一旦检测到非数字序列,sscanf(info.c_str(), "%d", address) 中的 "%d" 将导致 sscanf() 停止扫描。像"(5)" 这样的文本将在"(" 处停止扫描。

代码需要跳过非数字文本。


伪代码

  in a loop
    search for any of "-+0123456789"
    if not found return 0
    convert from that point using sscanf() or strtol()
    if that succeeds, return number
    else advance to next character

示例代码

int address;
const char *p = info.c_str();
for (;;) {
  p += strcspn(p, "0123456789+-");
  if (*p == 0) return 0;
  if (sscanf(p, "%d", &address) == 1) {
    return address;
  }
  p++;
}

注意事项:

strcspn 函数计算s1 指向的字符串的最大初始段的长度,该长度完全由不是来自s2 指向的字符串的字符组成。 C11 7.24.5.3 2


如果代码想要依赖 " 它总是在括号之间。" 不会出现像"abc()def(123)" 这样的输入,在() 之间有前面的非数字数据。:

const char *p = info.c_str();
int address;
if (sscanf(p, "%*[^(](%d", &address)==1) {
  return address;
}
return 0;

或者干脆

int address = 0;
sscanf(info.c_str(), "%*[^(](%d", &address);
return address;

【讨论】:

  • +1 没有看到最后一次编辑。回答同样的问题。无论如何,如果字符串是data(5,应该返回什么。您的代码看起来像 5. 即使不在括号内。
  • @silentboy 简化代码利用了 OP 的“当字符串包含整数时,它总是在括号之间”。所以(5 不会发生。
【解决方案2】:

您可以使用像这样简单的方法,其中 strchr 找到“(”的第一次出现,然后使用 atoi 返回将在第一个非数字处停止的整数。

  char s1[] = "hello y(5)";
  char s2[] = "data [x(3)]";
  char s3[] = "hello";

  int a1 = 0;
  int a2 = 0;
  int a3 = 0;

  char* tok = strchr( s1, '(');
  if (tok != NULL)
    a1 = atoi(tok+1);

  tok = strchr( s2, '(');
  if (tok != NULL)
    a2 = atoi(tok+1);

  tok = strchr(s3,'(');
  if (tok != NULL)
    a3 = atoi(tok+1);

  printf( "a1=%d, a2=%d, a3=%d", a1,a2,a3);

  return 0;

【讨论】:

    【解决方案3】:

    当一个字符串包含一个整数时,它总是介于两者之间 括号

    要严格遵守此要求,您可以尝试:

    void process(string info)
    {
        int address;
        char c = '5'; //any value other than ) should work
    
        sscanf(info.c_str(), "%*[^(](%d%c", &address, &c);
        if(c != ')') address = 0;
        .
        .
        .
    }
    

    【讨论】:

      【解决方案4】:

      link to a solution

      int address;
      
      sscanf(info.c_str(), "%*[^0-9]%d", &address);
      printf("%d", address);
      

      这应该提取括号之间的整数

      【讨论】:

      • 注意:如果整数前没有字符,这将失败,因为%[必须始终匹配至少一个字符
      • -%[ 的行为是实现定义的;各种编译器可能支持也可能不支持。 (但你可以使用^0123456789)。
      • 这会将“-123”转换为123。 if 会将"123" 转换为未定义的值。
      猜你喜欢
      • 2012-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-24
      • 2016-05-15
      • 1970-01-01
      相关资源
      最近更新 更多