我有一个来自tatoeba的双语语料库(EN-JP),想将其拆分为两个单独的文件。字符串必须分别在同一行上说。
我需要这样做来训练nmt-keras中的NMT,并且训练数据必须存储在每种语言的单独文件中。我尝试了几种方法,但是由于我是python和编码方面的绝对初学者,所以我感觉像是在圈子里奔跑。
到目前为止,我管理得最好的是:
源txt:
Go. 行け。
Go. 行きなさい。
Hi. やっほー。
Hi. こんにちは!
代码:
with open('jpns.txt', encoding="utf8") as f:
columns = zip(*(l.split("\t") for l in f))
list1= list(columns)
print(list1)
[('Go.', 'Go.', 'Hi.', 'Hi.'), ('行け。\n', '行きなさい。\n', 'やっほー。\n', 'こんにちは!')]
包含我的代码的结果:
[('Go.', 'Go.', 'Hi.', 'Hi.'), ('行け。\n', '行きなさい。\n', 'やっほー。\n', 'こんにちは!')]
英语和日语适当地分开了(分成一个元组?),但我一直在努力弄清楚如何仅导出英语,以及如何分别将日语仅导出到output.en
和output.jp
。
预期结果:
output.en
Go.
Go.
Hi.
Hi.
output.jp
行け。
行きなさい。
やっほー。
こんにちは!
每个输出的字符串应在字符串后包含\ n。
请记住,我是编码的初学者,所以我不确定在“ zip”之后所做的事情,因为我刚刚在stackoverflow上找到了它。我真的很感激得到一个完整的评论建议。
答案 0 :(得分:2)
首先要注意的是,遍历文件会保留换行符。这意味着在您的两列中,第一列没有换行符,而第二列已经将换行符附加到每行(可能是最后一行除外)。
因此,如果您已经解开了生成器columns
的内容,那么写第二列就很简单了:
with open('output.jp', 'w') as f:
f.writelines(list1[-1])
但是您仍然必须在第一列中添加换行符(如果您使用多语言,则可能还要添加其他行)。一种方法是将换行符添加到除最后一行之外的所有列。另一个方法是从最后一列中删除这些列,并对其进行相同的处理。
您可以通过一个小循环并再次调用zip
来获得所需的结果:
langs = ('en', 'jp')
for index, (lang, data) in enumerate(zip(langs, columns)):
with open('output.' + lang, 'w') as f:
if index < len(langs) - 1:
data = (line + '\n' for line in data)
f.writelines(data)
除非我们位于最后一列,否则该方法用附加换行符的生成器替换元组data
。
有两种方法可以在输出文件的每一行之间插入换行符。我展示的是使用惰性生成器分别附加到每一行。这样可以节省一点内存。如果您不关心内存节省,则可以将整个文件输出为单个字符串:
joiner = '\n' if index < len(langs) - 1 else ''
f.write(joiner.join(data))
您甚至可以自己编写循环并将print
写入文件:
for line in data:
print(line, file=f, end='\n' if index < len(args) - 1 else '')
附录
我们还要详细研究columns = zip(*(l.split("\t") for l in f))
行,因为它是转置嵌套列表的非常常见的Python习惯用法,并且是获取所需结果的关键。
生成器表达式l.split("\t") for l in f
非常简单:它将文件中的每一行围绕制表符分开,为您提供两个元素,一个为英文,一个为日文。在生成器前面添加一个*
会对其进行扩展,以使每个由两个元素组成的行成为zip
的单独参数。 zip
然后重新组合每行的各个元素,因此您将获得一列英文元素和一列日文元素,从而有效地转换了原始的“矩阵”。
结果是columns
是列上的生成器。您可以将其转换为list
,但这仅是查看所需的。生成器对于上面显示的代码将正常工作。