在Python中快速转换ASCII编码与整数

6 投票
1 回答
1478 浏览
提问于 2025-04-16 04:39

我有一种文件格式(fastq格式),它把一串整数编码成一个字符串,每个整数用一个带偏移量的ascii码表示。不幸的是,常用的编码有两种,一种偏移量是33,另一种是64。我通常需要把几亿个长度在80到150之间的字符串从一种偏移量转换成另一种。为了实现这个转换,我想出的最简单的代码是:

def phred64ToStdqual(qualin):
    return(''.join([chr(ord(x)-31) for x in qualin]))

这个方法可以正常工作,但速度不是特别快。在我的电脑上,处理100万个字符串大约需要4秒。如果我改用几个字典来进行转换,时间可以缩短到大约2秒。

ctoi = {}
itoc = {}
for i in xrange(127):
    itoc[i]=chr(i)
    ctoi[chr(i)]=i

def phred64ToStdqual2(qualin):
    return(''.join([itoc[ctoi[x]-31] for x in qualin]))

如果我直接在cython环境下运行,时间可以降到不到1秒。
看起来在C语言层面,这个过程其实就是把数据转成整数,减去偏移量,然后再转回字符。我还没有写这个代码,但我猜这样做会快很多。如果你有任何建议,比如如何在python中更好地编写这个代码,或者如何用cython来实现这个功能,那就太好了。

谢谢,

肖恩

1 个回答

4

如果你看看urllib.quote的代码,你会发现里面有点像你正在做的事情。它看起来是这样的:

_map = {}
def phred64ToStdqual2(qualin):
    if not _map:
        for i in range(31, 127):
            _map[chr(i)] = chr(i - 31)
    return ''.join(map(_map.__getitem__, qualin))

注意,上面的这个函数可以处理映射长度不一样的情况(在urllib.quote中,你需要把'%'转换成'%25')。

但实际上,由于每个转换的长度都是一样的,Python有一个函数可以非常快速地完成这个任务:maketranstranslate。你可能找不到比这个更快的方法:

import string
_trans = None
def phred64ToStdqual4(qualin):
    global _trans
    if not _trans:
        _trans = string.maketrans(''.join(chr(i) for i in range(31, 127)), ''.join(chr(i) for i in range(127 - 31)))
    return qualin.translate(_trans)

撰写回答