当数据行具有不同的有效格式时,如何在C++中使用 sscanf

How to use sscanf in C++ when data lines have different valid formats?

本文关键字:C++ sscanf 格式 数据 有效      更新时间:2023-10-16

如何扫描以下格式的字符串: 名称 id str1 num1 str2 num2

笔记:

  • 如果 str1 = "NO",则 num1 有一个值,
  • 如果 str1 = "YES",则 num1 没有值
示例 1:

阿里 1 NO 200 NO 100

示例 2:阿里 1 ,否 100

char name [10];
char str1 [4];
char str2 [4];
int id, num1, num2;
 sscanf(inputString, "%s %d %s %d %s %d",
                            name,  &id, str1, &num1, str2, &num2 );

当 str1="YES" 时,我有一个问题,str2 没有取正确的值!!

更改为:

char str1 [4];
char str2 [4];

允许 3 个字符加上一个 NULL 终止符。

示例 2 的格式与示例 1 不同,问题来了。您可以将 sscanf 分成两部分,并检查 str1 是否为是。

将输入读取到字符数组时,应始终指定可用空间量!读取字符数组的默认行为是不施加任何限制。这显然是错误的默认值,因为它使缓冲区溢出非常相似。

此外,在读取数据时,应始终验证读取操作是否确实成功:您的第二行与您正在读取的格式不匹配!YES后,根据格式需要一个整数。也就是说,你想要

if (6 == sscanf(inputString, "%10s %d %3s %d %3s %d",
                name, &id, str1, num1, str2, num2)) {
    // process the input upon success
}

当然,就个人而言,我宁愿使用std::istringstream

if (std::istringstream(inputString) >> std::setw(10) >> name >> id
        >> std::setw(3) >> str1 >> num1 >> std::setw(3) >> str2 >> num2) {
    // process the input upon success
}

要处理可选值,创建合适的conditional类型并创建合适的输入运算符会相当容易,例如:

template <int Size>
struct conditional_t {
    char* buffer;
    int*  value;
    conditional_t(char* buffer, int& value): buffer(buffer), value(&value) {}
};
template <int Size>
conditional_t<Size> conditional(char (&buffer)[Size], int& value) {
    return conditional_t<Size>(buffer, value);
}
template <int Size>
std::istream& operator>> (std::istream& in, conditional_t<Size> value) {
    if (in >> std::setw(Size) >> value.buffer && !strcmp(buffer, "NO")) {
        in >> *value.value;
    }
    return in;
}
// ...
if (std::istringstream(inputStream) >> std::skipws >> conditional(name, id)
        >> conditional(str1, num1) >> conditional(str2, num2)) {
    // ...
}

我认为这很甜蜜。

您无法在

一次调用中可靠地完成工作 sscanf() . 您必须适应第三列中的值。 因此,您需要执行以下操作:

char name [10];
char str1 [4];
char str2 [4];
int id, num1, num2;
int offset;
// %n conversion specifications do not count towards the return value
if (sscanf(inputString, "%9s %d %3s %n", name, &id, str1, &offset) != 3)
    ...report problem...
else
{
    if (strcmp(str1, "YES") == 0)
    {
        num1 = 0;  // Or other appropriate value
        if (sscanf(inputString+offset, "%3s %d", &str2, &num2) != 2)
            ...report problem...
    }
    else
    {
        if (sscanf(inputString+offset, "%d %3s %d", &num1, &str2, &num2) != 3)
            ...report problem...
    }
}

%n转换报告它出现的字符串中的偏移量。 它不计入 sscanf() 的返回值。

说你有很多变化要处理。 也许您的输入格式设计得不好,或者您可能需要一个更复杂的系统来识别数据的不同格式以及适用的格式。