初识Base64解码

题目描述

Base64 是网络上最常见的用于传输 8Bit 字节代码的编码方式之一。Base64 要求把每三 个 8Bit 的字节转换为四个 6Bit 的字节,然后把 6Bit 再添两位高位 0,组成四个 8Bit 的字 节,该 8Bit 的字节转化为十进制后一定表示一个 0-63 的整数。将这个整数对应转换表中的 字符便是编码后的结果。为简单起见,我们不考虑实际编码是的换行符,并且原码的长度一 定是 3 的倍数,因此编码后长度一定是 4 的倍数。转换后的字符串理论上将要比原来的长 1/3。转换表见百度。

下面举一个编码的例子。 原码为 abc。’a’,’b’,’c’的 ASCII 码分别为 97,98,99,对应二进制为 01100001,01100010,01100011,连起来是 011000010110001001100011,每六个分为一组, 每组前面补两个 0,便是 00011000,00010110,00001001,00100011,分别是 24,22,9,35,所以编码后是 YWJj。 现在给出编码后的结果,请你求出原码。

输入格式

输入文件只有一行,为一个字符串表示编码后的结果。数据保证字符串的长度为 4 的倍数且合法,且原码中均为常用字符,且不含空格和回车。

输出格式

输出文件只有一行,表示原码
【样例输入】 SGVsbG8h
【样例输出】 Hello!
【数据规模】
设 L 为编码的总长度。
对于 30%的数据,1≤L≤200 对于 100%的数据,1≤L≤10000 L 为 4 的倍数。

【输入文件】 base.in
【输出文件】 base.out
【时间限制】 1 秒
【空间限制】 128 MB


分析:

一个字符串,比如“abc
首先操作字符a
字符abc对应的ASCII码为979899,将97,98,99转换成八位二进制:01100001 01100010 01100011.
将这三个二进制组合起来,得到011000010110001001100011
接下来,每6个二进制位为一组,每一组前面补俩0,这样又得到了八位的二进制。
分组后: 00011000, 00010110, 00001001, 00100011
转成十进制: 24, 22, 9, 35
这四个十进制数就是索引了。通过索引表,我们可以得到转换后的base64编码:YWJj


知道了编码方法,解码方法就知道了。
假定base64编码为YWJj

首先,我们读入base64编码的第一个字符。比如:Y
由索引表:24 对应 Y,反推出Y对应的索引为24。

然后,我们把24转换成一个六位二进制数011000。(这个二进制数必定是6位以内的二进制数,因为索引最多到63,也就是111111
然后,我们操作base64编码的第二个字符。比如:W
由索引表:22对应 W,反推出W对应的索引为22。
然后,我们把22转换成一个六位二进制数010110

然后,我们操作base64编码的第三个字符。比如:J
由索引表:9对应 J,反推出J对应的索引为9。
然后,我们把9转换成一个六位二进制数010001

然后,我们操作base64编码的第四个字符。比如:j
由索引表:35对应 J,反推出J对应的索引为35。
然后,我们把35转换成一个六位二进制数100011

我们把所有的六位二进制数拼到一起,得到011000010110010001100011
然后以八个二进制位为一组,将这一串二进制分割,得到011000010110010001100011
将它们转换成十进制,得到979899
再根据ASCII码,推出对应的字符。

Done!

// Code::Blocks 编译通过
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
char base64[20000];//字符串数组
int  bin[90000];//把base64编码转成二进制后的二进制数组
char decode[20000];//解码后的
static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";//索引

int ReadFile()
{
    freopen("base.in","r",stdin);
    freopen("base.out","w",stdout);
    int i=0;
    while(scanf("%c", &base64[i]) == 1)
    {
        if((int)base64[i] == '=')//读到等号就结束
        {base64[i] = 0;return 0;}
        i++;
    }
}

void Dec2Bin(int num, int *a)//十进制转二进制。结果存放在传入的数组里
{//要转换的数字,接收最后的值的数组(数组从0到7,一共六位【6个二进制数】)
    int i=0;
    for(int j=0; j<6; j++)
        a[j] = 0;
    while(num)
    {
        a[i++] = (num%2)?1:0;
        num >>= 1;
    }
}

long Bin2Dec(char *s) /*将以数组形式存储的二进制数字转换为对应的十进制数字*/
{
    long rt=0;
    int n=0;
    while (s[n])
    {
        n++;
    }
    for (int i=n--; i>=0; i--)
    {
        rt |= (s[i]-48)<<n-i;
    }
    return rt;
}

int Digits2Index(char a)//将一位base64编码转为索引表中的索引
{
    if(a>='A' && a<='Z')
        return a-'A';
    if(a>='a' && a<='z')
        return a-'a' + 26;
    if(a>='0' && a<='9')
        return a-'0' + 52;
    if(a=='+')
        return 62;
    if(a=='/')
        return 63;
    return -1;
}

int Proc(char s[], int s_len)
{
    int temp[6];//用来储存返回的二进制数据的整数数组temp[6]
    int t;//记录bin数组长度
    for(int i=0; i<s_len; i++)//把base64编码转换成一长串二进制
    {
        Dec2Bin(Digits2Index(s[i]),temp);//把一个base64编码读进来,再转成6位二进制,将6位二进制存到temp数组里。
        for(int j=5; j>=0; j--)//反着循环
        {
            bin[6*i+(5-j)] = temp[j];//每6个为一组,外层i循环一次,就代表着添加进了6个二进制位,这样的话,用6*i表示当前应该插入到哪里。
            t = 6*i+(5-j);//记录bin数组长度
        }
    }
    char aa[8];
    int tpp,tbin;//临时变量
    t = (t+1)/8;//能把二进制串切成几字节。(1个字节由8个二进制位组成)
    for(int i=0; i<t; i++)
    {
        for(int j=0; j<8; j++)
        {
            aa[j] = (char)(bin[8*i+j]+48);
        }
        aa[8] = '\0';//末尾补个0,不然会出错。因为二转十,最后一位靠'\0'判断
        tbin = Bin2Dec(aa);
        tpp = Digits2Index(tbin);
        if(tpp == -1)//如果这个字符不在索引表里,那么就直接输出这个字符,否则输出索引表里的字符
            cout << (char)tbin;
        else
            cout << base64digits[Digits2Index(Bin2Dec(aa))];
    }
}

int main()
{
    ReadFile();
    Proc(base64, strlen(base64));
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值