Burrows-Wheeler 变换 (BWT) 重复字符串
Posted
技术标签:
【中文标题】Burrows-Wheeler 变换 (BWT) 重复字符串【英文标题】:Burrows-Wheeler Transform (BWT) repeating string 【发布时间】:2019-12-22 17:41:44 【问题描述】:我正在用 Python 编写 Burrows-Wheeler 变换及其逆向变换。它适用于小弦,但当我测试更大的弦时它就崩溃了。在某些时候,字符串似乎循环了。我确信它一定与解码器的最终循环有关,但我正在遵循在多个网站上找到的步骤。我的实现如下:
class BurrowsWheelerTransform:
def __init__(self, data):
self.data = data
def transform(self):
# get data size
size = len(self.data)
# get order (by index) of rotations
order = sorted(range(size), key=lambda i: self.data[i:])
# get index of original rotation
index = order.index(0)
# return size appended with last column of (imaginary) rotation table
return chr(255) * (index // 255) + chr(index % 255) + ''.join(self.data[(i - 1 + size) % size] for i in order)
def restore(self):
# get index of end of index
eoi = next(i for i in range(len(self.data)) if ord(self.data[i]) < 255)
# get index
index = 255 * eoi + ord(self.data[eoi])
# get tranformed content
content = self.data[eoi + 1:]
# get lshift array
lshift = [i - 1 for symbol in sorted(set(content)) for i, x in enumerate(self.data) if x == symbol]
# restore
restored = ''
for i in range(len(content)):
index = lshift[index]
restored += content[index]
# return restored
return restored
原字符串:
Rostv 不愿在公主身上出言不逊,没有回过头来 房子,但留在村子里等她离开。当她 马车开出家门,他上马陪着她八 从博古赫罗沃到我们部队占领的道路几英里。在 在扬克沃的客栈里,他第一次恭敬地告别了她 时间允许自己亲吻她的手。
你怎么能这样说!他红着脸回答玛丽斯公主 表达对她的解脱的感激之情,正如她所说的那样 发生了。任何警察都会这样做!如果我们有 只打农民,不应该让敌人来这么远, 他羞愧地说道,想换个话题。我是 很高兴有机会结识你。 再见,公主。祝你幸福和安慰,希望 在更幸福的情况下再次见到你。如果你不想让我 脸红了,请不要感谢我!
解码字符串:
Rostv 不愿在公主身上出言不逊,没有回过头来 房子,但留在村子里等她离开。当她 马车开出家门,他上马陪着她八 从博古赫罗沃到我们部队占领的道路几英里。在 在扬克沃的客栈里,他第一次恭敬地告别了她 时间允许自己亲吻她的手。
你怎么能这样说话!不愿在公主面前出言不逊, Rostv 没有回家,而是留在了村子里 等待她的离开。当她的马车驶出家门时,他 从博古赫罗沃骑马并陪伴她八英里到达 道路被我军占领。在扬克沃的旅馆里,他恭敬地 离开她,第一次允许自己亲吻她 手。
你怎么能这样说话!不愿在公主面前出言不逊, Rostv 没有回家,而是留在了村子里 等待她的离开。当
奇怪的是,我在网上找到并测试过的其他实现似乎也会发生这种情况,例如 this one 和 this one。到底是怎么回事?我是否误解了转换的工作原理?或者这个实现不正确?
【问题讨论】:
【参考方案1】:找到答案了!该算法基于字符串连接到一个最终字符的假设,该字符是唯一的并且在字典上小于字符串中的任何其他字符。但是,由于我打算对任何给定字符使用 0-255 范围内的任何值,因此我无法使用额外的符号。幸运的是,thanks to John Kurlak 和一些额外的错误修复,我已经能够稍微修改我的初始实现来解释这个事实。这里是:
class BurrowsWheelerTransform:
def __init__(self, data):
self.data = data
def transform(self):
# get data size
size = len(self.data)
# get doubled string
self.data *= 2
# get order (by index) of rotations
order = sorted(range(size), key=lambda i: self.data[i:])
# get index of original rotation
index = order.index(0)
# return index appended with last column of (imaginary) rotation table
return chr(255) * (index // 255) + chr(index % 255) + ''.join(self.data[(i - 1 + size) % size] for i in order)
def restore(self):
# get index of end of index
eoi = next(i for i in range(len(self.data)) if ord(self.data[i]) < 255)
# get index
index = 255 * eoi + ord(self.data[eoi])
# get tranformed content
content = self.data[eoi + 1:]
size = len(content)
# get lshift array
lshift = [i for symbol in sorted(set(content)) for i, x in enumerate(content) if x == symbol]
# restore
restored = ''
for i in range(size):
index = lshift[index]
if index >= size: break
restored += content[index]
# return restored
return restored
谢谢,约翰!
【讨论】:
【参考方案2】:我在 C++ 中使用 BWT 排序算法遇到了同样的问题,感谢您的评论,我很快通过使用 16 位数组而不是 8 位来修复它,以允许最后一个字符的值高于 0xFF (255)(也有稍微修改 BWT 排序算法代码,使其接受 16 位数据)。现在可以正常使用了,谢谢。
【讨论】:
以上是关于Burrows-Wheeler 变换 (BWT) 重复字符串的主要内容,如果未能解决你的问题,请参考以下文章