18位身份证信息压缩为7字节char型
身份证号18位压缩为7位
房间号8位压缩为3位
=== 身份证号 ===
17~16 省 15~12 地区市县 11~8 年 7 6 月 5 4 日 3 2 派出所 1 性别 0 校验
分析:
省:大陆为11~65 香港 71 澳门 81 台湾 82
计算时先归零,从11~82的范围减11,得到0~71,共72种
地区:0000~9999 共10000种
年: 1900~2899年 同样归零,减1900为0~999 共1000种
月:1~12 归零,减1,0~11,共12种
日:0~31 共32种
派出所+性别:0~999 共1000种
校验:0~9 x 共11种
分为7部分,由低到高分别为11进制、1000进制、32进制、12进制、1000进制、10000进制、72进制
本方法可以在最大限度压缩身份证号,但由于需要7Byte来表示数字,而32位机int型为4Byte无法表示,而C语言中并不保证有long long类型,而且许多编译器并不支持64位整型运算,为了增强程序可移植性,重写了64位加减乘除。本程序在处理身份证号中并不一定是最优算法,仅以此示例来表示一种压缩算法,实际上可以有更快的压缩算法,只是压缩比略低,如:将身份证号一分为二,前9位直接用32位int型表示,32位int型最大为4294967296,可以完全包括9位10进制整数,后9位的最后一位为校验位,可以通过前17位自动生成,可以抛弃,或者可以使用浪费的最高位数字来表示x,这样可以经过很少的计算来压缩身份证号,但是仅比所示程序的压缩位数多一个字节,也就是8Byte,但不需要大量的计算。
举例:
82 1541 1985 06 02 145 x
11
145 * 11
2 * 1000 * 11
(6 - 1) * 32 * 1000 * 11
(1985 - 1900)* 12 * 32 * 1000 * 11
1541 * 1000 * 12 * 32 * 1000 * 11
(82 - 11)* 10000 * 1000 * 12 * 32 * 1000 * 11
求和,即为压缩结果
aad88, 8f95b35
然后逆过程来解压缩
结果 / (10000 * 1000 * 12 * 32 * 1000 * 11) 商为最高位 余数作为下一位的计算被除数
循环计算得到最终结果
问题:上面的日期其实可以从1~31,用31进制表示,疏忽了。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned int UINT32;
typedef int INT32;
typedef int bool;
typedef unsigned char BYTE;
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned long DWORD;
#define true 1
#define false 0
typedef struct STRUCT_ID{
int province; // 16, 17 bit -- 11~82
int city; // 15, 12 bit
int year; // 11, 8 bit
int month; // 6, 7 bit
int day; // 4, 5 bit
int police; // 1, 2, 3 bit
int check; // 0 bit
}st_ID;
typedef struct STRUCT_BLOCK{
int b_check;
int b_pol;
int b_monthday;
int b_year;
int b_city;
int b_province;
}st_block;
typedef struct _ST_ROOM_PAIR{
char chRoomNo;
int iRoomNo;
}ST_ROOM_PAIR;
typedef struct STRUCT_COMPRESS{
unsigned long i_compress_high;
unsigned long i_compress_low;
}stCompress;
stCompress IDcardNoCompress(char *strID);
char* IDcardNoUnCompress(stCompress stCompressID);
stCompress UINT64Add(stCompress, stCompress);
stCompress UINT64Minus(stCompress, stCompress);
void UINT64Multiply(UINT32 multiplicator_0,/*乘数0*/\
UINT32 multiplicator_1,/*乘数1*/\
UINT32 *pResult_H32,/*乘运算结果高32位*/\
UINT32 *pResult_L32/*乘运算结果低32位*/);
bool UINT64Divide(UINT32 dividend_H /*被除数高32位*/,\
UINT32 dividend_L /*被除数低32位*/,\
UINT32 divisor_H /*除数高32位*/,\
UINT32 divisor_L /*除数低32位*/,\
UINT32 *pQuto /*商*/);
int main()
{
stCompress stCTest;
char strID[] = "82154119850602145x";
stCTest = IDcardNoCompress(strID);
char* xx = IDcardNoUnCompress(stCTest);
if(strcmp(strID, xx) != 0)
printf("IDcard No equal!\n");
free(xx);
return 0;
}
// 身份证ID18位,压缩成7字节
stCompress IDcardNoCompress(char *strID)
{
// 月日 派出所 性别 校验
char * IDp = strID;
char ch_province[3];
char ch_city[5];
char ch_year[5];
char ch_month[3];
char ch_day[3];
char ch_pol[4];
char ch_check[2];
UINT32 uH32 = 0 , uL32 = 0;
st_ID st_id;
stCompress st_compress;
stCompress st_temp;
// unsigned long i_compress = 0;
printf("原始数据为:%s\n", strID);
st_compress.i_compress_high = 0;
st_compress.i_compress_low = 0;
if( 18 != strlen(strID)){
printf("Error, Please input 18 bit ID Number!\n");
return st_temp;
}
ch_province[0] = *IDp++;
ch_province[1] = *IDp++;
ch_province[2] = '\0';
sscanf(ch_province, "%d", &st_id.province);
printf("province: %d\n", st_id.province);
st_id.province -= 11;
ch_city[0] = *IDp++;
ch_city[1] = *IDp++;
ch_city[2] = *IDp++;
ch_city[3] = *IDp++;
ch_city[4] = '\0';
sscanf(ch_city, "%d", &st_id.city);
printf("city: %d\n", st_id.city);
ch_year[0] = *IDp++;
ch_year[1] = *IDp++;
ch_year[2] = *IDp++;
ch_year[3] = *IDp++;
ch_year[4] = '\0';
sscanf(ch_year, "%d", &st_id.year);
st_id.year -= 1900;
printf("year: %d\n", st_id.year);
ch_month[0] = *IDp++;
ch_month[1] = *IDp++;
ch_month[2] = '\0';
sscanf(ch_month, "%d", &st_id.month);
st_id.month -= 1;
printf("month: %d\n", st_id.month);
ch_day[0] = *IDp++;
ch_day[1] = *IDp++;
ch_day[2] = '\0';
sscanf(ch_day, "%d", &st_id.day);
printf("day: %d\n", st_id.day);
ch_pol[0] = *IDp++;
ch_pol[1] = *IDp++;
ch_pol[2] = *IDp++;
ch_pol[3] = '\0';
sscanf(ch_pol, "%d", &st_id.police);
printf("pol: %d\n", st_id.police);
ch_check[0] = *IDp++;
ch_check[1] = '\0';
if (ch_check[0] == 'x' || ch_check[0] == 'X')
st_id.check = 10;
else
sscanf(ch_check, "%d", &st_id.check);
printf("check: %d\n", st_id.check);
printf("******************************************\n");
st_temp.i_compress_high = 0;
st_temp.i_compress_low = st_id.check;
st_compress = UINT64Add(st_compress, st_temp);
st_temp.i_compress_high = 0;
st_temp.i_compress_low = st_id.police*11;
st_compress = UINT64Add(st_compress, st_temp);
st_temp.i_compress_high = 0;
st_temp.i_compress_low = st_id.day*1000*11;
st_compress = UINT64Add(st_compress, st_temp);
st_temp.i_compress_high = 0;
st_temp.i_compress_low = st_id.month*32*1000*11;
st_compress = UINT64Add(st_compress, st_temp);
st_temp.i_compress_high = 0;
st_temp.i_compress_low = st_id.year*12*32*1000*11;
st_compress = UINT64Add(st_compress, st_temp);
//printf("st_compress high:%x, city low:%x\n", st_compress.i_compress_high, st_compress.i_compress_low);
// 到此之前的数字在32位即可处理,此后的city和province都必须先用64位乘法来计算
UINT64Multiply(st_id.city, 1000*12*32*1000*11UL,&uH32,&uL32);
//printf("city:%u \n", st_id.city);
//printf("city highx:%x, city lowx:%x\n", uH32, uL32);
//printf("city high:%u, city low:%u\n", uH32, uL32);
st_temp.i_compress_high = uH32;
st_temp.i_compress_low = uL32;
st_compress = UINT64Add(st_compress, st_temp);
//printf("st_compress2 high:%x, city low:%x\n", st_compress.i_compress_high, st_compress.i_compress_low);
UINT64Multiply(st_id.province*10000, 1000*12*32*1000*11UL,&uH32,&uL32);
//printf("province high:%x, province low:%x\n", uH32, uL32);
st_temp.i_compress_high = uH32;
st_temp.i_compress_low = uL32;
st_compress = UINT64Add(st_compress, st_temp);
//printf("st_compress3 high:%x, city low:%x\n", st_compress.i_compress_high, st_compress.i_compress_low);
//i_compress = (unsigned long)st_id.check + st_id.police*11 + st_id.day*1000*11 + st_id.month*32*1000*11 + st_id.year*12*32*1000*11 + st_id.city*1000*12*32*1000*11 + st_id.province*10000*1000*12*32*1000*11;
printf("压缩之后的数据为: %x, %x\n", st_compress.i_compress_high, st_compress.i_compress_low);
return st_compress;
}
char* IDcardNoUnCompress(stCompress stCompressID)
{
stCompress st_temp;
stCompress st_multiply_result;
UINT32 i_result;
int i;
char *IDresult = (char *)malloc(sizeof(char) * 19);
char *p = IDresult;
//printf("@200000000000 %x, %x, %x, %x\n", stCompressID.i_compress_high, stCompressID.i_compress_low, 0x266A, 0xC4320000); // province
bool res = UINT64Divide(stCompressID.i_compress_high /*被除数高32位*/,\
stCompressID.i_compress_low /*被除数低32位*/,\
0x266A /*除数高32位*/,\
0xC4320000 /*除数低32位*/,\
&i_result /*商*/);
if (res == false){
printf("ERROR: province \n" ); // province
return 0;
}
sprintf(p, "%.2d", i_result + 11);
printf("province:%.2d\n", i_result); // province
p += 2;
UINT64Multiply(i_result*10000*32, 0x07de2900 , &st_multiply_result.i_compress_high, &st_multiply_result.i_compress_low);
st_temp = UINT64Minus(stCompressID, st_multiply_result); // 计算余数
res = UINT64Divide(st_temp.i_compress_high /*被除数高32位*/,\
st_temp.i_compress_low /*被除数低32位*/,\
0x0 /*除数高32位*/,\
0xFBC52000 /*除数低32位*/,\
&i_result /*商*/);
if (res == false){
printf("ERROR: city \n" ); // city
return 0;
}
sprintf(p, "%.2d", i_result);
printf("city:%.2d\n", i_result);// city
p += 4;
UINT64Multiply(i_result*1000, 0x407400, &st_multiply_result.i_compress_high, &st_multiply_result.i_compress_low);
st_temp = UINT64Minus(st_temp, st_multiply_result); // 计算余数
//printf("T_T:st_temp %x,%x \n", st_temp.i_compress_high, st_temp.i_compress_low ); // province
//printf("year: %x,%x / %x\n", st_temp.i_compress_high, st_temp.i_compress_low, 0x407400);
res = UINT64Divide(st_temp.i_compress_high /*被除数高32位*/,\
st_temp.i_compress_low /*被除数低32位*/,\
0x0 /*除数高32位*/,\
0x407400 /*除数低32位*/,\
&i_result /*商*/);
if (res == false){
printf("ERROR: year \n" ); // year
return 0;
}
sprintf(p, "%.4d", i_result + 1900);
printf("year:%.4d\n", i_result);// year
p += 4;
UINT64Multiply(i_result, 0x407400, &st_multiply_result.i_compress_high, &st_multiply_result.i_compress_low);
st_temp = UINT64Minus(st_temp, st_multiply_result); // 计算余数
res = UINT64Divide(st_temp.i_compress_high /*被除数高32位*/,\
st_temp.i_compress_low /*被除数低32位*/,\
0x0 /*除数高32位*/,\
0x55F00 /*除数低32位*/,\
&i_result /*商*/);
if (res == false){
printf("ERROR: month \n" ); // month
return 0;
}
sprintf(p, "%.2d", i_result + 1);
printf("month:%.2d\n", i_result + 1);// month
p += 2;
UINT64Multiply(i_result, 0x55F00, &st_multiply_result.i_compress_high, &st_multiply_result.i_compress_low);
st_temp = UINT64Minus(st_temp, st_multiply_result); // 计算余数
res = UINT64Divide(st_temp.i_compress_high /*被除数高32位*/,\
st_temp.i_compress_low /*被除数低32位*/,\
0x0 /*除数高32位*/,\
0x2AF8 /*除数低32位*/,\
&i_result /*商*/);
if (res == false){
printf("ERROR: day \n" ); // day
return 0;
}
sprintf(p, "%.2d", i_result);
printf("day:%.2d\n", i_result);// day
p += 2;
UINT64Multiply(i_result, 0x2AF8, &st_multiply_result.i_compress_high, &st_multiply_result.i_compress_low);
st_temp = UINT64Minus(st_temp, st_multiply_result); // 计算余数
res = UINT64Divide(st_temp.i_compress_high /*被除数高32位*/,\
st_temp.i_compress_low /*被除数低32位*/,\
0x0 /*除数高32位*/,\
0xB /*除数低32位*/,\
&i_result /*商*/);
if (res == false){
printf("ERROR: policestation \n" ); // policestation
return 0;
}
sprintf(p, "%.3d", i_result);
printf("police:%.3d\n", i_result);// policestation
p += 3;
UINT64Multiply(i_result, 0xB, &st_multiply_result.i_compress_high, &st_multiply_result.i_compress_low);
st_temp = UINT64Minus(st_temp, st_multiply_result); // 计算余数
if(st_temp.i_compress_low == 10){
sprintf(p, "%c", 'x');
printf("%c", 'x');
}
else{
sprintf(p, "%d", st_temp.i_compress_low);
printf("%d", st_temp.i_compress_low);
}
p++;
*p = 0;
printf("\n恢复以后的数据为---------IDcard:%s\n", IDresult);
return IDresult;
}
//函数类型:bool
//函数名称:UINT64Divide
//函数功能:实现64位数据的除法运算
//
//输入:
// UINT32 dividend_H /*被除数高32位*/
// UINT32 dividend_L /*被除数低32位*/
// UINT32 divisor_H /*除数高32位*/
// UINT32 divisor_L /*除数低32位*/
//
//
//输出:
// UINT32 *pQuto /*商*/
// bool bSuccessed //计算成功标志
//
//实现:
// *pQuto = (dividend_H | dividend_L) / (divisor_H | divisor_L);
//
// 在输入合法性检查完成后,并且,商值在32位的类型范围内时,输出 bSuccessed 为真
//
//
//除法实现:
// 在分子分母的高32位值都为0时,说明可以直接使用32位的除法实现
// 在分母的高32位数有值时,使用公约数方式将分子分母同时缩小,直到高32位值为0结束
// 64位数除以32位数时,使用长除法
bool UINT64Divide(UINT32 dividend_H /*被除数高32位*/,\
UINT32 dividend_L /*被除数低32位*/,\
UINT32 divisor_H /*除数高32位*/,\
UINT32 divisor_L /*除数低32位*/,\
UINT32 *pQuto /*商*/)
{
bool bSuccessed = false;//用于标记除法计算是否成功
UINT32 uFlag = 0x0;//用于标记分子高32位最高位
UINT32 uQuto = 0x0;//商值
USHORT i = 0;
if((divisor_H == 0x0)/*分母高32位为0的情况下*/\
&&(divisor_L == 0x0)/*64位的分母不能为0*/ \
||(dividend_H/divisor_L))/*分子高32位除分母取整有值的话,说明64位的除式的商会超过32位,溢出*/
{
*pQuto = 0;
bSuccessed = false;
}
else if((divisor_H == 0x0)/*分母高32位为0的情况下*/\
&&(dividend_H == 0x0))/*如果分子和分母高32位都没有值,就可以使用32位的除法进行运算*/
{
*pQuto = dividend_L / divisor_L;
bSuccessed = true;
}
else
{
if(divisor_H != 0)//在高32位有值的情况下
{
while(divisor_H)//分子分母同缩小N倍,N为divisor_H中最高的'1'的位置值,例:0010 0001 N=5。这里2的N次方作为分子分母的公约数
{
dividend_L /= 2;//实现分子循环右移位,如果系统支持移位操作,这部分代码就会更方便实现
if(dividend_H % 2)
{
dividend_L += 0x80000000;
}
dividend_H /= 2;
divisor_L /= 2;//实现分母循环右移位
if(divisor_H %2)
{
divisor_L += 0x80000000;
}
divisor_H /= 2;
}
}
for (i = 0; i <= 31; i++)
{
// 将被除数的低32位值dividend_L可以全部移到高32位dividend_H中进行计算(长除的特征)
// (1)uFlag标记被除数是否够除,如果最高位移出一个'1',说明被除数是足够大,可以除除数
// uFlag
// | 64 |63<-------------->|<--------------->0|
// _____________________________________________
// |0(1) | dividend_H | dividend_L |0
// -----^-^----------------^-^----------------^-^ //这个步骤实际上是将处于低32的最高位移到高32位的最低位,实现循环移位了
// -
// ____________________
// | divisor_L |
// 31------------------0
//
//
//
uFlag = (INT32)dividend_H >> 31;//(1)
dividend_H = (dividend_H << 1)|(dividend_L >> 31);//(2)-1
dividend_L <<= 1; //(2)-2
uQuto <<= 1;
if((dividend_H|uFlag) >= divisor_L)/*判断分子是否够除*/
{
dividend_H -= divisor_L;
uQuto++;
}
}
*pQuto = uQuto;
bSuccessed = true;
}
return bSuccessed;
}
//函数类型:void
//函数名称:UINT64Multiply
//函数功能:实现64位数据的除法运算
//
//输入:
// UINT32 multiplicator_0 /*被除数高32位*/
// UINT32 multiplicator_1 /*被除数低32位*/
//
//
//
//输出:
// UINT32 *pResult_H32 /*乘运算结果高32位*/
// UINT32 *pResult_L32 /*乘运算结果低32位*/
//
//实现:
// *pQuto = (dividend_H | dividend_L) / (divisor_H | divisor_L);
//
//
//
//
//64位乘法实现:
// 乘法运算公式中,A1,B1,A0,B0四个变量中,以'1'为下标的为乘数的高16位,以'0'为
// 下标的乘数的低16位,按乘法运算规则(交叉相乘),可以得到下式:
//
// A1 A0
// *
// B1 B0
// ------------------------
// A1B0A0B0
// +
// A1B1A0B1
// = ------------------------//注意乘式中各项对齐
// 乘运算结果高32位 | 乘运算结果低32位
//
void UINT64Multiply(UINT32 multiplicator_0,/*乘数0*/\
UINT32 multiplicator_1,/*乘数1*/\
UINT32 *pResult_H32,/*乘运算结果高32位*/\
UINT32 *pResult_L32/*乘运算结果低32位*/)
{
//
// 如果乘数中有一个为0 ,直接输出0值,
// 如果乘数运算结果在32位表示范围之内,则直接用32位的乘法给出结果
#define LOWORD(l) ((WORD)(l))
#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
UINT32 A0 = 0, A1 = 0,B0 = 0,B1 = 0;
UINT32 A0B0 = 0,A1B0 = 0,A0B1 = 0,A1B1 = 0;
if(multiplicator_0 * multiplicator_1 == 0)/*乘数中任意一个为0,则输出0*/
{
*pResult_H32 = *pResult_L32 = 0;
}
else if(multiplicator_0/*下式中,除数不能为0*/
&& ((multiplicator_0 * multiplicator_1)/multiplicator_0 == multiplicator_1))
{
*pResult_H32 = 0;
*pResult_L32 = multiplicator_0 * multiplicator_1;
}
else
{
A0 = LOWORD( multiplicator_0 );
A1 = HIWORD( multiplicator_0 );
B0 = LOWORD( multiplicator_1 );
B1 = HIWORD( multiplicator_1 );
A0B0 = A0 * B0;
A1B0 = A1 * B0 + HIWORD( A0B0 );
A0B1 = A0 * B1 + LOWORD( A1B0 );
A1B1 = A1 * B1 + HIWORD( A1B0 ) + HIWORD( A0B1 );
*pResult_H32 = A1B1;
*pResult_L32 = multiplicator_0 * multiplicator_1;
}
//printf("A*B: %u * %u = %u, %u\n", multiplicator_0, multiplicator_1, *pResult_H32, *pResult_L32);
return ;
}
// 本函数有缺陷,不能保证两数字加起来不溢出,但C语言本身也是如此
stCompress UINT64Add(stCompress st_compress_A, stCompress st_compress_B)
{
int iTmp;
stCompress st_temp;
st_temp.i_compress_high = 0;
st_temp.i_compress_low = 0;
st_temp.i_compress_low = st_compress_A.i_compress_low + st_compress_B.i_compress_low;
st_temp.i_compress_high = st_compress_A.i_compress_high + st_compress_B.i_compress_high;
if (st_temp.i_compress_low < st_compress_A.i_compress_low || st_temp.i_compress_low < st_compress_B.i_compress_low)
st_temp.i_compress_high++;
//printf("A+B: %u %u+ %u %u = %u %u\n", st_compress_A.i_compress_high, st_compress_A.i_compress_low, st_compress_B.i_compress_high, st_compress_B.i_compress_low, st_temp.i_compress_high, st_temp.i_compress_low);
//printf("A+B2: %x %x+ %x %x = %x %x\n", st_compress_A.i_compress_high, st_compress_A.i_compress_low, st_compress_B.i_compress_high, st_compress_B.i_compress_low, st_temp.i_compress_high, st_temp.i_compress_low);
return st_temp;
}
stCompress UINT64Minus(stCompress st_compress_A, stCompress st_compress_B)
{
int iTmp;
stCompress st_temp;
st_temp.i_compress_high = 0;
st_temp.i_compress_low = 0;
st_temp.i_compress_low = st_compress_A.i_compress_low - st_compress_B.i_compress_low;
st_temp.i_compress_high = st_compress_A.i_compress_high - st_compress_B.i_compress_high;
printf("st_temp.i_compress_high:%x\n", st_temp.i_compress_high);
printf("st_temp.i_compress_low:%x\n", st_temp.i_compress_low );
if (st_temp.i_compress_low > st_compress_A.i_compress_low)
st_temp.i_compress_high--;
//printf("A-B: %u %u- %u %u = %u %u\n", st_compress_A.i_compress_high, st_compress_A.i_compress_low, st_compress_B.i_compress_high, st_compress_B.i_compress_low, st_temp.i_compress_high, st_temp.i_compress_low);
return st_temp;
}
int main3(int argc, char* argv[])
{
UINT32 uQuto = 0 ;
// UINT32 x = 1541;
// UINT32 y = 4224000000;
UINT32 x = 0xB8;
UINT32 y = 0x16c950c2;
UINT32 a = 0x12;
UINT32 b = 0x3EDE4000;
UINT64Divide(x,y,a,b,&uQuto);
printf("uQuto = %u\n",uQuto);
printf("uQuto = %x\n",uQuto);
//UINT32 uH32 = 0 , uL32 = 0;
// UINT64Multiply(x,y,&uH32,&uL32);
//UINT64Multiply(0xBFBFBFBF,0xEEEEBFBF,&uH32,&uL32);
// UINT64Multiply(0x605,0xFBC52000,&uH32,&uL32);
// printf("uH32 = %x,uL32 = %x \n",uH32,uL32);
// printf("uH32 = %u,uL32 = %u \n",uH32,uL32);
return 0;
}
浙公网安备 33010602011771号