ファイル内の各文字で始まる単語数の計算

ファイル内の各文字で始まる単語数の計算

ファイルをインポートし、アルファベットの各文字が単語数の降順で単語を開始する回数を印刷する必要があります。たとえば、ファイルが次のような場合:

my nice name is Mike Meller 

その後、出力は次のようになります。

3 M
2 N
1 I

これを1行で行う必要があります。wc -mとのようなコマンドがあることを知っていますが、wc -w各文字を繰り返して同じ方法で印刷してから、好きな方法で並べ替える方法がわかりません。

答え1

片道...(同じ単語を2回カウントしないように編集)

$ echo "my nice name is Mike Meller" | tr ' ' '\n' | sort -f | uniq -i | sed -nr 's/^([a-z]).*/\U\1/Ip' | uniq -c | sort -r
  3 M
  2 N
  1 I
  • tr ' ' '\n'スペースを改行に変更
  • sort -f大文字と小文字が異なる場合でも、同じ項目が一緒になるように行を並べ替えます。
  • uniq -i重複した単語を削除して大文字と小文字を無視してください。
  • sed -nr 's/^([a-z]).*/\U\1/Ip'最初の文字を除くすべての文字を削除し、すべての文字を大文字に変更し、文字で始まらない行を印刷しないでください。
  • uniq -c同じ行数の計算
  • sort -r降順ソート

echo "my nice name is Mike Meller"次に交換... cat name-of-your-file

答え2

そしてperl

perl -Mopen=locale -lne '
  $c{uc $_}++ for /\b\p{Alpha}/g;
  END{for (sort {$c{$b} <=> $c{$a}} keys %c) {print "$c{$_} $_"}}'

一部の文字が分解形式で表示されることを確認してください。たとえば、É入力が事前結合(U + 00E9)の代わりに(たとえば、Eの後にU + 0301結合アクセント)、場合は事前結合(U + 00E9)の代わりにNorÉとして計算されます。EÉ

これが問題の場合、最善のアプローチは、最初にテキストを分解し(一部の文字には事前設定された形式がないため)、文字のクラスタに基づいて作業することです。とにかく、次のように分解したいものがあります。

比較する:

$ printf 'my fine name is \uc9ric, maybe E\u301ric, certainly not Eric\n' |
  perl -Mopen=locale -lne '
    $c{uc $_}++ for /\b\p{Alpha}/g;
    END{for (sort {$c{$b} <=> $c{$a}} keys %c) {print "$c{$_} $_"}}'
2 E
2 N
2 M
1 C
1 FI
1 É
1 I

そして:

$ printf 'my fine name is \uc9ric, maybe E\u301ric, certainly not Eric\n' |
  perl -Mopen=locale -MUnicode::Normalize -lne '
    $c{uc $_}++ for NFKD($_) =~ /\b(?=\p{Alpha})\X/g;
    END{for (sort {$c{$b} <=> $c{$a}} keys %c) {print "$c{$_} $_"}}'
2 É
2 M
2 N
1 E
1 I
1 C
1 F

答え3

GNU awk:

gawk '
  { for (i=1; i<=NF; i++) count[toupper(substr($i,1,1))]++ } 
  END {
    PROCINFO["sorted_in"] = "@val_num_desc"
    for (key in count) print count[key], key
  }
' file 

答え4

これは宿題ではありませんか? ;-) トリッキーな部分は、Mellerの「L」を2回計算したくないということです。そうですか?だから「ユニークさ」があります。

$cat t
my nice name is Mike Meller

その後、変換を実行するコマンドパイプラインが提供されます。

$tr '[a-z]' '[A-Z]' < t |     # Convert all to upper case
fold -b -w 1 |                # Break into one letter per line
awk -f t.awk |                # Pipe the whole mess to awk to count
sort -r -n                    # Sort in reverse numeric order

awkスクリプトは別々のファイルに分割するのが最善ですが、bashでは1行にすべて入れることができます。

$cat t.awk    
/ / {                         # Match spaces,
  for (c in wc) {dc[c]+=1}    #  Accumulate word count (wc) into doc count (dc)
  split("",wc)                #  Reset the word count
}

!/ / {                        # Match non-spaces,
  if (wc[$1] == "") wc[$1]=1  #  If haven't already seen char in this word, mark it Donny
}

# Finally, output the count and the letter
END {
  for (c in wc) {dc[c]+=1}    # Accumulate one last time, in case there is no trailing space
  for (c in dc) {print c, dc[c]}
}

(私のために)次のような出力が生成されます。

$tr '[a-z]' '[A-Z]' < t | fold -b -w 1 | awk -f t.awk  | sort -r -n
4 M
4 E
3 I
2 N
1 Y
1 S
1 R
1 L
1 K
1 C
1 A

関連情報