4

我正在为学校编写 C++ 代码,我只能使用 std 库,所以没有提升。我需要解析像“14:30”这样的字符串并将其解析为:

unsigned char hour;
unsigned char min;

我们将字符串作为 c++ 字符串,因此没有直接指针。我尝试了此代码的所有变体:

sscanf(hour.c_str(), "%hhd[:]%hhd", &hours, &mins);

但我不断收到错误的数据。我究竟做错了什么。

4

6 回答 6

2

正如其他人所提到的,您必须使用%d指定的格式(或%u)。至于替代方法,我不喜欢“因为 C++ 具有必须使用的特性 XX”,并且经常求助于 C 级函数。虽然我从不使用scanf()类似的东西,因为它有自己的问题。话虽如此,这就是我将如何使用strtol()错误检查来解析您的字符串:

#include <cstdio>
#include <cstdlib>

int main()
{
    unsigned char hour;
    unsigned char min;

    const char data[] = "12:30";
    char *ep;

    hour = (unsigned char)strtol(data, &ep, 10);
    if (!ep || *ep != ':') {
        fprintf(stderr, "cannot parse hour: '%s' - wrong format\n", data);
        return EXIT_FAILURE;
    }

    min = (unsigned char)strtol(ep+1, &ep, 10);
    if (!ep || *ep != '\0') {
        fprintf(stderr, "cannot parse minutes: '%s' - wrong format\n", data);
        return EXIT_FAILURE;
    }

    printf("Hours: %u, Minutes: %u\n", hour, min);
}

希望能帮助到你。

于 2012-11-19T16:06:41.513 回答
2

当然,您的问题是您正在使用sscanf. 并且您正在使用一些非常特殊的类型来表示小时和分钟,而不是int. 由于您正在解析一个正好包含 5 个字符的字符串,因此最简单的解决方案就是确保所有字符在该位置都是合法的,使用isdigit字符 0、1、3 和 4,并与':'字符 2 进行比较。一旦你已经做到了,std::istringstream从字符串创建 an 并输入到 an int, a char(之后您将忽略)和 second是微不足道的int。如果您想在输入中更加灵活,例如"9:45"也允许类似的内容,您可以跳过初始检查,只需输入int,charint,然后检查char包含':' (并且两者int都在范围内)。

至于你sscanf失败的原因:你要求它匹配类似的东西"12[:]34",这不是你给它的东西。我不确定您是否正在尝试使用"%hhd:%hhd",或者由于某种原因您确实想要一个字符类,在这种情况下,您必须将其[用作转换说明符,然后忽略输入:"%hhd%*[:]%hhd"。(这将允许接受多个字符作为分隔符,但除此之外,我看不到优势。此外,至少从技术上讲,不支持使用%d然后传递unsigned整数类型的地址,%hhd 必须signed char. 在实践中,但是,对于小于 128 的非负输入值,我认为您永远不会遇到任何问题。)

于 2012-11-19T16:08:27.217 回答
1

正如 izomorphius 所提到的sscanf,变体不是 C++,它们是 C。C++ 的方式是使用流。以下作品(它不是非常灵活,但应该给你一个想法)

#include <iostream>
#include <string>
#include <sstream>

using namespace std;

int main(int argc, char* argv[])
{
    string str = "14:30";

    stringstream sstrm;

    int hour,min;

    sstrm << str;

    sstrm >> hour;
    sstrm.get(); // get colon
    sstrm >> min;

    cout << hour << endl;
    cout << min << endl;

    return 0;
}

您还可以使用getline将所有内容都放在冒号上。

于 2012-11-19T16:02:00.437 回答
1

我会这样做

unsigned tmp_hour, tmp_mins;
unsigned char hour, mins;

sscanf(hour.c_str(), "%u:%u", &tmp_hours, &tmp_mins);
hour = tmp_hours;
mins = tmp_mins;

减少晦涩的scanf选项。我也会添加一些错误检查。

于 2012-11-19T16:07:02.277 回答
0

我的理解是hin%hhd不是有效的格式说明符。十进制整数的正确说明符是%d.

正如 R.Martinho Fernandes 在他的评论中所说,%d:%d将匹配由冒号 (':') 分隔的两个数字。

你想要一些不同的东西吗?

您始终可以阅读整个文本字符串并以任何您想要的方式对其进行解析。

于 2012-11-19T15:57:28.060 回答
0

sscanfwith%hhd:%hhd似乎工作得很好:

std::string time("14:30");
unsigned char hour, min;
sscanf(time.c_str(), "%hhd:%hhd", &hour, &min);

请注意,hh长度修饰符只是允许将值存储在无符号字符中。

但是,sscanf它来自 C 标准库,并且有更好的 C++ 方法来执行此操作。执行此操作的 C++11 方法是使用stoi

std::string time("14:30");
unsigned char hour = std::stoi(time);
unsigned char min = std::stoi(time.substr(3));

在 C++03 中,我们可以使用stringstream,但如果你真的想要它在 a 中会有点痛苦char

std::stringstream stream("14:30");
unsigned int hour, min;
stream >> hour;
stream.ignore();
stream >> min;
于 2012-11-19T16:05:14.100 回答