数値を正しく解釈する方法 (16 進数、10 進数、10 進数)
-
20-09-2019 - |
質問
16進数、8進数、10進数の入力を受け取り、それらを整数変数に格納し、10進数形式への変換とともに出力するプログラムを作成しようとしています。例えば:
ユーザー入力:0x43、0123、65
プログラムの出力:
0x43 hexadecimal converts to 67 decimal
0123 octal converts to 83 decimal
65 decimal converts to 65 decimal
したがって、数値を解釈する方法が必要であることは明らかですが、どうすればよいかわかりません。それらを関数に読み取って文字列に変換したり、その逆を行ったりするなど、さまざまな方法を試しました(「 ここ コード例については)、数値を解釈するには、元の入力を破棄する何らかの形式への変換が常に必要になります。
私が考えることができる唯一のことは、一度に 1 文字を読み取る >> 演算子をオーバーロードすることです。入力の先頭に 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
他のヒント
常にそれを文字列として保存して開始し、最初の 2 文字を調べて 0x かどうかを確認できます。
std::string num;
std::cin >> num;
if (num[0] == '0' && num[1] == 'x')
{
//handle
}
C++ でこれを行う方法があるかどうかはわかりませんが、少し C っぽくても構わない場合は、これを次のように読み込むことができます。 char
配列して次のようなものを使用します sscanf(buffer, "%i", &output)
. 。の %i
説明したように、入力をその形式に応じて 16 進数、8 進数、または 10 進数として解釈します。
編集:ああ、それは知りませんでした strtol
これもできます。私を無視。
基本情報 (hex/oct/dec) を保存したい場合は、その情報を整数値自体とは別に保存する必要があり、入力文字列 (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 */
}
文字通りに言うなら 持っている 最終出力を表示するために必要なすべての情報を格納するために単一の整数変数を使用するには、入力が含まれていた元のベースを格納するために整数変数の一部を使用する必要があります。そうしないと回復できません。