在Python中合并两个不同长度的文件

时间:2012-05-13 22:16:12

标签: python

我有两个文件,列数相同但行数不同。一个文件是时间戳列表和一个单词列表,第二个文件是一个时间戳列表,其中包含每个单词中的声音列表,即:

9640 12783 she
12783 17103 had
...

9640 11240 sh
11240 12783 iy
12783 14078 hv
14078 16157 ae
16157 16880 dcl
16880 17103 d
...

我想合并这两个文件并创建一个条目列表,其中单词为一个值,而拼音为另一个,即:

[['she', 'sh iy']
 ['had', 'hv ae dcl d']
  ...

我是一个完整的Python(和编程)菜鸟,但我最初的想法是通过在第二个文件中搜索第一个文件中的第二个字段,然后将它们附加到列表中来实现。我试着这样做:

word = open('SA1.WRD','r')
phone = open('SA1.PHN','r')
word_phone = []

for line in word.readlines():
    words = line.split()
    word = words[2]
    word_phone.append(word)

for line in phone.readlines():
    phones = line.split()
    phone = phones[2]
    if int(phones[1]) <= int(words[1]):
        word_phone.append(phone)

print word_phone

这是输出:

['she', 'had', 'your', 'dark', 'suit', 'in', 'greasy', 'wash', 'water', 'all', 'year', 'sh', 'iy', 'hv', 'ae', 'dcl', 'd', 'y', 'er', 'dcl', 'd', 'aa', 'r', 'kcl', 'k', 's', 'uw', 'dx', 'ih', 'ng', 'gcl', 'g', 'r', 'iy', 's', 'iy', 'w', 'aa', 'sh', 'epi', 'w', 'aa', 'dx', 'er', 'q', 'ao', 'l', 'y', 'iy', 'axr']

正如我所说,我是一个完全的菜鸟,一些建议会非常有用。

更新 如果可能的话,我想重温这个问题。我修改了Lattyware的代码以在目录上运行:

phns = []
wrds = []
for root, dir, files in os.walk(sys.argv[1]):
    wrds = wrds + [ os.path.join( root, f ) for f in files if f.endswith( '.WRD' ) ]
    phns = phns + [ os.path.join( root, f ) for f in files if f.endswith( '.PHN' ) ]
phns.sort()
wrds.sort()
files = (zip(wrds,phns))

#OPEN THE WORD AND PHONE FILES, COMPARE THEM
output = []
for file in files:
    with open( file[0] ) as unsplit_words, open( file[1] ) as unsplit_sounds:
        sounds = (line.split() for line in unsplit_sounds)
        words = (line.split() for line in unsplit_words)
        output = output +  [
          (word, " ".join(sound for _, _, sound in
                    takeuntil(sounds, stop)))
                for start, stop, word in words
            ]

我想在这些文件的文件路径中保留一些信息。我想知道如何将拆分文件路径附加到此代码返回的列表中的元组,例如,

[('she', 'sh iy', 'directory', 'subdirectory'), ('had', 'hv ae dcl d', 'directory', subdirectory')]

我想我可以拆分路径然后将列表压缩在一起,但是上面的代码输出列表中有53,000个项目,但只处理了6300个文件对。

1 个答案:

答案 0 :(得分:3)

这是一个主要问题是将声音与单词匹配的任务。幸运的是,这很容易做到,因为我们可以简单地取出所有声音,直到它们与结束时间相匹配。

要做到这一点,我们必须构建一个takeuntil()函数 - itertools.takewhile()(我的原始解决方案),不幸的是需要额外的值,所以这是最好的解决方案。

def takeuntil(iterable, stop):
    for x in iterable:
        yield x
        if x[1] == stop:
            break

with open("SA1.WRD") as unsplit_words, open("SA1.PHN") as unsplit_sounds:
    sounds = (line.split() for line in unsplit_sounds)
    words = (line.split() for line in unsplit_words)
    output = [
        (word, " ".join(sound for _, _, sound in takeuntil(sounds, stop)))
        for start, stop, word in words
    ]

print(output)

给我们:

[('she', 'sh iy'), ('had', 'hv ae dcl d')]

此代码使用the with statement来提高可读性并关闭文件(即使是异常)。它也充分利用了list comprehensions and generator expressions

您的代码中存在一些不良模式。您在没有open()语句的情况下使用with是一个坏主意,并且不需要使用readlines()(直接在文件上循环 - 它是懒惰的,因此在大多数情况下效率更高,更不用说阅读更好,更少打字)。

那么这是如何工作的?让我们来看看它:

首先,我们打开两个要读取的文件,并使用快速生成器表达式来分割文件中的行。

接下来是一个怪物列表理解。我们在这里做的是从sounds迭代中取出声音,直到我们到达属于我们所在单词的最后一个声音,然后移动到下一个单词,返回单词和相关声音列表。然后我们使用str.join()将声音加入单个字符串。

如果您无法理解思考过程,那么这是一个扩展版本,其工作方式相同,但由于python端循环效率低得多(生成器和列表推导使得上面的更快):

with open("SA1.WRD") as words, open("SA1.PHN") as sounds:
    output = []
    current = []
    for line in words:
        start, stop, word = line.split()
        for sound_line in sounds:
            sound_start, sound_stop, sound = sound_line.split()
            current.append(sound)
            if sound_stop == stop:
                break
        output.append((word, " ".join(current)))
        current = []

print(output)