2

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

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 个文件对正在处理。

4

1 回答 1

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')]

此代码使用with语句来提高可读性并关闭文件(即使出现异常)。它还大量使用列表推导和生成器表达式

您的代码中有一些不好的模式。不使用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)
于 2012-05-13T22:33:40.877 回答