文件:
lib/NumberConvert.hpp
#ifndef NUMBERCONVERT_HPP_
#define NUMBERCONVERT_HPP_
#include <string>
#include <map>
#include <exception>
#include <sstream>
namespace HyertyMath {
/* **** 主类定义 **** */
class NumberConvert
{
public:
/* **** 嵌套类声明 **** */
class InvalidBase;
class InvalidFormat;
/* **** 类成员声明 **** */
// 数字映射表,映射一个char字符和它表示的int权值
static std::map<char, int> const &digitMap;
static std::string const charMap;
// 解码,给定一个数字的字符串字面值形式和其基数base(进制数),解码为一个int值
static int decode(std::string const &s, int base);
// 编码,将一个int值,以base为基数,编码为字符串
static std::string encode(int n, int base);
// 编码转换,将以fromBase为基的数转换为以toBase为基的形式
static std::string convert(std::string const &s, int fromBase, int toBase) {
int n = decode(s, fromBase);
return encode(n, toBase);
}
// 辅助函数
static void validateBase(int base); // 效验基(进制)是否合法
static void validateFormat(std::string const &s, int base); // 效验输入格式
public:
NumberConvert(int from=10, int to=10) {
setFrom(from);
setTo(to);
}
// virtual ~NumberConvert() { } // DO NOT intend to be a base class
void setFrom(int from) {
validateBase(from);
this->from = from;
}
void setTo(int to) {
validateBase(to);
this->to = to;
}
int decode(std::string const &s) {
return decode(s, from);
}
std::string encode(int n) {
return encode(n, to);
}
std::string convert(std::string const &s) {
validateFormat(s, from); // 效验输入格式是否有效
int n = decode(s);
return encode(n);
}
private:
int from, to;
};
/* **** TODO: 嵌套类定义 **** */
class NumberConvert::InvalidBase: public std::exception {
public:
InvalidBase(int base) {
std::stringstream msgBuf;
msgBuf << "Invalid base: " << base << "!";
msg = msgBuf.str();
}
InvalidBase &operator=(InvalidBase const &e) {
msg = e.msg;
return *this;
}
~InvalidBase() throw() { }
char const *what() const throw() {
return msg.c_str();
}
private:
std::string msg;
};
class NumberConvert::InvalidFormat: public std::exception {
public:
char const *what() const throw() {
return "Invalid format!";
}
};
/* **** 类内联函数定义 **** */
inline void NumberConvert::validateBase(int base) {
if (base < 2 || base > 36) {
throw InvalidBase(base);
}
}
inline void NumberConvert::validateFormat(std::string const &s, int base) {
std::string::const_iterator iter = s.begin(), end = s.end();
while(iter != end) {
std::map<char, int>::const_iterator mIter = digitMap.find(*iter);
if (mIter == digitMap.end() || mIter->second >= base) {
throw InvalidFormat();
}
++iter;
}
}
}
#endif /*NUMBERCONVERT_HPP_*/
文件:
lib/NumberConvert.cpp
#include "NumberConvert.hpp"
#include <list>
namespace {
std::map<char ,int> &getDigitMap();
} // end of anonymous namespace
namespace HyertyMath {
std::map<char, int> const &NumberConvert::digitMap = getDigitMap();
std::string const NumberConvert::charMap(
"0123456789abcdefghigklmnopqrstuvwxyz");
// 解码,给定一个数字的字符串字面值形式和其基数base(进制数),解码为一个int值
int NumberConvert::decode(std::string const &s, int base) {
int n = 0;
std::string::const_iterator iter = s.begin(), end = s.end();
while(iter != end) {
n = n * base + digitMap.find(*iter)->second;
++iter;
}
return n;
}
// 编码,将一个int值,以base为基数,编码为字符串
std::string NumberConvert::encode(int n, int base) {
std::list<char> buf;
int q, r;
while(n >= base) {
q = n / base;
r = n % base;
buf.push_front(charMap[r]);
n = q;
}
// 当 n < base 时一定 q = 0, r = n
buf.push_front(charMap[n]);
return std::string(buf.begin(), buf.end());
}
}
namespace {
// 正常情况下,这个函数只应该在初始化NumberConvert::digitMap时被调用一次
std::map<char ,int> &getDigitMap() {
static std::map<char, int> digitMap;
// 首次调用标识,防止意外的多次调用时重复设置digitMap的值
static bool firstTime = true;
if (!firstTime) {
return digitMap;
}
for(char c = '0'; c <= '9'; ++c) {
digitMap[c] = c - '0';
}
char c1 = 'a', c2 = 'A';
for( ; c1 <= 'z' && c2 <= 'Z'; ++c1, ++c2) {
digitMap[c1] = c1 - 'a' + 10;
digitMap[c2] = c2 - 'A' + 10;
}
firstTime = false;
return digitMap;
}
} // end of anonymous namespace
文件:
main.cpp
#include <iostream>
#include <string>
#include <exception>
#include "lib/NumberConvert.hpp"
int main(int argc, char **argv) {
std::string s;
int from, to;
std::cout << ">>> ";
while(std::cin >> s >> from >> to) {
std::string s2;
try {
s2 = HyertyMath::NumberConvert(from, to).convert(s);
}
catch(std::exception &e) {
s2 = e.what();
}
catch(...) {
throw;
}
std::cout << s2 << "\n>>> ";
}
return 0;
}