我在C中实现RLE算法,我遇到了一个很大的问题。我使用@作为压缩/解压缩的标识符。让我用例子说明:
0 0 0 0 1 2 0 0 0 0 = @ 0 4 1 2 @ 0 4
@ X Y =重复X,Y次。数字从0到255(unsigned char)不等。但是,数字64让我感到困惑,因为它与'@'相同。
程序读取64 0 5
我希望:64 0 5(不需要减压)
得到的结果:0 0 0 0 0(64存储在char变量中,然后程序将其用作'@')
if (var == '@') {
// decompress
}
答案 0 :(得分:1)
您需要选择一个绝对不会用作转义机制的字符序列。如果您将输入转换为@ <character> <count>
,如果同一个字符连续出现至少3次,那么您未转换的最差输入将有2个连续的@字符。
输入中另一个最坏的情况是有64个@字符,产生@ @ @
。所以,我们确定输出不能连续超过3个。
鉴于此,你可以将单个@字符表示为@@@@
,它产生4个字符。如上所示,RLE的输出不能有4个连续的@(或任何其他4个连续的字符,以这种方式)
但相反,如果你总是将@转换为@ @ <count>
,你可以保留一个字节,你只需要修改项目的RLE创建部分,因为这种格式是完美的根据RLE解析器很好。
答案 1 :(得分:1)
我猜你正在使用一些scanf
- 类似函数来解析你的输入。
别。在这种情况下它不起作用。
相反,只需读取输入字符串,将空格拆分为标记(示例:"@ 0 4 1 2 @ 0 4"
- &gt; "@", "0", "4", "1", "2", "@", "0", "4"
和"64 0 5"
- &gt; "64", "0", "5"
)
下一步是解析。在那里你可以淘汰@
- s。你可以很容易地将它们与64
- strlen("@") == 1
和strlen("64") == 2
区分开来,你知道了吗?)
当您遇到纯数字字符串时,您可以使用atoi
之类的内容将其转换为整数(之后您可以将其转换为unsigned char
)。
答案 2 :(得分:0)
这可能不是解决问题的最佳方法,但它可以胜任。 c编译器会根据需要自动将int转换为char,将char转换为int。如果您可以找到限制此行为的方法,则问题将得到解决。我通过将字符转换为respective ASCII
并将其与ASCII value
的{{1}}进行比较来限制行为。
该程序的一个明显问题是它读取单个字符,并且它永远不会出现64个整体,但即使我们修改程序以将空格分隔为分隔符,我也不认为这样做有任何问题
@
答案 3 :(得分:0)
转义重复指令的一个非常简单的解决方案是重复字符。
让我解释一下:
将0 0 0 0
编码为0 0 2
(2表示重复前一个字符的2倍)
小心重复2次:
3 4 4 5
应编码为3 4 4 0 5
,
0意味着不再有'4'。
解码时只需查找重复的字符,找到后,将下一个字符作为重复字符的次数。
未经测试的例子:
int input_char(void);
void output_char(int);
void encode(void) {
int c, previous_c = EOF;
int repeating = 0, repetitions;
while ((c = input_char()) != EOF) {
if (repeating) {
if (c == previous_c && repetitions < 255) {
++repetitions;
} else {
output_char(repetitions);
output_char(c);
repeating = 0;
}
} else {
output_char(c);
if (previous_c == c) {
repeating = 1;
repetitions = 0;
}
}
previous_c = c;
}
}
void decode(void)
{
int c, previous_c = EOF;
while ((c = input_char()) != EOF) {
output_char(c);
if (c == previous_c) {
int repetitions = (unsigned char) input_char();
while (repetitions--) {
output_char(c);
}
}
previous_c = c;
}
}
答案 4 :(得分:0)
查看此ascii table:您可以看到数字的范围,用它来确定您是否正在阅读数字:
if (var >= 48 && var <= 57) {/* I'm an integer */}