كيف يمكنني مطابقة ترتيب السلسلة بين وثيقتين في بيرل؟
-
04-10-2019 - |
سؤال
لدي مشكلة في صنع برنامج Perl لمطابقة الكلمات في مستندتين. دعنا نقول أن هناك مستندات A و B.
لذلك أريد حذف الكلمات في الوثيقة A ليست في المستند B.
مثال 1:
ج: أنا آكل البيتزا
ب: تذهب إلى السوق وتناول البيتزا
النتيجة: أكل البيتزا
مثال 2: ج: أكل البيتزا
ب: بيتزا تأكل
النتيجة: البيتزا (ترتيب الكلمة ذات صلة ، لذلك يتم حذف "تناول الطعام".)
أستخدم Perl للنظام والجمل في كل مستند ليست بأعداد كبيرة ، لذلك أعتقد أنني لن أستخدم SQL
والبرنامج هو subproram لتصنيف المقالات التلقائية للغة الإندونيسية (بهاسا)
شكرا ، آسف إذا كان سؤالي مربكا بعض الشيء. أنا جديد حقًا على "هذا العالم" :)
المحلول
حسنًا ، أنا بدون وصول في الوقت الحالي ، لذلك لا يضمن هذا 100 ٪ أو حتى الترجمة ولكن يجب أن توفر إرشادات كافية:
الحل 1: (ترتيب الكلمات لا يهم)
#!/usr/bin/perl -w
use strict;
use File::Slurp;
my @B_lines = File::Slurp::read_file("B") || die "Error reading B: $!";
my %B_words = ();
foreach my $line (@B_lines) {
map { $B_words{$_} = 1 } split(/\s+/, $line);
}
my @A_lines = File::Slurp::read_file("A") || die "Error reading A: $!";
my @new_lines = ();
foreach my $line (@A_lines) {
my @B_words_only = grep { $B_words{$_} } split(/\s+/, $line);
push @new_lines, join(" ", @B_words_only) . "\n";
}
File::Slurp::write_file("A_new", @new_lines) || die "Error writing A_new: $!";
يجب أن ينشئ هذا ملفًا جديدًا "a_new" يحتوي فقط على كلمات A الموجودة في B.
هذا يحتوي على خلل طفيف - سيحل محل أي مسافة متعددة في ملف A بمساحة واحدة ، لذلك
word1 word2 word3
سيصبح
word1 word2 word3
يمكن إصلاحه ولكن سيكون مزعجًا حقًا للقيام بذلك ، لذلك لم أكن أزعجني ما لم تكن ترغب في الحفاظ على مساحة البيضاء بنسبة 100 ٪ بشكل صحيح
الحل 2: (أمر الكلمات مهم ولكن يمكنك طباعة الكلمات من ملف A Out دون أي معيات للحفاظ على مساحة البيضاء على الإطلاق)
#!/usr/bin/perl -w
use strict;
use File::Slurp;
my @A_words = split(/\s+/gs, File::Slurp::read_file("A") || die "Error reading A:$!");
my @B_words = split(/\s+/gs, File::Slurp::read_file("B") || die "Error reading B:$!");
my $B_counter = 0;
for (my $A_counter = 0; $A_counter < scalar(@A_words); ++$A_counter) {
while ($B_counter < scalar(@B_words)
&& $B_words[$B_counter] ne $A_words[$A_counter]) {++$B_counter;}
last if $B_counter == scalar(@B_words);
print "$A_words[$A_counter]";
}
الحل 3 (لماذا نحتاج بيرل مرة أخرى؟ :))
يمكنك القيام بذلك بشكل تافه في Shell بدون Perl (أو عبر System () الاتصال أو backticks في البرنامج النصي Perl Perl)
comm -12 A B | tr "\012" " "
لاستدعاء هذا من بيرل:
my $new_text = `comm -12 A B | tr "\012" " " `;
لكن راجع تعليقي الأخير لماذا يمكن اعتبار ذلك "سيئًا بيرل" ... على الأقل إذا قمت بذلك في حلقة مع تكرار العديد من الملفات وتهتم بالأداء.