如何以2位编码char?

时间:2016-08-31 07:08:50

标签: c++ c hash

试图对DNA序列的k-mer实施哈希函数,DNA序列通常包含四个字符A,C,G,T的组合。

我发现这个thread非常有趣,

  

我使用了A,C,G,T的简单映射到{00,01,10,11}(以位为单位),允许在一个字节中编码四个碱基。然后,您可以使用hash(word)+ hash(rc(word))或任何其他对称函数。这种方法的优点是您可以使用当前哈希来查找下一个哈希值;当您将基数移入和移出k-mer时,您可以移入和移出散列或散列成分。这是sylamer采用的方法,而且速度非常快。

但是我不知道如何用2位编码一个字符,我的问题是,是否有任何教程,库,用于将字符映射到位的函数?

2 个答案:

答案 0 :(得分:2)

也许是这样的:

typedef enum { NB_A = 0, NB_C, NB_G, NB_T } Nucleobase;

Nucleobase nucleobase_encode(char n)
{
  n = tolower((unsigned char) n);
  switch(n)
  {
    case 'a': return NB_A;
    case 'c': return NB_C;
    case 'g': return NB_G;
    case 't': return NB_T;
  }
  return 0;
}

然后你可以使用上面的代码将四个碱基编码成一个字节:

uint8_t encode_quad(char b0, char b1, char b2, char b3)
{
  return (nucleobase_encode(b3) << 6) | (nucleobase_encode(b2) << 4) |
   (nucleobase_encode(b1) << 2) | nucleobase_encode(b0);
}

这将对四个基数进行编码,如下所示:

b3 | b2 | b1 | b0

答案 1 :(得分:2)

虽然A,C,G&amp; T可以任意映射到00,01,10,11或任何其他布置 - 至少有一个映射实际上没有ASCII码,A,C,G&amp; T - &gt; 00,01,11,10:

B

方便地,该排列也适用于RNA,因为U核苷酸在取代DNA T核苷酸时不会干扰位模式:

A 65 01000|00|1  0
C 67 01000|01|1  1
G 71 01000|11|1  3
T 84 01010|10|0  2

要从ASCII字母到位,只需移位和屏蔽:(N&gt;&gt; 1)&amp; 3

同样,您使用的映射是任意的,这只是一个很容易实现的映射。

考虑到上述方法,让我们编写一个编码器/解码器,将32基本k-mer打包成64位数字:

U 85 01010|10|1  2

<强>输出

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>

#define TWO_BIT_MASK (3)
#define BITS_PER_BYTE (8)
#define BIG_ENOUGH (1024)

uint64_t encode(char *original) {

    size_t length = strlen(original);

    assert(length * 2 == sizeof(uint64_t) * BITS_PER_BYTE);

    uint64_t result = 0;

    for (size_t i = 0; i < length; i++) {
        result = (result << 2) | ((original[i] >> 1) & TWO_BIT_MASK);
    }

    return result;
}

void decode(uint64_t encoded, char *decoded, bool rna_flag) {

    int i = sizeof(uint64_t) * BITS_PER_BYTE / 2;

    for (decoded[i--] = '\0'; i >= 0; i--, encoded >>= 2) {

        unsigned char byte = encoded & TWO_BIT_MASK;

        if (byte == 2) {
            byte = (rna_flag) ? 'U' : 'T';
        } else {
            byte = 'A' | (byte << 1);
        }

        decoded[i] = byte;
    }
}

int main() {
    char *segment = "GCCGTGCTAAGCGTAACAACTTCAAATCCGCG";

    printf("%s\n", segment);

    uint64_t binary = encode(segment);

    printf("%llu\n", binary);

    char string[BIG_ENOUGH];

    decode(binary, string, false);

    printf("%s\n", string);

    return 0;
}