C 高效地将4个字符序列压缩为每个字符2位的文件

C 高效地将4个字符序列压缩为每个字符2位的文件,c,bash,file-io,binary,compression,C,Bash,File Io,Binary,Compression,我试图压缩一个基因组序列。这些是由字母“A”、“C”、“G”和“T”组成的字符串。在文本文件形式中,它们存储为字符。因为只有4个,所以在一个文件中可以表示为两个位 换句话说:ACTG->00 01 10 11,而不是8位字符 这些数据将被写回一个文件,其中每个字节代表4个字符。在bash脚本或C程序中,最有效的方法是什么 谢谢 这里有一个过滤器,它首先以最低有效位对序列进行编码: #include <stdio.h> int main(void) { unsigned i

我试图压缩一个基因组序列。这些是由字母“A”、“C”、“G”和“T”组成的字符串。在文本文件形式中,它们存储为字符。因为只有4个,所以在一个文件中可以表示为两个位

换句话说:ACTG->00 01 10 11,而不是8位字符

这些数据将被写回一个文件,其中每个字节代表4个字符。在bash脚本或C程序中,最有效的方法是什么


谢谢

这里有一个过滤器,它首先以最低有效位对序列进行编码:

#include <stdio.h>

int main(void) {
    unsigned i = 0;
    int c, d = 0;
    while ((c = getchar()) != EOF) {
        switch (c) {
          case 'A': d |= 0 << (2 * (i & 3)); break;
          case 'C': d |= 1 << (2 * (i & 3)); break;
          case 'T': d |= 2 << (2 * (i & 3)); break;
          case 'G': d |= 3 << (2 * (i & 3)); break;
          default: continue; // ignore all other characters
        }
        if ((++i & 3) == 0) {
            putchar(d);
            d = 0;
        }
    }
    if (i & 3) {
        putchar(d);
    }
    return 0;
}
#包括
内部主(空){
无符号i=0;
int c,d=0;
而((c=getchar())!=EOF){
开关(c){

案例“A”:d |=0
char
s是C中最小的数据类型,它们仍然是8位。你不能真正创建一个2位大小,但是看看一些建议,如何创建一个1字节的
struct
来保存4条信息。你能为每个可能的排列分配一个数字吗?当然,然后你必须读/写你的文件在二进制模式下。将数字保存为可读文本不会节省太多空间。下面看起来不错。祝你好运!是的,我可以为每一个4的排列分配一个值,但我正在尝试找到一种有效的方法。使用开关似乎非常耗时。我相信你的意思是
@NominalAnimal:你是对的,答案更新。像素顺序更常见,但有点不一致:第n个基数应为字节数
n/4
,并使用位数
2*(n%4)
2*(n%4)+1
。这种不一致性可以追溯到早期的位图图形,在早期的位图图形中,像素在图形内存字节中的顺序与它们在阿拉伯数字中的基2转录形式在视觉上是一致的。这种顺序在数学上是不一致的,但在文化上对西方人来说是正确的。我不太理解。
n
th base是字节数
n/4
,并且在示例代码和一般代码中都使用位
2*(n%4)
2*(n%4)+1
。噢,我明白了:不一致之处在于顺序是最高有效位优先,但对齐或打包是最低有效位(占用)首先,我不认为西方习惯是造成这种情况的原因(特别是,在某些体系结构上标记为0位的MSB会更西方化,但现在很少);我认为位移位无处不在,使这种形式的打包/解包变得简单和快速更可能是原因。@NominalAnimal:数字是按英语和阿拉伯语的顺序写的,但在英语中,最重要的数字排在第一位,而在阿拉伯语中,因为它是从右向左读的,所以最不重要的数字排在第一位在你的评论中,从最有意义的数字中提取比特是非常罕见的,因为更自然地考虑比特n来代表值2 ^ n.Ah,现在我明白了。我不同意,我们写数字的顺序特别是西方;毕竟,十进制数字系统是从印度教阿拉伯数字系统中派生出来的!有人可能会说写“三百二十一”——因为在许多以前被称为“一二三百”的语言中,as 123更“西方化”……然而,我完全同意顺序不是基于数学的,也不是最优的,而是任意选择的,可能是出于文化原因。
#include <stdio.h>

int main(void) {
    unsigned i = 0;
    int c, d = 0;
    while ((c = getchar()) != EOF) {
        switch (c) {
          case 'A': d = (d << 2) | 0; break;
          case 'C': d = (d << 2) | 1; break;
          case 'T': d = (d << 2) | 2; break;
          case 'G': d = (d << 2) | 3; break;
          default: continue; // ignore all other characters
        }
        if ((++i & 3) == 0) {
            putchar(d);
            d = 0;
        }
    }
    if (i & 3) {
        putchar(d << (2 * (3 - (i & 3))));
    }
    return 0;
}