Как правильно интерпретировать числа (шестнадцатеричное число, октябрь, декабрь)

StackOverflow https://stackoverflow.com/questions/1195979

  •  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 */
}

Если вы буквально иметь Чтобы использовать одну целочисленную переменную для хранения всей информации, которая вам нужна для отображения окончательного результата, вам придется использовать часть целочисленной переменной для хранения исходной базы, в которой находились входные данные.В противном случае оно не подлежит восстановлению.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top