Как правильно интерпретировать числа (шестнадцатеричное число, октябрь, декабрь)
-
20-09-2019 - |
Вопрос
Я пытаюсь написать программу, которая принимает входные данные - шестнадцатеричные, октальные и десятичные числа -, сохраняет их в целочисленных переменных и выводит их вместе с их преобразованием в десятичную форму.Например:
Входные данные пользователя:0x43, 0123, 65
Выходные данные программы:
0x43 hexadecimal converts to 67 decimal
0123 octal converts to 83 decimal
65 decimal converts to 65 decimal
Поэтому, очевидно, мне нужен способ интерпретировать цифры, но я не уверен, как это сделать.Я пробовал различные методы, такие как считывание их в функцию и преобразование в строку, и наоборот (см. здесь для примеров кода), но интерпретация чисел всегда требует преобразования в некоторый формат, который уничтожает исходные входные данные.
Единственное, о чем я могу думать, это перегрузка оператора >>, который считывает символ за раз, и если он видит 0x или 0 в начале ввода, то он сохраняет весь ввод в строку, прежде чем он будет считан в int.Тогда программа каким-то образом должна была бы определить правильный манипулятор во время вывода.
Не уверен, что есть более простой способ сделать это, буду признателен за любую помощь.
Редактировать:Это было решено, но я решил опубликовать код, если кому-то будет интересно.
#include "std_lib_facilities.h"
void number_sys(string num, string& s)
{
if(num[0] == '0' && (num[1] != 'x' && num[1] != 'X')) s = "octal";
else if(num[0] == '0' && (num[1] == 'x' || num[1] == 'X')) s = "hexadecimal";
else s = "decimal";
}
int main()
{
cout << "Input numbers in hex, dec, or oct. Use 0xx to cancel.\n";
string a;
while(cin >> a){
if(a == "0xx")break;
string atype;
number_sys(a, atype);
int anum = strtol(a.c_str(), NULL, 0);
cout << a << setw(20-a.length()) << atype << setw(20) << "converts to" << setw(10)
<< anum << setw(10) << "decimal\n";
}
keep_window_open();
}
Решение
Взгляните на функцию strtol.
char * args[3] = {"0x43", "0123", "65"};
for (int i = 0; i < 3; ++i) {
long int value = strtol(args[i], NULL, 0);
printf("%s converts to %d decimal\n", args[i], value);
}
Выходы:
0x43 converts to 67 decimal
0123 converts to 83 decimal
65 converts to 65 decimal
Другие советы
Вы всегда можете сохранить его как строку для начала и посмотреть на первые два символа, чтобы убедиться, что они равны 0x:
std::string num;
std::cin >> num;
if (num[0] == '0' && num[1] == 'x')
{
//handle
}
Я не уверен, есть ли способ сделать это на C ++, но если вы не возражаете против небольшого C-ishness, вы можете перевести это в char
массивируйте и используйте что-то вроде sscanf(buffer, "%i", &output)
.Тот Самый %i
интерпретирует входные данные как шестнадцатеричные, восьмеричные или десятичные в зависимости от их формата, точно так, как вы описали.
Редактировать:Ах, я этого не знал strtol
мог бы также сделать это.Не обращай на меня внимания.
Если вы хотите сохранить базовую информацию (шестнадцатеричное/октябрьское/десятичное), вам нужно будет хранить эту информацию отдельно от самого целочисленного значения, и вам потребуется проанализировать хотя бы первые пару символов входной строки (sscanf (), strtol() и т. д. не сохранит для вас эту информацию).
Вы можете создать свой собственный мини-парсер, который сохраняет базу ввода и выполняет преобразование (код, пришедший мне в голову, непроверенный):
char inputStr[MAX_INPUT_LENGTH+1];
char *p;
int result = 0;
char values[128];
/**
* This enumeration serves double duty; it keeps track of what
* base the input was entered in, and it controls the state machine
* used to parse the input; from a didactic POV, this is probably bad form
*/
enum {
eStart,
eHexOrOctal,
eOctal,
eDecimal,
eHexadecimal,
eError
} eBase = eStart;
/**
* Use the values array as a table to map character constants to their corresponding
* integer values. This is safer than using an expression like *p - '0', in
* that it can work with character encodings where digits are not consecutive.
* Yes, this wastes a little space, but the convenience makes
* up for it IMO. There are probably better ways to do this.
*/
values['0'] = 0; values['1'] = 1; values['2'] = 2; values['3'] = 3;
values['4'] = 4; values['5'] = 5; values['6'] = 6; values['7'] = 7;
values['8'] = 8; values['9'] = 9; values['a'] = 10; values['b'] = 11;
values['c'] = 12; values['d'] = 13; values['e'] = 14; values['f'] = 15;
/**
* Insert code to get input string here
*/
for (p = inputStr; *p != 0; p++)
{
/**
* Cycle through each character in the input string, adjusting the state
* of the parser as necessary. Parser starts in the eStart state.
*/
switch(eBase)
{
/**
* Start state -- we haven't parsed any characters yet
*/
case eStart:
if (*p == '0') eBase = eHexOrOctal; // leading 0 means either hex or octal
else if (isdigit(*p))
{
eBase = eDecimal; // leading non-0 digit means decimal
result = values[*p];
}
else eBase = eError; // no other character may start an integer constant
break;
/**
* HexOrOctal -- we've read a leading 0, which could start either a hex or
* octal constant; we need to read the second character to make a determination
*/
case eHexOrOctal:
if (tolower(*p) == 'x') base = eHexadecimal;
else if (isdigit(*p) && *p != '8' && *p != '9')
{
base = eOctal;
result = values[*p];
}
else eBase = eError;
break;
/**
* Octal -- we are parsing an octal constant
*/
case eOctal:
if (isdigit(*p) && *p != '8' && *p != '9')
{
result *= 8;
result += values[*p];
}
else eBase = eError;
break;
/**
* Decimal -- we are parsing a decimal constant
*/
case eDecimal:
if (isdigit(*p))
{
result *= 10;
result += values[*p];
}
else eBase = eError;
break;
/**
* Hexadecimal -- we are parsing a hex constant
*/
case eHexadecimal:
if (isxdigit(*p))
{
result *= 16;
result += values[tolower(*p)];
}
else eBase = eError;
break;
/**
* String is not a properly formatted integer constant in
* any base; once we fall into the error state, we stay there.
*/
case eError:
default:
break;
}
}
if (eBase != eError)
{
printf("input: %s ", inputStr); fflush(stdout);
switch(eBase)
{
case eOctal: printf("octal "); break;
case eHexadecimal: printf("hexadecimal "); break
default: break;
}
fflush(stdout);
printf("converts to %d decimal\n", result);
}
else
{
/** Print a suitable error message here */
}
Если вы буквально иметь Чтобы использовать одну целочисленную переменную для хранения всей информации, которая вам нужна для отображения окончательного результата, вам придется использовать часть целочисленной переменной для хранения исходной базы, в которой находились входные данные.В противном случае оно не подлежит восстановлению.