Я пишу код C ++ для школы, в которой я могу использовать только библиотеку std, так что никакого повышения. Мне нужно разобрать строку вроде «14:30» и разобрать ее в:
unsigned char hour;
unsigned char min;
Мы получаем строку как строку c ++, поэтому прямой указатель отсутствует. Я перепробовал все варианты этого кода:
sscanf(hour.c_str(), "%hhd[:]%hhd", &hours, &mins);
но я продолжаю получать неправильные данные. Что я делаю неправильно.
Как уже упоминалось, вы должны использовать %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);
}
Надеюсь, поможет.
Ваша проблема, конечно, в том, что вы используете sscanf
, И это
Вы используете какой-то особенный тип для часов и минут, вместо
из int
, Поскольку вы анализируете строку ровно из 5 символов,
Самое простое решение — просто убедиться, что все символы легальны
в этом положении, используя isdigit
для символов 0, 1, 3 и 4, и
по сравнению с ':'
для персонажа 2. Как только вы это сделали, это тривиально
создать std::istringstream
из строки, и введите в
int
, char
(который вы потом проигнорируете) и второй int
, Если
Вы хотите быть более гибкими в вводе, например, позволяя вещи
лайк "9:45"
также вы можете пропустить начальные проверки и просто ввести
в int
, char
а также int
затем проверьте, что char
содержит ':'
(и что два int
находятся в пределах досягаемости).
Что касается того, почему ваш sscanf
терпит неудачу: вы просите, чтобы это соответствовало чему-то
лайк "12[:]34"
, который не что вы даете. Я не уверен
пытаетесь ли вы использовать "%hhd:%hhd"
или если по какой-то причине вы
действительно хотите класс персонажа, в этом случае вы должны использовать [
как
спецификатор преобразования, а затем игнорировать ввод: "%hhd%*[:]%hhd"
,
(Это позволит принять более одного символа в качестве разделителя,
но в остальном я не вижу преимущества. Кроме того, технически, по крайней мере,
с помощью %d
а затем передать адрес unsigned
интегральные типы
не поддерживается, %hhd
должен быть signed char
, На практике,
Тем не менее, я не думаю, что вы когда-либо столкнетесь с какими-либо проблемами для
неотрицательные входные значения меньше 128.)
Как упоминается Изоморфия 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
чтобы получить все до толстой кишки.
Я бы сделал это так
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
опции. Я бы тоже добавил проверку ошибок.
Я понимаю, что h
в %hhd
не является допустимым спецификатором формата. Правильный спецификатор для десятичных целых чисел %d
,
Как говорит Р.Мартиньо Фернандес в своем комментарии, %d:%d
будет соответствовать двум числам, разделенным двоеточием (‘:’).
Вы хотели что-то другое?
Вы всегда можете прочитать всю текстовую строку и проанализировать ее так, как хотите.
sscanf
с %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
вместо этого, но это немного больно, если вы действительно хотите это в char
:
std::stringstream stream("14:30");
unsigned int hour, min;
stream >> hour;
stream.ignore();
stream >> min;