5

テキストの文があるとしましょう:

$body = 'the quick brown fox jumps over the lazy dog';

その文を「キーワード」のハッシュに入れたいのですが、複数単語のキーワードを許可したいです。単一の単語のキーワードを取得するには、次のものが必要です。

$words{$_}++ for $body =~ m/(\w+)/g;

これが完了すると、次のようなハッシュが得られます。

'the' => 2,
'quick' => 1,
'brown' => 1,
'fox' => 1,
'jumps' => 1,
'over' => 1,
'lazy' => 1,
'dog' => 1

2 語のキーワードを取得するための次のステップは次のとおりです。

$words{$_}++ for $body =~ m/(\w+ \w+)/g;

しかし、それはすべての「他の」ペアを取得するだけです。次のようになります。

'the quick' => 1,
'brown fox' => 1,
'jumps over' => 1,
'the lazy' => 1

1 ワードのオフセットも必要です。

'quick brown' => 1,
'fox jumps' => 1,
'over the' => 1

これを行うには、次よりも簡単な方法はありますか?

my $orig_body = $body;
# single word keywords
$words{$_}++ for $body =~ m/(\w+)/g;
# double word keywords
$words{$_}++ for $body =~ m/(\w+ \w+)/g;
$body =~ s/^(\w+)//;
$words{$_}++ for $body =~ m/(\w+ \w+)/g;
$body = $orig_body;
# triple word keywords
$words{$_}++ for $body =~ m/(\w+ \w+ \w+)/g;
$body =~ s/^(\w+)//;
$words{$_}++ for $body =~ m/(\w+ \w+ \w+)/g;
$body = $orig_body;
$body =~ s/^(\w+ \w+)//;
$words{$_}++ for $body =~ m/(\w+ \w+ \w+)/g;
4

5 に答える 5

5

説明されているタスクは手作業でコーディングするのが面白いかもしれませんが、n-gramを処理する既存のCPANモジュールを使用する方が良いのではないでしょうか。Text::Ngrams(ではなくText::Ngram)単語ベースのn-gram分析を処理できるようです。

于 2010-08-18T21:35:44.470 に答える
3

先読みで少しファンキーなことをすることができます:

私が行った場合:

$words{$_}++ for $body =~ m/(?=(\w+ \w+))\w+/g;

この式は、2 つの単語を先読み (およびそれらをキャプチャ) するが、1 を消費することを示しています。

私は得る:

%words: {
          'brown fox' => 1,
          'fox jumps' => 1,
          'jumps over' => 1,
          'lazy dog' => 1,
          'over the' => 1,
          'quick brown' => 1,
          'the lazy' => 1,
          'the quick' => 1
        }

カウントの変数を入れることでこれを一般化できるようです:

my $n    = 4;
$words{$_}++ for $body =~ m/(?=(\w+(?: \w+){$n}))\w+/g;
于 2010-08-18T21:43:03.023 に答える
2

私は先読みを使用して、最初の単語以外のすべてを収集します。そうすれば、位置は自動的に正しく進みます。

my $body = 'the quick brown fox jumps over the lazy dog';

my %words;

++$words{$1}         while $body =~ m/(\w+)/g;
++$words{"$1 $2"}    while $body =~ m/(\w+) \s+ (?= (\w+) )/gx;
++$words{"$1 $2 $3"} while $body =~ m/(\w+) \s+ (?= (\w+) \s+ (\w+) )/gx;

単語ごとに1つのグループを使用する代わりに、で任意の数の単語を収集できるため、代わりに単一のスペースを使用する場合は、少し単純化できます\s+(そうする場合は、修飾子を削除することを忘れないでください)。/x$2

于 2010-08-18T21:28:19.230 に答える
2

正規表現のみを使用してこれを行う特定の理由はありますか? 私にとって明らかなアプローチはsplit、テキストを配列に入れ、ネストされたループのペアを使用してそこからカウントを抽出することです。次のようなもの:

#!/usr/bin/env perl

use strict;
use warnings;

my $text = 'the quick brown fox jumps over the lazy dog';
my $max_words = 3;

my @words = split / /, $text;
my %counts;

for my $pos (0 .. $#words) {
  for my $phrase_len (0 .. ($pos >= $max_words ? $max_words - 1 : $pos)) {
    my $phrase = join ' ', @words[($pos - $phrase_len) .. $pos];
    $counts{$phrase}++;
  }
} 

use Data::Dumper;
print Dumper(\%counts);

出力:

$VAR1 = {
          'over the lazy' => 1,
          'the' => 2,
          'over' => 1,
          'brown fox jumps' => 1,
          'brown fox' => 1,
          'the lazy dog' => 1,
          'jumps over' => 1,
          'the lazy' => 1,
          'the quick brown' => 1,
          'fox jumps' => 1,
          'over the' => 1,
          'brown' => 1,
          'fox jumps over' => 1,
          'quick brown' => 1,
          'jumps' => 1,
          'lazy' => 1,
          'jumps over the' => 1,
          'lazy dog' => 1,
          'dog' => 1,
          'quick brown fox' => 1,
          'fox' => 1,
          'the quick' => 1,
          'quick' => 1
        };

編集:$phrase_len cjm のコメントに従って、誤った結果を引き起こしていた負のインデックスの使用を防ぐためにループを修正しました。

于 2010-08-18T22:13:58.820 に答える
1

pos演算子を使用する

pos SCALAR

m//g問題の変数の最後の検索が終了した位置のオフセットを返します($_変数が指定されていない場合に使用されます)。

@-特別な配列

@LAST_MATCH_START

@-

$-[0]最後に成功した一致の開始位置のオフセットです。n番目のサブパターンに$-[n]一致する部分文字列の開始位置のオフセット、またはサブパターンが一致しなかった場合。undef

たとえば、次のプログラムは、各ペアの 2 番目の単語を独自のキャプチャで取得し、一致の位置を巻き戻して、2 番目の単語が次のペアの最初の単語になるようにします。

#! /usr/bin/perl

use warnings;
use strict;

my $body = 'the quick brown fox jumps over the lazy dog';

my %words;
while ($body =~ /(\w+ (\w+))/g) {
  ++$words{$1};
  pos($body) = $-[2];
}

for (sort { index($body,$a) <=> index($body,$b) } keys %words) {
  print "'$_' => $words{$_}\n";
}

出力:

「クイック」 => 1
'クイック ブラウン' => 1
'茶色のキツネ' => 1
'キツネのジャンプ' => 1
「飛び越える」=> 1
「以上」 => 1
「怠け者」 => 1
'怠惰な犬' => 1
于 2010-08-18T21:07:43.363 に答える