2

私は、(演習のために)同じ単語のテキストファイルをチェックし、それらを新しいファイルに(ダブルスなしで)出力するperlプログラムを書く必要があります。

誰か助けてください。am// 関数を使用して単語を検索できることは理解していますが、存在しない可能性のある単語をどのように検索すればよいでしょうか? 例: テキスト ファイルに次のものが含まれている場合:

こんにちは、こんにちは、お元気ですか?このファイルを「Hello」なし で新しいファイルにコピーしたい場合があります。もちろん、ファイルに繰り返しの単語があるかどうかはわかりません。これが、繰り返しの単語を検索するプログラムの考え方です。

単語をアルファベット順に並べ替える基本的なスクリプトがありますが、繰り返される単語を見つけるステップ 2 がわかりません。スクリプトは次のとおりです(これまでのところ正しいことを願っています):

#!/usr/bin/perl 
use strict;
use warnings;

my $source = shift(@ARGV);
my $cible = shift(@ARGV);

open (SOURCE, '<', $source) or die ("Can't open $source\n");
open (CIBLE, '>', $cible) or die ("Can't open $cible\n");

my @lignes = <SOURCE>;
my @lignes_sorted = sort (@lignes);

print CIBLE @lignes_sorted;

chomp @lignes;
chomp @lignes_sorted;

print "Original text : @lignes\n";

sleep (1);

print "Sorted text : @lignes_sorted\n"; 

close(SOURCE);
close (CIBLE);
4

4 に答える 4

1

文章から単語を重複排除することは、思ったよりも複雑です。たとえば、空白で文を分割すると、Hello,単語以外の文字を含む「単語」が得られ、実際の単語と重複しないと見なされHelloます。考慮すべき多くの変数がありますが、空白を除くすべての文字が正当な単語を構成するという最も単純なケースを想定すると、次のようにすることができます。

$ perl -anlwe '@F=grep !$seen{$_}++, @F; print "@F";' hello.txt
Hello, how are you?
yada Yada this is test material dupe Dupe

$ cat hello.txt
Hello, Hello, how are you?
yada Yada this is test material dupe dupe Dupe

ご覧のとおり、考慮せずyadaYada複製します。Helloの複製も考慮しませんHello,。使用を追加するlcuc、大文字と小文字の依存関係を削除することでこれを微調整し、空白以外のさまざまな区切り文字を許可できます。

ここで行っているのは、ハッシュを使用して、%seen以前に出現した単語を追跡することです。基本的なプログラムは次のとおりです。

while (<>) {         # reading input file or stdin
    @F = split;      # splitting $_ on whitespace by default
    @F = grep !$seen{$_}++, @F;   # remove duplicates
    print "@F";      # print array elements space-separated 
}

の機能は!$seen{$_}++、新しいキーが初めて入力されたときに式が true を返し、それ以外の場合は false を返すことです。それはどのように機能しますか?実行されるさまざまな手順は次のとおりです。

$seen{$_}     # value for key $_ is fetched
$seen{$_}++   # value for key $_ is incremented, undef -> 1
              # $foo++ returns the value *before* it is incremented, 
              # so it returns undef
!$seen{$_}++  # this is now "! undef", meaning "not false", as in true.

1 以上の値はすべて true であり、not演算子はそれらをすべて false に否定します。

于 2013-03-16T15:58:43.290 に答える
0

大文字と小文字が異なる重複した単語を見つける心配がない場合は、1 つの置換でこれを行うことができます。

use strict;
use warnings;

my ($source, $cible) = @ARGV;

my $data;
{
    open ($source_fh, '<', $source) or die ("Can't open $source\n");
    local $/;
    $data = <$source_fh>;
}

$data =~ s/\b(\w+)\W+(?=\1\b)//g;

open (my $cible_fh, '>', $cible) or die ("Can't open $cible\n");
print $cible_fh $data;
于 2013-03-17T03:43:32.787 に答える
0

パールでは:

#!/usr/bin/perl -w
use strict;

my $source = shift(@ARGV);
my $cible = shift(@ARGV);

open (SOURCE, '<', $source) or die ("Can't open $source\n");
open (CIBLE, '>', $cible) or die ("Can't open $cible\n");

my @input = sort <SOURCE>;
my %words = ();
foreach (@input) {
    foreach my $word (split(/\s/)) {
        print CIBLE $word." " unless ( exists $words{$word} );
        $words{$word} = 1;
    }
}

close(SOURCE);
close (CIBLE);

基本的な考え方は、テキスト全体を (関数を使用して) 単一の単語に分割し、splitこの単語をキーとしてハッシュを作成することです。次の単語を読み取るときは、この単語が既にハッシュに含まれているかどうかを確認してください。もしそうなら - それは重複しています。

Hello, Hello, how are you?印刷される文字列の場合: Hello, how are you?.

于 2013-03-16T15:25:33.787 に答える
-1

Perl での実行方法はわかりませんが、sed といくつかの Unix ユーティリティを使用して簡単に実行できます。アルゴリズムは次のようになります。

  1. スペースを改行文字に置き換えて、すべての単語を区切ります
  2. 単語を並べ替える
  3. -c オプション (単語数) を指定して、並べ替えられた単語のリストを uniq 経由で送信します。
  4. 1 回出現するすべての単語を削除します (最初の列で 1 のカウント)

コマンドは次のようになります (\t を TAB に、\n を ENTER に置き換えます)。

sed 's/[ \t,.][ \t,.]*/\n/g' filename | sort | uniq -c | sed '/^  *\<1\>/d'

それが役立つことを願っています。

于 2013-03-16T15:23:08.367 に答える