【问题标题】:Ignoring integers that are next to characters using sscanf()使用 sscanf() 忽略字符旁边的整数
【发布时间】:2012-01-12 21:09:02
【问题描述】:

很抱歉这个简单的问题,但我正在尝试找到一种优雅的方法来避免我的程序看到像“14asdf”这样的输入并像 14 一样接受它。

if (sscanf(sInput, "%d", &iAssignmentMarks[0]) != 0)

有没有一种简单的方法可以防止sscanf 从这样的错位字符串中提取整数?

【问题讨论】:

  • 你的意思是有没有办法让 sscanf 只提取字符串中的数字字符?您可能还想澄清您是否希望“53sd2”返回 53 或 532。
  • 对不起,我应该更清楚一点,我希望“14asdf”被识别为无效输入,“53sd2”也是如此。我只想识别没有非数字字符接触它们的独立整数(至少以空格分隔)。
  • 这在 C++ 中很容易。也许应该从这个问题中删除“c++”标签? @AdamWathan,您只想要 C 语言中的答案吗?

标签: c


【解决方案1】:

您不能直接阻止sscanf() 执行其设计和指定执行的操作。但是,您可以使用sscanf() 的一个鲜为人知且很少使用的功能来轻松发现问题所在:

int i;

if (sscanf(sInput, "%d%n", &iAssignmentMarks[0], &i) != 1)
    ...failed to recognize an integer...
else if (!isspace(sInput[i]) && sInput[i] != '\0')
    ...character after integer was not a space character (including newline) or EOS...

%n 指令报告到该点所消耗的字符数,并且不计为一次转换(因此该格式只有一次转换)。自 C89 以来,%nsscanf() 中的标准。

对于提取单个整数,您还可以使用strtol() - 小心(用它检测错误条件非常困难,但它比不会报告或检测溢出的sscanf() 好)。但是,这种技术可以在一种格式中多次使用,这通常更方便。

【讨论】:

    【解决方案2】:

    您想从字符串中读取整数。使用strtol 而不是sscanf 更容易做到这一点。 strtol 将通过endptr 间接返回成功读入数字的最后一个字符之后的地址。如果,且仅当,字符串是一个数字,那么endptr 将指向你的数字字符串的结尾,即*endptr == \0

    char *endptr = NULL;
    long n = strtol(sInput, &endptr, 10);
    bool isNumber = endptr!=NULL && *endptr==0 && errno==0;
    

    (忽略初始空格。有关详细信息,请参阅strtol man page

    【讨论】:

    • 我在答案中添加了一些文字以解释代码。我希望你不介意@Serge-appTranslator。随意进一步编辑或删除它。
    • 什么?文本?为什么不在你的代码中评论呢! :-) 谢谢亚伦
    【解决方案3】:

    这很容易。不需要花哨的 C++!做吧:

    char unusedChar;
    if (sscanf(sInput, "%d%c", &iAssignmentMarks[0], &unusedChar) == 1)
    

    【讨论】:

      【解决方案4】:

      scanf 没那么聪明。您必须将输入读取为文本并使用strtol 进行转换。 strtol 的一个参数是 char *,它将指向未转换的第一个字符;如果该字符不是空格或 0,则输入字符串不是有效整数:

      char input[SIZE]; // where SIZE is large enough for the expected values plus
                        // a sign, newline character, and 0 terminator
      ...
      if (fgets(input, sizeof input, stdin))
      {
        char *chk;
        long val = strtol(input, &chk, 10);
        if (*chk == NULL || !isspace(*chk) && *chk != 0)
        {
          // input wasn't an integer string
        }
      }
      

      【讨论】:

      • 问题是关于sscanf,而不是scanf,因此数据已经在字符串中。请参阅@Serge 的回答。
      • 这是不正确的:您可以使用[fs]scanf() 来解决这个问题:您只需要尝试在数字之后读取一些内容并检查读取的元素数。
      【解决方案5】:

      如果您可以使用 c++ 特定的功能,还有更清晰的方法可以使用流测试输入字符串。

      检查这里: http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.2

      如果您想知道,是的,这确实来自另一个堆栈溢出帖子。这回答了这个问题: Other answer

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-10-09
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-10
        • 2015-11-07
        • 2017-09-05
        相关资源
        最近更新 更多