我有一个包含字符的向量。这些字符只能是字母表中的 26 个大写字母,因此表示这些字符的位数可以从 8 位减少到 5 位。然后我需要将结果写入文件,以备后用。
我目前的想法是 A..Z 的 3 个最高有效位都是相同的,因此我可以使用 5 个最低有效位来唯一标识字符吗?但是我正在努力将这些未格式化的数据写入文件。
我将如何执行此操作并将结果写入文件?
我有一个包含字符的向量。这些字符只能是字母表中的 26 个大写字母,因此表示这些字符的位数可以从 8 位减少到 5 位。然后我需要将结果写入文件,以备后用。
我目前的想法是 A..Z 的 3 个最高有效位都是相同的,因此我可以使用 5 个最低有效位来唯一标识字符吗?但是我正在努力将这些未格式化的数据写入文件。
我将如何执行此操作并将结果写入文件?
要将字符减少到 5 位,您可以使用ch
& 0x1F
或ch - 'A'
; 两者都不适用于EBCDIC,但这可能不是问题。(如果是:在所有大写字母的字符串中查找表,返回索引,可以使用。)
在那之后,它变得复杂。最简单的解决方案是定义一个位数组,例如:
class BitArray
{
std::vector<unsigned char> myData;
int byteIndex( int index ) { return index / 8; }
unsigned char bitMask( int index ) { return 1 << (index % 8); }
int byteCount( int bitCount )
{
return byteIndex( bitCount )
+ (bitIndex( bitCount) != 0 ? 1 : 0);
}
public:
BitArray( int size ) : myData( byteCount( size ) ) {}
void set( index )
{
myData[byteIndex( index )] |= bitMask( index );
}
void reset( index )
{
myData[byteIndex( index )] &= ~bitMask( index );
}
bool test( index )
{
return (myData[byteIndex( index ) & bitMask( index )) != 0;
}
};
(你需要更多的数据来提取数据,但我不确定你需要什么格式。)
然后你循环你的字符串:
BitArray results( 5 * s.size() );
for ( int index = 0; index != s.size(); ++ index ) {
for ( int pos = 0; pos != 5; ++ pos ) {
results.set( 5 * index + pos );
}
}
这将毫无问题地工作。当我在遥远的过去尝试使用它(或更确切地说是等效的)时(对于霍夫曼编码,在 C 中,因为这是在 1980 年代),它也太慢了。如果您的琴弦相当短,那么今天可能就足够了。否则,您将需要一个更复杂的算法,它会跟踪最后一个字节中已经使用了多少位,并进行适当的移位和掩码以一次性插入尽可能多的位:最多两个移位和或每次插入操作,而不是这里的 5 次。这就是我最终使用的。(但我没有代码了,所以我不能轻易发布一个例子。)
你可以试试我的PackedArray代码。
它实现了一个随机访问容器,其中项目以位级别打包。换句话说,它的作用就像您能够操作 eguint9_t
或uint17_t
数组一样:
PackedArray principle:
. compact storage of <= 32 bits items
. items are tightly packed into a buffer of uint32_t integers
PackedArray requirements:
. you must know in advance how many bits are needed to hold a single item
. you must know in advance how many items you want to store
. when packing, behavior is undefined if items have more than bitsPerItem bits
PackedArray general in memory representation:
|-------------------------------------------------- - - -
| b0 | b1 | b2 |
|-------------------------------------------------- - - -
| i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7 | i8 | i9 |
|-------------------------------------------------- - - -
. items are tightly packed together
. several items end up inside the same buffer cell, e.g. i0, i1, i2
. some items span two buffer cells, e.g. i3, i6
您可以使用的最小数据单位是 8 位。您将不得不使用位移,但您只能以 8 位为一组读取/写入数据,因此您将需要额外的逻辑来处理它。如果您的输入至少有 8 个 5 位字母,则一次将 8 个字母合并在一起以形成总共 40 位,并将其作为 5 个 8 位字节写入文件。根据需要继续,直到剩下的 5 位字母少于 8 个,然后将它们合并在一起,并将剩余部分填充为 8 的偶数倍,并将其写入文件。
你能做到吗?当然。
我认为您只需使用 gzip 编写压缩文件就会获得更大的成功和轻松。
我有一个向量 [of chars that] 只能是字母表的 26 个大写字母
您可以相对容易地对其进行编码:将文本拆分为 8 个字符的块,并将编码后的文本写入 5 个字节的块,如下所示:
76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210
ORIGINAL: 000AAAAA 000BBBBB 000CCCCC 000DDDDD 000EEEEE 000FFFFF 000GGGGG 000HHHHH
76543210 76543210 76543210 76543210 76543210
ENCODED: AAAAABBB BBCCCCCD DDDDEEEE EFFFFFGG GGGHHHHH
如果您的最后一个块没有足够的字符,请使用不用于对 26 个字母中的任何一个进行编码的“填充”字符(所有字符)。