12

私はすでに PHP を使用してこのソリューションを自分で考え出しましたが、どうすれば別の方法で実行できるか興味があります。私が主に興味を持っている 2 つの言語は PHP と Javascript ですが、今日の他の主要な言語 (主に C#、Java など) でもこれがどれほど迅速に行われるかを知りたいと思います。

  1. X より大きい出現回数を持つ単語のみを返す
  2. Y より大きい長さの単語のみを返す
  3. 「and、is、the など」などの一般的な用語を無視する
  4. 処理の前に句読点を自由に削除してください (つまり、"John's" は "John" になります)。
  5. 結果をコレクション/配列で返す

エクストラクレジット

  1. 引用されたステートメントを一緒に保管してください(つまり、「彼らは明らかに「真実であるには良すぎる」でした」)「真実であるには
    良すぎる」が実際のステートメントになります

エクストラエクストラクレジット

  1. 一緒に見つかる頻度に基づいて、まとめておくべき単語をスクリプトで判断できますか? これは、事前に言葉を知らずに行われます。例:
    *「ショウジョウバエは医学研究において素晴らしい存在です。ショウジョウバエについては過去に多くの研究が行われ、多くのブレークスルーがもたらされました。今後もショウジョウバエの研究は続けられますが、私たちの方法は変わるかもしれません。」*
    明らかに、ここにある単語は「フルーツ フライ」であり、簡単に見つけることができます。あなたの search'n'scrape スクリプトもこれを判断できますか?

ソーステキスト: http://sampsonresume.com/labs/c.txt

回答形式

  1. 操作がどれくらい続いたかに加えて、コードの結果、出力を確認することは素晴らしいことです.
4

13 に答える 13

11

GNU スクリプト

sed -e 's/ /\n/g' | grep -v '^ *$' | sort | uniq -c | sort -nr

結果:

  7 be
  6 to
[...]
  1 2.
  1 -

X より大きいオカレンス:

sed -e 's/ /\n/g' | grep -v '^ *$' | sort | uniq -c | awk '$1>X'

Y より大きい長さの単語のみを返します (2 番目の grep に Y+1 ドットを入れます):

sed -e 's/ /\n/g' | grep -v '^ *$' | grep .... | sort | uniq -c

「and、is、the など」のような一般的な用語を無視します (一般的な用語がファイルに「無視」されていると仮定します)

sed -e 's/ /\n/g' | grep -v '^ *$' | grep -vf ignored | sort | uniq -c

処理の前に句読点を自由に削除してください (つまり、"John's" は "John" になります):

sed -e 's/[,.:"\']//g;s/ /\n/g' | grep -v '^ *$' | sort | uniq -c

コレクション/配列で結果を返します。これはすでにシェルの配列のようなものです。最初の列はカウント、2 番目の列は単語です。

于 2009-06-24T20:53:52.983 に答える
6

わずか 43 文字の Perl。

perl -MYAML -anE'$_{$_}++for@F;say Dump\%_'

使用例を次に示します。

echo a a a b b c  d e aa | perl -MYAML -anE'$_{$_}++for@F;say Dump \%_'

---
a: 3
aa: 1
b: 2
c: 1
d: 1
e: 1

小文字バージョンのみをリストする必要がある場合は、さらに 2 文字必要です。

perl -MYAML -anE'$_{lc$_}++for@F;say Dump\%_'

指定されたテキストで機能するには、58 文字が必要です。

curl http://sampsonresume.com/labs/c.txt |
perl -MYAML -F'\W+' -anE'$_{lc$_}++for@F;END{say Dump\%_}'
実質 0m0.679s
ユーザー 0m0.304s
システム 0m0.084s

これは最後の例を少し拡張したものです。

#! perl
use 5.010;
use YAML;

while( my $line = <> ){
  for my $elem ( split '\W+', $line ){
    $_{ lc $elem }++
  }
  END{
    say Dump \%_;
  }
}
于 2009-06-24T18:54:40.260 に答える
4

F# : 304 文字

let f =
    let bad = Set.of_seq ["and";"is";"the";"of";"are";"by";"it"]
    fun length occurrence msg ->
        System.Text.RegularExpressions.Regex.Split(msg, @"[^\w-']+")
        |> Seq.countBy (fun a -> a)
        |> Seq.choose (fun (a, b) -> if a.Length > length && b > occurrence && (not <| bad.Contains a) then Some a else None)
于 2009-06-24T13:39:31.503 に答える
3

C# 3.0 (LINQ を使用)

これが私の解決策です。コードを短く保つために、LINQ/拡張メソッドのいくつかの非常に優れた機能を利用しています。

public static Dictionary<string, int> GetKeywords(string text, int minCount, int minLength)
{
    var commonWords = new string[] { "and", "is", "the", "as", "of", "to", "or", "in",
        "for", "by", "an", "be", "may", "has", "can", "its"};
    var words = Regex.Replace(text.ToLower(), @"[,.?\/;:\(\)]", string.Empty).Split(' ');
    var occurrences = words.Distinct().Except(commonWords).Select(w =>
        new { Word = w, Count = words.Count(s => s == w) });
    return occurrences.Where(wo => wo.Count >= minCount && wo.Word.Length >= minLength)
        .ToDictionary(wo => wo.Word, wo => wo.Count);
}

ただし、これは最も効率的な方法でO(n^2)はなく、単語数ではなくO(n)、この場合に最適であると私は信じています。より効率的な少し長いメソッドを作成できるかどうかを確認します。

サンプル テキストで関数を実行した結果を次に示します (最小出現回数: 3、最小長さ: 2)。

  3×そのような
  4×コード
  4×どれ
  4 x 宣言
  5×機能
  4 x ステートメント
  3×新品
  3×タイプ
  3 x キーワード
  7×ステートメント
  3×言語
  3×式
  3回の実行
  3×プログラミング
  オペレーター×4
  3 x 変数

そして私のテストプログラム:

static void Main(string[] args)
{
    string sampleText;
    using (var client = new WebClient())
        sampleText = client.DownloadString("http://sampsonresume.com/labs/c.txt");
    var keywords = GetKeywords(sampleText, 3, 2);
    foreach (var entry in keywords)
        Console.WriteLine("{0} x {1}", entry.Value.ToString().PadLeft(3), entry.Key);
    Console.ReadKey(true);
}
于 2009-06-24T13:30:45.827 に答える
3
#! perl
use strict;
use warnings;

while (<>) {
  for my $word (split) {
    $words{$word}++;
  }
}
for my $word (keys %words) {
  print "$word occurred $words{$word} times.";
}

それがシンプルな形です。並べ替え、フィルタリングなどが必要な場合:

while (<>) {
  for my $word (split) {
    $words{$word}++;
  }
}
for my $word (keys %words) {
  if ((length($word) >= $MINLEN) && ($words{$word) >= $MIN_OCCURRENCE) {
    print "$word occurred $words{$word} times.";
  }
}

出力を非常に簡単に並べ替えることもできます。

...
for my $word (keys %words) {
  if ((length($word) >= $MINLEN) && ($words{$word) >= $MIN_OCCURRENCE) {
    push @output, "$word occurred $words{$word} times.";
  }
}
$re = qr/occurred (\d+) /;
print sort {
  $a = $a =~ $re;
  $b = $b =~ $re;
  $a <=> $b
} @output;

真の Perl ハッカーは、これらをそれぞれ 1 行または 2 行で簡単に取得できますが、読みやすさを重視しました。



ブラッド

編集:これは、この最後の例を書き直す方法です

...
for my $word (
  sort { $words{$a} <=> $words{$b} } keys %words
){
  next unless length($word) >= $MINLEN;
  last unless $words{$word) >= $MIN_OCCURRENCE;

  print "$word occurred $words{$word} times.";
}

または、より高速に実行する必要がある場合は、次のように書くこともできます。

for my $word_data (
  sort {
    $a->[1] <=> $b->[1] # numerical sort on count
  } grep {
    # remove values that are out of bounds
    length($_->[0]) >= $MINLEN &&      # word length
    $_->[1] >= $MIN_OCCURRENCE # count
  } map {
    # [ word, count ]
    [ $_, $words{$_} ]
  } keys %words
){
  my( $word, $count ) = @$word_data;
  print "$word occurred $count times.";
}

もちろん、map を使用して効率を高め、grep を使用して余分な要素を削除し、sort を使用して並べ替えを行います。(その順番で行います)

これは、シュワルツ変換のわずかな変形です。

于 2009-06-24T14:14:10.873 に答える
3

ルビー

「縮小」すると、この実装は 165 文字になります。を使用array#injectして開始値 (デフォルトは 0 の Hash オブジェクト) を指定し、要素をループ処理して、ハッシュにロールします。結果は最小周波数から選択されます。

スキップする単語のサイズを数えていないことに注意してください。これは外部定数です。定数もカウントすると、解は 244 文字になります。

アポストロフィとダッシュは削除されませんが、含まれます。それらを使用すると単語が変更されるため、記号を超えたすべての情報を削除せずに単純に削除することはできません。

実装

CommonWords = %w(the a an but and is not or as of to in for by be may has can its it's)
def get_keywords(text, minFreq=0, minLen=2)
  text.scan(/(?:\b)[a-z'-]{#{minLen},}(?=\b)/i).
    inject(Hash.new(0)) do |result,w|
      w.downcase!
      result[w] += 1 unless CommonWords.include?(w)
      result
    end.select { |k,n| n >= minFreq }
end

テストリグ

require 'net/http'

keywords = get_keywords(Net::HTTP.get('www.sampsonresume.com','/labs/c.txt'), 3)
keywords.sort.each { |name,count| puts "#{name} x #{count} times" }

試験結果

code x 4 times
declarations x 4 times
each x 3 times
execution x 3 times
expression x 4 times
function x 5 times
keywords x 3 times
language x 3 times
languages x 3 times
new x 3 times
operators x 4 times
programming x 3 times
statement x 7 times
statements x 4 times
such x 3 times
types x 3 times
variables x 3 times
which x 4 times
于 2009-06-24T19:32:28.793 に答える
2

C# コード:

IEnumerable<KeyValuePair<String, Int32>> ProcessText(String text, int X, int Y)
{
    // common words, that will be ignored
    var exclude = new string[] { "and", "is", "the", "as", "of", "to", "or", "in", "for", "by", "an", "be", "may", "has", "can", "its" }.ToDictionary(word => word);
    // regular expression to find quoted text
    var regex = new Regex("\"[^\"]\"", RegexOptions.Compiled);

    return
        // remove quoted text (it will be processed later)
        regex.Replace(text, "")
        // remove case dependency
        .ToLower()
        // split text by all these chars
        .Split(".,'\\/[]{}()`~@#$%^&*-=+?!;:<>| \n\r".ToCharArray())
        // add quoted text
        .Concat(regex.Matches(text).Cast<Match>().Select(match => match.Value))
        // group words by the word and count them
        .GroupBy(word => word, (word, words) => new KeyValuePair<String, Int32>(word, words.Count()))
        // apply filter(min word count and word length) and remove common words 
        .Where(pair => pair.Value >= X && pair.Key.Length >= Y && !exclude.ContainsKey(pair.Key));
}

ProcessText(text, 3, 2) 呼び出しの出力:

3 x languages
3 x such
4 x code
4 x which
3 x based
3 x each
4 x declarations
5 x function
4 x statements
3 x new
3 x types
3 x keywords
3 x variables
7 x statement
4 x expression
3 x execution
3 x programming
3 x operators
于 2009-06-24T16:29:01.210 に答える
1

Python(258文字のまま、最初の行に66文字、句読点を削除するために30文字を含む):

W="and is the as of to or in for by an be may has can its".split()
x=3;y=2;d={}
for l in open('c.txt') :
    for w in l.lower().translate(None,',.;\'"!()[]{}').split() :
        if w not in W: d[w]=d.get(w,0)+1
for w,n in d.items() :
    if n>y and len(w)>x : print n,w

出力:

4 code
3 keywords
3 languages
3 execution
3 each
3 language
4 expression
4 statements
3 variables
7 statement
5 function
4 operators
4 declarations
3 programming
4 which
3 such
3 types
于 2009-06-24T19:36:52.187 に答える
1

C# の場合:

  1. LINQ、具体的には groupby を使用してから、グループ数でフィルター処理し、フラット化された (selectmany) リストを返します。

  2. LINQ を使用し、長さでフィルター処理します。

  3. LINQ を使用し、'badwords'.Contains でフィルター処理します。

于 2009-06-24T13:30:58.307 に答える
1

リボル

おそらく冗長なので、間違いなく勝者ではありませんが、仕事は完了します。

min-length: 0
min-count: 0

common-words: [ "a" "an" "as" "and" "are" "by" "for" "from" "in" "is" "it" "its" "the" "of" "or" "to" "until" ]

add-word: func [
    word [string!]
    /local
        count
        letter
        non-letter
        temp
        rules
        match
][    
    ; Strip out punctuation
    temp: copy {}
    letter: charset [ #"a" - #"z" #"A" - #"Z" #" " ]
    non-letter: complement letter
    rules: [
        some [
            copy match letter (append temp match)
            |
            non-letter
        ]
    ]
    parse/all word rules
    word: temp

    ; If we end up with nothing, bail
    if 0 == length? word [
        exit
    ]

    ; Check length
    if min-length > length? word [
        exit
    ]

    ; Ignore common words
    ignore: 
    if find common-words word [
        exit
    ]

    ; OK, its good. Add it.
    either found? count: select words word [
        words/(word): count + 1
    ][
        repend words [word 1]
    ]
]

rules: [
    some [
        {"}
        copy word to {"} (add-word word)
        {"}
        |
        copy word to { } (add-word word)
        { }
    ]
    end
]

words: copy []
parse/all read %c.txt rules

result: copy []
foreach word words [
    if string? word [
        count: words/:word
        if count >= min-count [
            append result word
        ]
    ]
]

sort result
foreach word result [ print word ]

出力は次のとおりです。

act
actions
all
allows
also
any
appear
arbitrary
arguments
assign
assigned
based
be
because
been
before
below
between
braces
branches
break
builtin
but
C
C like any other language has its blemishes Some of the operators have the wrong precedence some parts of the syntax could be better
call
called
calls
can
care
case
char
code
columnbased
comma
Comments
common
compiler
conditional
consisting
contain
contains
continue
control
controlflow
criticized
Cs
curly brackets
declarations
define
definitions
degree
delimiters
designated
directly
dowhile
each
effect
effects
either
enclosed
enclosing
end
entry
enum
evaluated
evaluation
evaluations
even
example
executed
execution
exert
expression
expressionExpressions
expressions
familiarity
file
followed
following
format
FORTRAN
freeform
function
functions
goto
has
high
However
identified
ifelse
imperative
include
including
initialization
innermost
int
integer
interleaved
Introduction
iterative
Kernighan
keywords
label
language
languages
languagesAlthough
leave
limit
lineEach
loop
looping
many
may
mimicked
modify
more
most
name
needed
new
next
nonstructured
normal
object
obtain
occur
often
omitted
on
operands
operator
operators
optimization
order
other
perhaps
permits
points
programmers
programming
provides
rather
reinitialization
reliable
requires
reserve
reserved
restrictions
results
return
Ritchie
say
scope
Sections
see
selects
semicolon
separate
sequence
sequence point
sequential
several
side
single
skip
sometimes
source
specify
statement
statements
storage
struct
Structured
structuresAs
such
supported
switch
syntax
testing
textlinebased
than
There
This
turn
type
types
union
Unlike
unspecified
use
used
uses
using
usually
value
values
variable
variables
variety
which
while
whitespace
widespread
will
within
writing
于 2009-06-24T15:32:22.837 に答える
0

PHPでの私の変種は次のとおりです。

$str = implode(file('c.txt'));
$tok = strtok($str, " .,;()\r\n\t");

$splitters = '\s.,\(\);?:'; // string splitters
$array = preg_split( "/[" . $splitters . "]*\\\"([^\\\"]+)\\\"[" . $splitters . "]*|[" . $splitters . "]+/", $str, 0, PREG_SPLIT_DELIM_CAPTURE );

foreach($array as $key) {
    $res[$key] = $res[$key]+1;
}

$splitters = '\s.,\(\)\{\};?:'; // string splitters
$array = preg_split( "/[" . $splitters . "]*\\\"([^\\\"]+)\\\"[" . $splitters . "]*|[" . $splitters . "]+/", $str, 0, PREG_SPLIT_DELIM_CAPTURE );

foreach($array as $key) {
    $res[$key] = $res[$key]+1;
}

unset($res['the']);
unset($res['and']);
unset($res['to']);
unset($res['of']);
unset($res['by']);
unset($res['a']);
unset($res['as']);
unset($res['is']);
unset($res['in']);
unset($res['']);

arsort($res);
//var_dump($res); // concordance
foreach ($res AS $word => $rarity)
    echo $word . ' <b>x</b> ' . $rarity . '<br/>';

foreach ($array as $word) { // words longer than n (=5)
//    if(strlen($word) > 5)echo $word.'<br/>';
}

そして出力:

statement x 7
be x 7
C x 5
may x 5
for x 5
or x 5
The x 5
as x 5
expression x 4
statements x 4
code x 4
function x 4
which x 4
an x 4
declarations x 3
new x 3
execution x 3
types x 3
such x 3
variables x 3
can x 3
languages x 3
operators x 3
end x 2
programming x 2
evaluated x 2
functions x 2
definitions x 2
keywords x 2
followed x 2
contain x 2
several x 2
side x 2
most x 2
has x 2
its x 2
called x 2
specify x 2
reinitialization x 2
use x 2
either x 2
each x 2
all x 2
built-in x 2
source x 2
are x 2
storage x 2
than x 2
effects x 1
including x 1
arguments x 1
order x 1
even x 1
unspecified x 1
evaluations x 1
operands x 1
interleaved x 1
However x 1
value x 1
branches x 1
goto x 1
directly x 1
designated x 1
label x 1
non-structured x 1
also x 1
enclosing x 1
innermost x 1
loop x 1
skip x 1
There x 1
within x 1
switch x 1
Expressions x 1
integer x 1
variety x 1
see x 1
below x 1
will x 1
on x 1
selects x 1
case x 1
executed x 1
based x 1
calls x 1
from x 1
because x 1
many x 1
widespread x 1
familiarity x 1
C's x 1
mimicked x 1
Although x 1
reliable x 1
obtain x 1
results x 1
needed x 1
other x 1
syntax x 1
often x 1
Introduction x 1
say x 1
Programming x 1
Language x 1
C, like any other language, has its blemishes. Some of the operators have the wrong precedence; some parts of the syntax could be better. x 1
Ritchie x 1
Kernighan x 1
been x 1
criticized x 1
For x 1
example x 1
care x 1
more x 1
leave x 1
return x 1
call x 1
&& x 1
|| x 1
entry x 1
include x 1
next x 1
before x 1
sequence point x 1
sequence x 1
points x 1
comma x 1
operator x 1
but x 1
compiler x 1
requires x 1
programmers x 1
exert x 1
optimization x 1
object x 1
This x 1
permits x 1
high x 1
degree x 1
occur x 1
Structured x 1
using x 1
struct x 1
union x 1
enum x 1
define x 1
Declarations x 1
file x 1
contains x 1
Function x 1
turn x 1
assign x 1
perhaps x 1
Keywords x 1
char x 1
int x 1
Sections x 1
name x 1
variable x 1
reserve x 1
usually x 1
writing x 1
type x 1
Each x 1
line x 1
format x 1
rather x 1
column-based x 1
text-line-based x 1
whitespace x 1
arbitrary x 1
FORTRAN x 1
77 x 1
free-form x 1
allows x 1
restrictions x 1
Comments x 1
C99 x 1
following x 1
// x 1
until x 1
*/ x 1
/* x 1
appear x 1
between x 1
delimiters x 1
enclosed x 1
braces x 1
supported x 1
if x 1
-else x 1
conditional x 1
Unlike x 1
reserved x 1
sequential x 1
provides x 1
control-flow x 1
identified x 1
do-while x 1
while x 1
any x 1
omitted x 1
break x 1
continue x 1
expressions x 1
testing x 1
iterative x 1
looping x 1
separate x 1
initialization x 1
normal x 1
modify x 1
control x 1
structures x 1
As x 1
imperative x 1
single x 1
act x 1
sometimes x 1
curly brackets x 1
limit x 1
scope x 1
language x 1
uses x 1
evaluation x 1
assigned x 1
values x 1
To x 1
effect x 1
semicolon x 1
actions x 1
common x 1
consisting x 1
used x 1

var_dumpステートメントは単に一致を表示します。このバリアントは、二重引用符で囲まれた式を保持します。

提供されたファイルの場合、このコードは0.047秒で終了します。ただし、ファイルが大きいと大量のメモリが消費されます (file関数のため)。

于 2009-06-24T14:40:20.460 に答える
0

これはゴルフ賞を受賞するつもりはありませんが、引用されたフレーズをまとめて保持し、ストップワードを考慮に入れています (そしてCPANモジュールLingua::StopWordsText::ParseWordsを活用しています)。

さらに、to_Sfrom Lingua::EN::Inflect::Numberを使用して、単語の単数形のみを数えます。

Lingua::CollinsParserも参照してください。

#!/usr/bin/perl

use strict; use warnings;

use Lingua::EN::Inflect::Number qw( to_S );
use Lingua::StopWords qw( getStopWords );
use Text::ParseWords;

my $stop = getStopWords('en');

my %words;

while ( my $line = <> ) {
    chomp $line;
    next unless $line =~ /\S/;
    next unless my @words = parse_line(' ', 1, $line);

    ++ $words{to_S $_} for
        grep { length and not $stop->{$_} }
        map { s!^[[:punct:]]+!!; s![[:punct:]]+\z!!; lc }
        @words;
}

print "=== only words appearing 4 or more times ===\n";
print "$_ : $words{$_}\n" for sort {
    $words{$b} <=> $words{$a}
} grep { $words{$_} > 3 } keys %words;

print "=== only words that are 12 characters or longer ===\n";
print "$_ : $words{$_}\n" for sort {
    $words{$b} <=> $words{$a}
} grep { 11 < length } keys %words;

出力:

=== 4回以上出現する単語のみ ===
ステートメント : 11
機能 : 7
式 : 6
5月:5
コード:4
変数 : 4
オペレーター:4
宣言 : 4
c:4
タイプ: 4
=== 12文字以上の単語のみ ===
再初期化: 2
制御フロー: 1
シーケンスポイント: 1
最適化: 1
中括弧 : 1
テキスト行ベース: 1
非構造化: 1
列ベース: 1
初期化: 1
于 2010-03-16T01:32:47.093 に答える