Python将制表符分隔的双语txt拆分为两个单独的txt文件(列表),并使用换行符分隔字符串

时间:2019-01-10 19:29:00

标签: python unicode split

我有一个来自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.enoutput.jp

预期结果:

output.en

Go.
Go.
Hi.
Hi.

output.jp

行け。
行きなさい。
やっほー。
こんにちは!

每个输出的字符串应在字符串后包含\ n。

请记住,我是编码的初学者,所以我不确定在“ zip”之后所做的事情,因为我刚刚在stackoverflow上找到了它。我真的很感激得到一个完整的评论建议。

1 个答案:

答案 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,但这仅是查看所需的。生成器对于上面显示的代码将正常工作。