韩林涛老师:译者编程知识30天×300字写作计划 | Day 7

背景

我们接到了一个客户的机器翻译译后编辑项目需求,对方提供了20万字的英文,共4700句话,并且提供了机器翻译给出的中文译文,要求我们提供译后编辑结果。

客户提供的英文和中文在两个不同的txt文本中,两个文本中的句子均是以换行符隔开。

客户并未说明使用怎样的工具完成译后编辑,仅需要译后编辑之后的结果。

(注:以上案例描述已在真实案例信息基础上进行了调整,隐去了关键信息)

在拿到这个项目后,我很快在研一本地化管理方向的学生中召集了一位同学担任项目经理,与客户联络具体的项目需求,在本周《翻译项目管理》课上以此为案例分析此类项目的需求背景、项目规划方法、报价方法等。并在《翻译与本地化工程技术实践》课上为同学介绍了在实际操作过程中如何创建项目和分配项目。

在今天这篇帖子中,我主要介绍如何通过编程对txt格式任务文件进行切分。

正文

我们在本文中依然是以PHP为例介绍如何开发一个txt文件切分工具,主要是考虑到开发完成后可以比较方便部署成在线工具,一次开发部署方便多人同时随时随地使用。

第一步:读取待处理文本

为了方便展示,我创建了一个名为demo.txt的文本文件,里面包含10个句子,计划将其切分后每个文件中包含3行。

我们在开发环境的根目录下创建名为split的文件夹,将上述txt文件放置到split文件夹内,并在该文件夹内创建一个名为index.php的文件,输入代码如下:

第3行:定义一个变量,将待处理的文件名放置其中

第5行:使用file_get_contents()函数读取txt文件,并将读取后的内容放置到$file_content变量中

第7行:使用explode()函数将txt文本中的所有句子以换行符(\n)分割开编程数组(Array),并将数组放置到$sentences_array变量中。

第9行:将数组显示到浏览器中

以上代码运行结果如下:

需要特别注意:变成数组后,数组中的元素是从0开始排序。

第二步:循环遍历数组,将所有句子放置到一个变量中

我们的目标是将整个文件切分成几个小文件并导出,所以需要先了解如何把目标文件创建出来,因此需要先循环遍历数组:

第11行:统计一共有多少个句子

第13行:创建一个空白的变量$exported_sentences存储需要导出的句子

第15行:开启一个for循环,从0个句子开始,每循环一次后就自加1,直到全部句子都遍历完

第17行:当开始第0次循环时,读取$sentences_array数组的第0个元素($sentences_array[$i]),并将该元素的内容连同一个换行符(\n)一起放到$exported_sentences变量中

第19行:使用fopen()函数创建并打开一个空白的可写入txt文件:exported.txt

第21行:将$exported_sentences变量中的句子写入到txt文件中

第23行:关闭exported.txt文件

以上代码运行完成后,根目录下会生成一个exported.txt文件:

打开后会看到所有句子:

第三步:根据切分文件中包含的条目数定义导出文件的条件

我们通过上一步已经知道如何导出文件了,接下来就是思考要导出的文件中应该包含多少行句子。

在我们的测试文件中一共有10个句子,我们希望导出的文件中包含3个句子,这就意味着在设置导出条件时,1-3是一组,4-6是一组,7-9是一组,10是一组。

而在我们的之前创建的数组$exported_sentences中,所有句子是从0开始排序的,所以是:0-2一组,3-5是一组,6-8是一组,9是一组。

再具体一点就是:如果我们希望每个文件中有3个句子,那么第一个切分的断点就是在2后面,也就是:2 = 3-1。每个断点之间的间隔是3。

如果我们用变量$lines来定义每个文件中包含的句子数,那么第一个断点就是:$lines - 1

据此,我们可以添加一个新的循环来告知程序在何处产生断点:

第21行:创建一个新的for循环,从第一个断点开始,直到没有断点才结束

第23行:当我们从第一个句子开始遍历时,通过$i == $j 这个语句来判断是否遍历到一个断点,如果到了一个断点,就导出文件。

但是我们还不能现在就运行这段代码,因为从流程上来看,第一个文件导出后需要专门取一个名字,而不能就叫exported.txt,否则后面的文件就会覆盖旧的文件;而且第一个文件导出后,第一个文件所包含的句子就不能再导入到第二个文件中了,所以我们对代码进行如下修改:

第21行:新增一个$k变量,规定第一个导出文件的标号为1

第28行:规定第一个导出文件的名字为1.txt

第34行:每个文件导出后将之前的内容从$exported_sentences中清空

第37行:文件标号自加1,开始准备导出下一个文件

以上代码执行完成后效果如下:

我们会发现在当前的文件夹只看到了3个文件,每个文件中有3句话,只有最后一句话没有导出来。

之所以会出现这样的问题,在于上述代码的第23行。

我们前面讲了每个断点的标号:

0-2一组,3-5是一组,6-8是一组,9是一组。

到第一个断点时,$j的值是2;

到第二个断点时,$j的值是5;

到第三个断点时,$j的值是8;

按照这个推定,当第三个文件导出后,$j的值变成了8+3 = 11,而$i的值是不可能变成11的,因为$i最大才会是9,因此第四个文件就不会导出了。

此时$k = 4 而$j = 11,$eported_sentences已经装有最后几个句子,等待导出,我们只需要改进一下判断条件:

第17行:将$i < $num 修改为 $i < $lines * ceil($num/$lines),之所以这么修改是因为:如果我们一共有10句话,那么前九句话被断点分割后,我们应该在第12句增加一个断点。虽然我们没有第12句,但我们可以使用ceil()函数先算出总共可以分成几个文件,比如ceil(11/3) = 4,所以应该有4个文件,最后一个断点就是3*4 = 12。

第23行:将$j < $num 修改成$j < $num + $lines,也就是说在上面的例子里终止条件改成了11 < 10+3 。

以此我们可以输出最后一个文件。

现在我们成功完成了小工具的开发,总共不到20行。

在最开始的例子中,我们一共有4700个句子,我们按照每400个句子进行切分,只需要将第15行代码改成:$lines = 400,运行效果如下:

以上就是使用PHP对txt文件进行按行分割的方法,接下来就可以将所有文件导入到CAT工具里准备做译后编辑了。

优化

为了给大家展示编程的有趣之处,我再给大家提供一个思路:

PHP有个函数叫array_chunk(),它的作用是对数组进行切片,参加下面的代码:

运行结果如下:

可见通过这个函数就已经可以直接把文件分成我们想要的组。接下来就是遍历数组生成文件了:

$file) { $key = $key + 1; foreach($file as $line) { $exported_sentences = $exported_sentences.$line."\n"; $handle = fopen($key.".txt",'w'); fwrite($handle,$exported_sentences); fclose($handle); } $exported_sentences = ""; } ?>

简化后的代码不到15行,而且还可以继续简化。如果你聪明的话,还可以写出更简单的代码。

显然这种方法要比之前的方法更好理解,而且更节约代码。我们把两种方法都提供给大家比较分析,大家可以从中窥见编程的好处。

如果这种需求持续存在,还可以添加上传下载功能,放到网站上供更多人使用。

(不过,如果在网上搜索“txt杀手”,你会看到一款更简单粗暴的工具,不用写一行代码也可以完成txt文件的按行数分割。)

本篇原文首发于韩老师的微信公众号“简言”,原文标题为《如何将一个txt文件按行分割成多个小文件》。

作者:韩林涛,北京语言大学高级翻译学院教师,《译者编程入门指南》作者