ディジタルへんかん

6148 ワード

ファイル:
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 << "
>>> "; } return 0; }