C++直接对字符串进行进制转换

问题描述

我们都知道,当我们需要进制转换时,可以有以下的方法:
1.字符串 到 整型:使用 atoi
2.整型 到 字符串:使用 sprintf

但是,如果我们想直接对字符串进行进制转换,又或者是输入的整数太长,通常的方法就无法满足我们的需求

原理分析

首先我们知道,任意 n n n进制数( n ∈ N , n ≥ 2 n\in N,n \ge 2 nN,n2)可以写成以下的形式:
a m a m − 1 . . . a 1 a 0 = a 0 n 0 + a 1 n 1 + . . . + a m − 1 n m − 1 + a m n m ( m ∈ N ) a_ma_{m-1}...a_1a_0 = a_0 n^0+a_1n^1+...+a_{m-1}n^{m-1}+a_mn^m \quad (m \in N) \\ amam1...a1a0=a0n0+a1n1+...+am1nm1+amnm(mN)

例如:
十进制数 6371 6371 6371 ,可以表示成:
6371 = 1 ∗ 1 0 0 + 7 ∗ 1 0 1 + 3 ∗ 1 0 2 + 6 ∗ 1 0 3 6371 = 1 *10^0 + 7 * 10^1 + 3*10^2+6*10^3 6371=1100+7101+3102+6103

十六进制数 7 f e 6 7fe6 7fe6 ,可以表示成:
7 f e 6 = 6 ∗ 1 6 0 + 14 ∗ 1 6 1 + 15 ∗ 1 6 2 + 7 ∗ 1 6 3 7fe6 = 6 * 16^0 + 14*16^1+15*16^2+7*16^3 7fe6=6160+14161+15162+7163
知道了这个之后,我们可以使用下面得方法进行简单的进制转换,如:
6371 = 1 ∗ 1 0 0 + 7 ∗ 1 0 1 + 3 ∗ 1 0 2 + 6 ∗ 1 0 3 6371 = 1 *10^0 + 7 * 10^1 + 3*10^2+6*10^3 6371=1100+7101+3102+6103

我们将十进制数 6371 6371 6371 转换为 十六进制数,因为有:
1 0 0 = 1 6 0 1 0 1 = 10 ∗ 1 0 0 = 10 ∗ 1 6 0 1 0 2 = 10 ∗ 1 0 1 = 100 ∗ 1 6 0 = 4 ∗ 1 6 0 + 6 ∗ 1 6 1 1 0 3 = 10 ∗ 1 0 2 = 40 ∗ 1 6 0 + 60 ∗ 1 6 1 = 8 ∗ 1 6 0 + 68 ∗ 1 6 1 = 8 ∗ 1 6 0 + 14 ∗ 1 6 1 + 3 ∗ 1 6 2 \begin{aligned} 10^0& = 16^0 \\10^1&=10*10^0= 10*16^0 \\10^2& =10*10^1 =100*16^0 = 4*16^0 + 6 * 16^1 \\10^3&=10*10^2=40*16^0+60*16^1=8*16^0+68*16^1= 8*16^0 + 14*16^1 + 3*16^2 \end{aligned} 100101102103=160=10100=10160=10101=100160=4160+6161=10102=40160+60161=8160+68161=8160+14161+3162

我们将其全部代入上面的式子,有:
6371 = 1 ∗ 1 6 0 + 7 ∗ ( 10 ∗ 1 6 0 ) + 3 ∗ ( 4 ∗ 1 6 0 + 6 ∗ 1 6 1 ) + 6 ∗ ( 8 ∗ 1 6 0 + 14 ∗ 1 6 1 + 3 ∗ 1 6 2 ) = ( 1 + 70 + 12 + 48 ) ∗ 1 6 0 + ( 18 + 84 ) ∗ 1 6 1 + 18 ∗ 1 6 2 = 131 ∗ 1 6 0 + 102 ∗ 1 6 1 + 18 ∗ 1 6 2 = ( 3 ∗ 1 6 0 + 8 ∗ 1 6 1 ) ∗ 1 6 0 + ( 6 ∗ 1 6 0 + 6 ∗ 1 6 1 ) ∗ 1 6 1 + ( 2 ∗ 1 6 0 + 1 6 1 ) ∗ 1 6 2 = 3 ∗ 1 6 0 + 14 ∗ 1 6 1 + 8 ∗ 1 6 2 + 1 ∗ 1 6 3 \begin{aligned} 6371 &= 1 *16^0 + 7 * (10*16^0) + 3*(4*16^0 + 6 * 16^1)+6*(8*16^0 + 14*16^1 + 3*16^2) \\ &= (1+70+12+48)*16^0 + (18+84)*16^1+18*16^2 \\ &=131*16^0 +102*16^1+18*16^2 \\ &= (3*16^0+8*16^1)*16^0 + (6*16^0+6*16^1)*16^1+(2*16^0+16^1)*16^2 \\ &= 3*16^0 + 14*16^1 + 8*16^2 + 1*16^3 \end{aligned} 6371=1160+7(10160)+3(4160+6161)+6(8160+14161+3162)=(1+70+12+48)160+(18+84)161+18162=131160+102161+18162=(3160+8161)160+(6160+6161)161+(2160+161)162=3160+14161+8162+1163

可得转换后的十六进制数为 18 e 3 18e3 18e3

我们总结一下,对于 n n n进制数( n ∈ N , n ≥ 2 n\in N,n \ge 2 nN,n2)
∀ m ∈ N a m a m − 1 . . . a 1 a 0 = a 0 n 0 + a 1 n 1 + . . . + a m − 1 n m − 1 + a m n m \forall m \in N \\ a_ma_{m-1}...a_1a_0 = a_0 n^0+a_1n^1+...+a_{m-1}n^{m-1}+a_mn^m mNamam1...a1a0=a0n0+a1n1+...+am1nm1+amnm
我们要将其转换为 n ′ n' n进制数( n ′ ∈ N , n ≥ 2 n'\in N,n \ge 2 nN,n2)
先列出下面的一串式子:
n 0 = b 00 n ′ 0 + . . . b 0 c 0 n ′ c 0 n 1 = b 10 n ′ 0 + . . . b 1 c 1 n ′ c 1 . . . n m = b m 0 n ′ 0 + . . . b m c m n ′ c m n^0 = b_{00}n'^0 + ...b_{0c_0}n'^{c_0} \\n^1 = b_{10}n'^0 + ...b_{1c_1}n'^{c_1} \\... \\n^m = b_{m0}n'^0 + ...b_{mc_m}n'^{c_m} n0=b00n0+...b0c0nc0n1=b10n0+...b1c1nc1...nm=bm0n0+...bmcmncm

然后我们将上面得式子代回 a m a m − 1 . . . a 1 a 0 a_ma_{m-1}...a_1a_0 amam1...a1a0中,得
d 0 n ′ 0 + d 1 n ′ 1 + . . . d m ′ − 1 n ′ m ′ − 1 + d m ′ n ′ m ′ d_{0} n'^0 + d_1n'^1+...d_{m'-1}n'^{m'-1}+d_{m'}n'^{m'} d0n0+d1n1+...dm1nm1+dmnm

即进行转换后的数字为 d m ′ d m ′ − 1 . . . d 1 d 0 d_{m'}d_{m'-1}...d_1d_0 dmdm1...d1d0 (超过十进制要进行对应字符替换)

虽然这种进制转换方法手算并不方便,效率也不算高,但对于字符串的进制转换来说,是比较有效的一个方法

代码实现

步骤:

  1. 实现将 n n n的任意次方分解为 n ′ n' n的任意次方线性组合
  2. 将分解后的 n n n乘上系数,放到新的字符串中
  3. 得到进制转换后的字符串

C++代码如下:

  1. 头文件 SystemTransform.h
//SystemTransform.h
#ifndef _YYYCZ_SYSTEM_TRANSFORM_NUMBER_LIST

#define _YYYCZ_SYSTEM_TRANSFORM_NUMBER_LIST "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

#include<string>

namespace YYYCZ
{
	//直接对字符串进行进制转换
	//参数依次为 1.转换的字符串 2.原进制 3.新进制
	//可转换的进制的范围为 2 - 62
	//超出该范围不会进行转换,并返回原字符串
	//转换后 0 - 62 对应字符依次为 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
	std::string systemTransform(const std::string& num_str, char original_carry, char target_carry);

	//使用提供的字符直接对字符串进行进制转换
	//参数依次为 1.转换的字符串 2.原进制 3.新进制 4.新进制的字符 5.原进制的字符
	//必须提供目标进制的转换字符,原进制可不提供
	//注意:涉及到的进制转换不建议超过128进制,并且绝对不能超过256进制
	//注意:进制数若超出对应字符数将不进行转换,并返回原字符串
	std::string systemTransform(const std::string& num_str, char original_carry, char target_carry,
		const char target_char_list[], const char char_list[] = _YYYCZ_SYSTEM_TRANSFORM_NUMBER_LIST);
}

#endif
  1. 源文件 SystemTransform.cpp
//SystemTransform.cpp
#include<vector>
#include "SystemTransform.h"

std::vector<uint16_t> indexMutiply(const std::vector<uint16_t>& _a, const std::vector<uint16_t>& _b, char _carry)
{
	std::vector<uint16_t> result(_a.size() + _b.size() - 1, 0);
	size_t index = 0;
	char temp = 0;

	for (auto itr = result.begin(); itr != result.end(); itr++, index++)
	{
		auto _aitr = _a.begin() + (index >= _b.size() ? index - _b.size() + 1 : 0);
		auto _bitr = _b.begin() + (index - (index >= _b.size() ? index - _b.size() + 1 : 0) + 1);
		for (size_t x = (index >= _b.size() ? index - _b.size() + 1 : 0); x <= std::min(_a.size() - 1, index); x++)
			*itr += *(_aitr++) * *(--_bitr);
	}

	for (auto itr = result.begin(); itr != result.end(); itr++, index++)
		if (*itr >= _carry && itr != result.end() - 1)
			*(itr + 1) += *itr / _carry,
			* itr %= _carry;

	while (result.back() >= _carry)
		temp = result.back() / _carry,
		result.back() %= _carry,
		result.push_back(temp);

	return result;
}

bool systemTransform_toNum(char& _num, char _carry,const char _char_list[])
{
	for (char i = 0; i < _carry; i++)
	{
		if (_char_list[i] == _num)
		{
			_num = i;
			return true;
		}
	}
	return false;
}

std::string YYYCZ::systemTransform(const std::string& _text, char original_carry, char target_carry,
	const char target_char_list[], const char char_list[])
{
	if (original_carry == 0 || original_carry == 1 || original_carry > strlen(char_list) ||
		target_carry == 0 || target_carry == 1 || target_carry > strlen(target_char_list) ||
		original_carry == target_carry)
		return _text;

	std::vector<uint16_t> original_split, act_split = { 1 }, temp_save;
	char temp_num = original_carry;
	uint16_t temp_unum = 0;
	bool positive = true;

	do
	{
		original_split.push_back(temp_num % target_carry);
		temp_num /= target_carry;
	} while (temp_num > 0);

	for (auto i = _text.rbegin(); i != _text.rend(); i++)
	{
		temp_num = *i;
		if (systemTransform_toNum(temp_num, original_carry, char_list))
		{
			if (act_split.size() > temp_save.size())
				temp_save.resize(act_split.size(), 0);

			auto temp_itr = temp_save.begin();
			for (auto j = act_split.begin(); j != act_split.end(); j++)
			{
				*temp_itr += (uint16_t)(*j) * (uint16_t)temp_num;

				if (temp_itr + 1 == temp_save.end())
				{
					while (temp_save.back() >= target_carry)
					{
						temp_unum = temp_save.back() / target_carry;
						temp_save.back() %= target_carry;
						temp_save.push_back(temp_unum);
					}
					break;
				}
				else
				{
					if (*temp_itr >= target_carry)
					{
						*(temp_itr + 1) += *temp_itr / target_carry;
						*temp_itr %= target_carry;
					}
					temp_itr++;
				}
			}

			act_split = indexMutiply(original_split, act_split, target_carry);
		}
		else
		{
			if (*i == '-')
				positive = false;
			break;
		}
	}

	for (auto i = temp_save.begin(); i != temp_save.end(); i++)
		*i = target_char_list[*i];

	if (!positive)
		temp_save.push_back('-');

	std::string result;
	result.resize(temp_save.size());
	auto str_itr = result.rbegin();
	for (auto i = temp_save.begin(); i != temp_save.end(); i++, str_itr++)
		*str_itr = *i;

	return result;
}

std::string YYYCZ::systemTransform(const std::string& num_str, char original_carry, char target_carry)
{
	return YYYCZ::systemTransform(num_str, original_carry, target_carry, _YYYCZ_SYSTEM_TRANSFORM_NUMBER_LIST);
}
  1. 测试代码 main.cpp
//main.cpp
#include<iostream>
#include "SystemTransform.h"
using namespace std;
using namespace YYYCZ;

//将十进制数转换为2、4、8、16、26、32、36、52、58、62、64进制数
int main()
{
	string d_num_str;

	cout << "请输入一个十进制数:";
	while (cin >> d_num_str)
		cout << "进制转换后:" << endl,
		cout << "二进制:" << systemTransform(d_num_str, 10, 2) << endl,
		cout << "四进制:" << systemTransform(d_num_str, 10, 4) << endl,
		cout << "八进制:" << systemTransform(d_num_str, 10, 8) << endl,
		cout << "十进制:" << systemTransform(d_num_str, 10, 10) << endl,
		cout << "十六进制:" << systemTransform(d_num_str, 10, 16) << endl,
		cout << "二十六进制:" << systemTransform(d_num_str, 10, 26, "abcdefghijklmnopqrstuvwxyz") << endl,
		cout << "三十二进制:" << systemTransform(d_num_str, 10, 32, "0123456789ABCDEFGHJKMNPQRSTVWXYZ") << endl,
		cout << "三十六进制:" << systemTransform(d_num_str, 10, 36, "0123456789abcdefghijklmnopqrstuvwxyz") << endl,
		cout << "五十二进制:" << systemTransform(d_num_str, 10, 52, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") << endl,
		cout << "五十八进制:" << systemTransform(d_num_str, 10, 58, "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ") << endl,
		cout << "六十二进制:" << systemTransform(d_num_str, 10, 62) << endl,
		cout << "六十四进制:" << systemTransform(d_num_str, 10, 64, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") << endl,
		cout << "\n请输入一个十进制数:";

	return 0;
}

测试结果

测试结果1
测试结果2
针 不 戳 , 转 换 出 来 的 结 果 针 不 戳 针不戳,转换出来的结果针不戳
可以看到十进制数 6371 6371 6371 转换为十六进制数结果为 18 e 3 18e3 18e3 ,与上面结果相同
对于超长整数也能进行正常的转换

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值