情况如下:
我有两个版本的小说,都是txt格式。一个是原始语言,另一个是中文或英文翻译。阅读原始版本时,有时候我想快速查看特定句子的翻译版本。我的期望是:当我用原始语言输入特定句子时,翻译版本中的相应句子会直接进入我的眼睛。
这是我的方法:
我的原始想法是,由于Perl知道匹配查询的行的位置(从Chris的解决方案到我的第二篇文章的#lentnt),我需要做的就是让Perl使用该位置信息来显示内容另一个文件。但后来我意识到从一种语言转换到另一种语言更加复杂。一种语言中的一行内容可能会变成另一种语言中的两行甚至三行,并且会产生差异。然后我认为布莱恩对我的第三个问题的解决方案似乎再次有用。一种语言的一段内容在翻译时可能同样包含在一个段落中。我可以让Perl将段落视为一行。现在我来了以下代码。
这是我的代码:
#! perl
use warnings; use strict;
use autodie;
my $n;
my $file1 = "c:/FR.txt";
my $file2 = "c:/EN.txt";
print "INPUT YOUR QUERY:";
chomp(my $query=<STDIN>);
open my $fr,'<', $file1;
{ local $/="\n\n"; #learnt from brians's solution to [my 3rd question][1]
my @fr = <$fr>;
close $fr;
for (0 .. $#fr) { #learnt from Chris' solution to [my 2nd question][2]
if ($fr[$_] =~ /$query/i){
$n = $_;
}
}
}
open my $eng,'<',$file2;
{ local $/="\n\n";
my @eng = <$eng>;
close $eng;
print $eng[$n];
}
问题在这里:
1:这是解决问题的好方法吗?
2:当找不到匹配时,我会收到一条警告信息,上面写着“使用未经初始化的价值”等等。嗯,这是技术性的,是的,我知道其含义。但是有可能将此消息更改为“糟糕,找不到匹配”这样的内容吗?
测试文件类似于:
文件1
Chapitre premier Une petite ville La petite ville de Verrières peut passer pour l’une des plus jolies de la Franche-Comté....Espagnols, et maintenant ruinées. Verrières est abrité du ... depuis la chute de Napoléon ...de presque toutes les maisons de Verrières. à peine entre-t-on dans la ville ... ... Eh ! elle est à M. le maire.
file2的
CHAPTER 1 A Small Town The small town of Verrieres may be regarded as one of the most attractive....and now in ruins. Verrieres is sheltered ... since the fall of Napoleon, has led to the refacing of almost all the houses in Verrieres. No sooner has one entered the town ...Eh! It belongs to the Mayor.
如果搜索“La petite ville de”,屏幕上的输出应为:
The small town of Verrieres may be regarded as one of the most attractive....and now in ruins.
总是感谢任何评论:)
UPDATE1
感谢您的帮助!
现在问题2可以通过克里斯建议的一些小修改来解决:
if(defined $n) {
open my $eng,'<',$file2;
{ local $/="\n\n";
my @eng = <$eng>;
close $eng;
print $eng[$n];
}
} else {
print "Oops, no match found!\n";
}
UPDATE2
在处理大文件时,Chris的代码应该比我的代码运行得快得多。答案 0 :(得分:2)
(这只是对问题第1部分的回答)
我实际上已经开始了“翻译文本搜索”。我只是在文件中使用了百分比偏移量。这适用于短文本,但如果文本有任何长度,很快就会崩溃。
my $offset = $offset_of_passage_in_text1 * length ($text2)/length ($text1);
与文本长度相比的误差范围越来越大。对于整本书,我认为这种方法没有多大希望。
一个建议是将第二语言文本发送给Google翻译,或者通过某种s/(\w+)/$dictionary{$1}/
替换将其发送,然后搜索翻译文本中的关键词以找到翻译的可能位置。
以下是使这项工作的代码草图
open my $dictionary_file, "<:utf8", "name_of_file_containing_English_and_Chinese"
or die $!;
my %dictionary;
while (<$dictionary_file>) {
my ($english, $chinese) = split;
$dictionary{$english} = $chinese;
}
close $dictionary_file or die $!;
my $crude_translation = $english_text;
$crude_translation =~ s/(\w+)/$dictionary{$1}/g;
我没有测试过这个。最后一行不会尝试捕获由字典中没有的单词引起的错误。
答案 1 :(得分:2)
为避免出现此警告,您必须检查$n
是否为defined()
:
if(defined $n) {
open my $eng,'<',$file2;
{ local $/="\n\n";
<$eng> while --$n;
print scalar <$eng>;
close $eng;
}
} else {
print "No match found!\n";
}
我还重写了读英文的部分。它不是读取整个文件而只是使用它的一行,而是读入$n - 1
行并抛出它们,然后打印它读取的下一行(这次是真实的)。这应该具有相同的效果,但对大文件的内存影响较小。 (如果没有,那可能是一个错误,因为我累了。)
编辑:事实证明这引入了一个微妙的错误。您找到匹配行的代码执行相同的操作:将文件拖入数组,然后查找匹配的数组索引。让我们将此代码转换为逐行读取,这样我们就不会遇到大量的内存消耗问题:
open my $fr,'<', $file1;
{ local $/="\n\n";
while(<$fr>) {
$n = $. if /$query/i;
}
}
我认为您理解大部分内容:while(<$fr>)
从$fr
逐行读取并将每行设置为$_
以进行循环迭代,/$query/i
将隐式地匹配$_
(这是我们想要的),但你可能对这个小问题感到好奇:$n = $.
。来自perldoc perlvar
:
- 把手型&GT; input_line_number(EXPR)
- $ INPUT_LINE_NUMBER
- $ NR
- $。
访问的最后一个文件句柄的当前行号。
Perl中的每个文件句柄都会计算从中读取的行数。 (根据$ /的值,Perl对构成一行的构思可能与你的不匹配。)当从文件句柄读取一行(通过readline()或&lt;&gt;),或者tell()或seek(在它上面调用,$。成为该文件句柄的行计数器的别名。
您可以通过分配$来调整计数器。 ,但这实际上不会移动搜索指针。本地化$。不会本地化文件句柄的行数。相反,它将本地化perl的文件句柄$的概念。目前是别名。
$。文件句柄关闭时重置,但是在没有插入close()的情况下重新打开文件句柄时重置。有关更多详细信息,请参阅perlop中的“I / O操作符”。因为&lt;&gt;从不在ARGV文件中显式关闭,行号增加(但请参阅eof中的示例)。
您还可以使用HANDLE-&gt; input_line_number(EXPR)访问给定文件句柄的行计数器,而不必担心您上次访问的句柄。
(助记符:许多程序使用“。”表示当前行号。)
因此,如果我们在您的第三段中找到匹配项,则$.
将为3.作为一般建议,请每隔一段时间阅读perlvar
页面。那里有一些宝石,即使你不明白一切都是什么,你也会重读。
然而,我要说的最后一点是关于明确存储段落信息的mobrule's advice可能是最好的方法。我可能会回避自制格式,但我理解,对于您的目的,XML或某些东西是否有点重量级。 (只要知道如果你不小心,你的目的可能会大大扩展)。
答案 2 :(得分:2)
从数据录入的有利位置来看,将文件拆分为双重换行符似乎是一个等待发生的事故(或令人尴尬的一个一个错误)。如果章节和段落的概念在两个翻译中是相同的,那么在文件中包含该信息会更安全。有点像...
FR.txt -- :i,j,k ==> Chapter i, Paragraph j, Sentence/Clause k
------
:1,1,0
Chapter premiere
:1,1,1
Une petite ville
...
EN.txt
------
...
:1,1,4
No sooner has one entered the town ...Eh! It belongs to the Mayor.
...
当您遍历法语文件时,您会跟踪找到正确文本时看到的最后一条索引信息,然后在英文文件中查找相同的索引信息并打印出后面的文本。
除了使您不易受输入错误(在某处键入额外的换行符)之外,此方法还为您提供了组织数据的其他方法。也许有一天你会按字母顺序对法语文本进行排序,以便更快地找到文本,同时保持按索引排序的英文文本按索引查找文本。也许将来你会从数据库中检索这些数据。
<小时/>
要回答您的第二个问题,可以按摩您的警告信息,但这不是初学者通常会尝试做的事情。它涉及安装 __WARN__
处理程序。 perldoc for warn给出了足够温和的概念介绍。对于您的应用程序,它可能类似于:
$SIG{__WARN__} = sub {
my $msg = shift;
if ($msg =~ /Use of uninitialized value/) {
warn "Oops! No value was found.\n"; # ok to call "warn" inside handler
} else {
warn $msg;
}
};
答案 3 :(得分:1)
这是一种不同的方法供您考虑:
use strict;
use warnings;
use File::Slurp qw(read_file);
my %para = map { $_ => Read_paragraphs("$_.txt") } qw(FR EN);
my $query = 'La petite ville de';
my @matches =
map { $para{EN}[$_] }
grep { $para{FR}[$_] =~ /$query/ }
0 .. @{$para{FR}} - 1
;
print $_, "\n" for @matches;
sub Read_paragraphs {
return [split /\n{2,}/, read_file(shift)];
}