python-reedsolomon实际应用

2020/10/15更新:之前的代码错了:)

之前只对十进制列表算过编码,昨天试了下对字符串直接编码,然后发现结果很神奇。

我用一段伪随机生成的核酸序列举例吧(用random做的。搞生信,理解一下)

>>> from reedsolo import RSCodec
>>> rsc = RSCodec(6)
>>> ans = rsc.encode(b"CtttaAatUAGTTtUG")
>>> ans
bytearray(b'CtttaAatUAGTTtUG_$\xaf\xa5x>')

可以看到后面有奇怪的字符。这里解释一下,\x表示后面两位是十六进制。

同时,我也刚发现,原来对十进制进行编码时,也有问题,比如:

>>> from reedsolo import RSCodec
>>> rsd = RSCodec(6)
>>> rsd.encode([9,1,2,9]*4)
bytearray(b'\t\x01\x02\t\t\x01\x02\t\t\x01\x02\t\t\x01\x02\tQ\x7f_\xa3=\xef')

那么,当有9出现的时候,我下面的编码解码都是错的。也许还有别的数字也有这样的问题。

我当前的策略是按位解析。。。对单字符和双字符分别解析。

def _rsEncode(data, n):
    '''
    n 是实际编码长度,16 for example
    dat = bytearray(b'CtttaAatUAGTTtUG_$\xaf\xa5x>')

    :param data: bytearray
    :param n:
    :return:
    '''
    data = str(bytes(data))[2:-1]
    tail = data[n:]
    pos = tail.find("\\x")
    i = 0
    result = ''
    while i < len(tail):
        #print("start: " + str(i))
        if i == pos:
            # 取两位字符
            result += "." + tail[i+2:i+4]
            i += 4
            pos = tail.find("\\x", i)
        else:
            ...
            i += 1
    return result

需要注意的是,\和\t其实都是一个字符。


之前这篇 差错控制-reed-solomon编码 我鸽了,可能要 很久 才有空补了。当前业务上使用场景有限,现在只用一个 reedsolo 包足够了。

安装

直接pip 官方例子

编码

from reedsolo import RSCodec

def _rsEncode(data, n):
    '''
    Encode input data with Reed-Solomon codes. n bits for error correcting.
    :param data: input data, like "b'@\\x16\\x10\\xec\\x11\\xec\\x11\\xda(\\xf3\\xd4BG\\x96'"
    :param n: Length of result list.
    :return: A list of error correcting values. Decimal.
    '''
    res = []
    # remove b' and '
    temp = str(bytes(data))[2:-1]
    li = temp.split("\\x")
    # only retain encoded values
    for i in li[::-1]:
        size = len(i)
        if size == 1:
            res.append(ord(i))
        else:
            j = i[2:]
            # first 2 digits are hex
            temp_li = [int('0' + i[:2], 16)]
            while len(j) > 0: # single char
                temp_li.append(ord(j[0]))
                j = j[1:]
            # reverse
            res.extend(temp_li[::-1])
        if len(res) >= n:
            break
    return res[:n][::-1]

rsc = RSCodec(7)
# 我这个data_list是一个十进制整数列表
encode_ = rsc.encode(data_list)
# _rsEncode帮我把【纠错码】,也就是尾部附加的那些数字转为十进制
rs_tail = _rsEncode(encode_, 7)

解码

下面这个函数将十进制整数的list(业务数据附加纠错码)转为字符串。

def _rsDecode(data, n, m):
    '''
    Reed-Solomon Decoding.
    :param data: decimal list.
    :param n: length of ecc. (bytes)
    :param m: length of bussiness data. (bytes)
    :return: utf-8 string
    '''
    rsd = RSCodec(n)
    data = rsd.decode(data)[:m]
    hex_ = ""
    for i in data:
        hex_ += "{:02X}".format(i)
    # need to remove '@' at head
    hex_ = hex_[3:]
    while hex_[-1:] != "0":
        hex_ = hex_[:-2]
    hex_ = hex_[:-1]
    return bytearray.fromhex(hex_).decode("utf-8")

注意

  • RS的纠错能力是有限的,纠错码用几位要根据实际需求来。默认的是GF(2^8),也就是说,对于0~255的值是ok的。256以下就是8位表示嘛,所以如果超过8位,函数会自动切块,不保证速度。键盘上常用字符其实是够用的了。
>> rsc = RSCodec(12, nsize=4095)  # always use a power of 2 minus 1
>> rsc = RSCodec(12, c_exp=12)  # alternative way to set nsize=4095
  • 纠错能力:2*e + v <= n
    e:错误的位数
    v:缺失的位数(需要提供位置)
    n:纠错码长度

你可能感兴趣的:(python,字符串,算法)