对论坛一个字符串编码问题的回答
Horin | horin153@msn.com
昨天晚上更新一篇博客,顺便看见论坛一个帖子:http://topic.csdn.net/u/20110726/07/8c715386-d282-414d-a8a0-13b4acd4bc87.html;其问题如下:例如输入字符串:AAABBBBCCCCCC,要求输出:A3B4C6.
正好这两天有空,也觉得问题简单,就分析如下:
首先是需求分析,贴主的问题显然描述不清晰。
1,对字符串进行编码后,是否需要进行可逆的解码?
2,字符串输入集是英文字母?还是 ASCII 字符?是否有汉字等多字节字?
假设字符串需要可逆解码,如果输入是英文字母,则 A123 是无歧义的;如果是 ASCII 字符,则 A123 是有歧义的(A222 或者 123个连续A)。为简化问题,假设是没有汉字的纯 ASCII 字符串(当然包括了字母集)。
接着是设计。对 ASCII 字符串进行编码,因为字符的重复次数未定,为了节约空间,定义编码后的数据结构为:
字符/byte + 字符重复数(最大255)/byte
对连续 260 个 A 的字符串,编码后内存数据为:'A',0xFF,'A',0x05,也就是占用 4 字节(255个A,5个A);在可视化输出时可以处理为 A:260。
最后就是代码实现和单元测试。对这个简单的字符串问题,用标准库就足够了,代码如下:
//---------------------------- code begin ---------------------------- #include <string.h> #include <assert.h> #include <stdio.h> void encode(char* dst, char* src) { assert(dst); assert(src); unsigned char n=0; char *ps=src, *pd=dst, *p=src; while (*p++) { if ((*ps!=*p) || (p-ps==0xff)) { *pd++ = *ps; n = p - ps; ps = p; *pd++ = *((char*)&n); } } *pd = '\0'; } int main(void) { char src[301] = {0}; // 最长为300的字符串 ::memset(src, 'A', 260); // 连续260个A char* p = src; p += 260; ::memset(p, 'B', 40); // 接着连续40个B size_t len = 300*2+1; // 输出字符串长度为输入字符串长度的 2 倍 char* dst = new char[len]; ::memset(dst, 0, len); encode(dst, src); // 把编码后的内存数据打印出来, 很容易就可以改为解码算法. printf ("After encode:"); p = dst; while(*p && *(p+1)) { printf ("%c:%d;", *p, *((unsigned char*)(p+1))); p += 2; } delete[] dst; return 0; } //---------------------------- code end ----------------------------
测试输出结果如下:
After encode:A:255;A:5;B:40;
这和输入的字符数是一致的,测试正确。