如何正确解释数字(十六进制,八进制,十进制)

时间:2009-07-28 18:42:33

标签: c++ numbers string-parsing

我正在尝试编写一个输入 - 十六进制,八进制和小数 - 的程序,将它们存储在整数变量中,并将它们与它们转换为十进制形式一起输出。例如:

用户输入:0x43,0123,65

节目输出:

0x43 hexadecimal converts to 67 decimal
0123 octal converts to 83 decimal
65 decimal converts to 65 decimal

所以显然我需要一种解释数字的方法,但我不知道如何去做。我尝试了各种方法,例如将它们读入函数并将它们转换为字符串,反之亦然(请参阅here代码示例),但解释数字总是需要转换为某种格式来破坏原始输入。

我唯一能想到的是重载>>一次读取一个字符的运算符,如果它在输入的开头看到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();
}

5 个答案:

答案 0 :(得分:11)

看一下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

答案 1 :(得分:1)

您始终可以将其存储为要启动的字符串,并查看前两个字符以查看它们是否为0x:

std::string num;
std::cin >> num;

if (num[0] == '0' && num[1] == 'x')
{ 
  //handle
}

答案 2 :(得分:1)

我不确定是否有C ++方法可以做到这一点,但是如果你不介意一点C-ishness,你可以将这个东西读成char数组并使用类似{{{ 1}}。 sscanf(buffer, "%i", &output)将输入解释为十六进制,八进制或十进制,具体取决于其格式,就像您描述的那样。

编辑:啊,不知道%i也可以这样做。不理我。

答案 3 :(得分:1)

如果要保留基本信息(十六进制/八进制/十进制),则需要将该信息与整数值本身分开存储,并且需要至少解析输入的前几个字符string(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 */
}

答案 4 :(得分:0)

如果您确实 使用单个整数变量来存储您显示最终输出所需的所有信息,那么您必须使用整数变量的一部分来存储输入所在的原始基础。否则它不可恢复。