任意进制之间的转换

任意进制之间的转换

有一些进制转换的练习,例如10进制数转换为2进制数,或者反过来。闲来无事,用Rust写了一个任意进制互相转换的代码。

#[derive(Debug, PartialEq, Eq)]
// 定义几种错误情况
pub enum Error {
    InvalidInputBase,      // 输入进制不符合要求
    InvalidOutputBase,     // 输出进制不符合要求
    InvalidDigit(u32),     // 输入字串出现了大于 from_base 的字符
}

// 定义几种常见的进制前缀
const BASE2: &str = "0b";
const BASE8: &str = "0o";
const BASE16: &str = "0x";

// 任意进制之间的转换
pub fn convert(number_str: &str, from_base: u32, to_base: u32) -> Result<String, Error> {
    // 排除两种基数输入错误情况
    if from_base <= 1 {
        return Err(Error::InvalidInputBase);
    };
    if to_base <= 1 || to_base > 61 {
        return Err(Error::InvalidOutputBase);
    }

    // 首先将输入的字符串转换为 十进制 数字
    let mut number = 0_i128;
    for (digit, num_char) in number_str.chars().rev().enumerate() {
        // 将 num_char 从 char 类型转换为 数值类型
        let num = match num_char {
            ('0'..='9') => (0..=9).zip('0'..='9').find(|(_, b)| *b == num_char).unwrap().0,
            ('A'..='Z') => (10..=35).zip('A'..='Z').find(|(_, b)| *b == num_char).unwrap().0,
            ('a'..='z') => (36..=61).zip('a'..='z').find(|(_, b)| *b == num_char).unwrap().0,
            _ => panic!("Invalid input!"),
        } as u32;
        if num >= from_base {
            return Err(Error::InvalidDigit(num));
        }
        number += num as i128 * (from_base as i128).pow(digit as u32);
    }

    if number == 0 {
        return Ok("0".into());
    }

    let prefix: String = match to_base {
        2 => BASE2.into(),
        8 => BASE8.into(),
        16 => BASE16.into(),
        _ => "".into(),
    };
    
	// remainder 用于保存取余的结果
    let mut remainder = Vec::new();
    while number > 0 {
        remainder.push(number % (to_base as i128));
        number /= to_base as i128;
    }
    
	// 将余数逆序
    remainder.reverse();

    let res: String = remainder.iter().fold(prefix, |mut acc, x| {
        match x {
            x @ (10..=35) => acc.push(('A'..='Z').nth((x - 10) as usize).unwrap()),
            x @ (36..=61) => acc.push(('a'..='z').nth((x - 36) as usize).unwrap()),
            _ => acc.push_str(&x.to_string()),
        }
        acc
    });

    Ok(res)
}

思路:
from_base代表输入的字符串代表的数字的进制,将输入字符串统一转换为十进制表示的数字,然后再将十进制数字通过取余的方法得到需要进制的数字。


步骤:

  • 将输入的字符串解析为数字,因为存在A~z英文字母,需要转换为对应的数字,使用
    (10..=35).zip('A'..='Z').find(|(_, b)| *b == num_char).unwrap().0,进行转换
  • 在循环转换字符到数字的同时,进行相加,得到十进制数
  • 最后再将十进制数转换为要求输出的进制,同样的,如果得到的余数大于9,那么用对应的
    英文字母替代

代码解析:

  • 对于'0' ~ '9'之间的字符,用zip结合find函数,得到对应的数字表示
  • 对于> '9' 的字符,同样结合zipfind得到索引,只不过要加上基数10
    例如十六进制表示中,A代表的数字是10,以此类推
  • 对于> 'Z'的字符,基数就是10再加26个字母,也就是36
  • 限制小写字母z为最大的数字字符,因为在ascii码表中,z 在英文字母范围内是最大的。z对应的索引下标为2525 + 36 = 61,所以规定输出的进制最大为61进制

在转换的过程中,定义了常见的进制前缀,添加到了结果字符串中。


本人水平有限,有不当的地方,欢迎大家批评指正。

好的,以下是一个实现任意进制之间互相转换的例子: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> // 将一个任意进制转换为十进制数 int anyBaseToDecimal(char* num, int base) { int result = 0; int i = 0; int len = strlen(num); // 按权展开法 for (i = 0; i < len; i++) { int digit; if (num[i] >= '0' && num[i] <= '9') { digit = num[i] - '0'; } else if (num[i] >= 'A' && num[i] <= 'Z') { digit = num[i] - 'A' + 10; // A~Z表示的数字 } else { printf("Invalid input!\n"); // 非法输入 return 0; } result = result * base + digit; } return result; } // 将一个十进制转换任意进制数 char* decimalToAnyBase(int num, int base) { int quotient = num; int remainder; char* result = (char*) malloc(32 * sizeof(char)); // 分配足够的内存空间,最多支持32位进制数 char* buffer = (char*) malloc(32 * sizeof(char)); int i = 0; // 除基取余法 while (quotient != 0) { remainder = quotient % base; quotient = quotient / base; if (remainder < 10) { buffer[i++] = remainder + '0'; } else { buffer[i++] = remainder - 10 + 'A'; // 大于等于10时,使用A~Z表示 } } int j = 0; // 反转字符串 for (j = 0; j < i; j++) { result[j] = buffer[i-j-1]; } result[j] = '\0'; // 字符串结尾需要加上'\0' free(buffer); // 释放内存空间 return result; } // 将一个任意进制转换为另一个任意进制数 char* anyBaseToAnyBase(char* num, int from, int to) { int decimal = anyBaseToDecimal(num, from); // 先将任意进制转换为十进制数 char* result = decimalToAnyBase(decimal, to); // 再将十进制转换为目标进制数 return result; } int main() { char* num = "12345"; int from = 10; // 数字是10进制 int to = 16; // 转换为16进制 char* result = anyBaseToAnyBase(num, from, to); printf("%s in base %d: %s in base %d\n", num, from, result, to); free(result); // 释放内存空间 return 0; } ``` 以上代码可以将一个任意进制转换为另一个任意进制数。你可以根据自己的需要来修改进制数和测试数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值