char
が表す数字1文字をint
に変換したいことがあった。
具体的には、(char)'1' -> (int)1
とか(char)'9' -> (int)9
ということ。
実装1
想定するケースは高々10個なので、switch-case
文で実装してみた。
(数字以外が入力された場合は-1
を返す)
int ctoi(const char c){
switch(c){
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
default : return -1;
}
}
実装2
char
において数字を表す値には規格においてある程度決まりがあるという話を聞いた。
実際見てみると、Cでは 5.2.1 Character sets に、C++では 2.3 Character sets に次のような文があった。
(章番号はC:n1570、C++:n4567のドラフトのものである)
In both the source and execution basic character sets, the value of each character after
0
in the above list of decimal digits shall be one greater than the value of the previous.
(基本ソース文字集合および基本実行文字集合の双方において、上の表の0
以降のそれぞれの数字に対応する文字の値は、その直前にある文字の値より1だけ大きくなければならない)
つまり、0
を基準としてchar
の値を比較すれば数字の値が得られるわけである。
また、数字を表す文字コードは固まって存在するので、数字以外が入力された場合を判定できる。
この方針で同じ機能を実装すると次のようになる。
(やはり数字以外が入力された場合は-1
を返す)
int ctoi(const char c){
if('0' <= c && c <= '9') return (c-'0');
return -1;
}
おまけ
数字の場合と同じ感じで、大文字英字がアルファベット順で何番目か(たとえば'A'
なら1
、'Z'
なら26
)を返すような関数を作ることもできる。
ただし、こちらは文字コードに関する規格上の保証はなく、大文字英字が'A'
から順番に隙間なく配置されていない文字集合(EBCDICなど)では動かない。
int alphabet_pos(const char c){
if('A' <= c && c <= 'Z') return (c-'A'+1);
return -1;
}