Bagaimana cara menghitung kemunculan setiap karakter?

13

Misalnya saya punya file 1.txt, yang berisi:

Moscow
Astana
Tokyo
Ottawa

Saya ingin menghitung jumlah semua char sebagai:

a - 4,
b - 0,
c - 1,
...
z - 0
Set-xx
sumber
4
Dari jawaban yang diterima, tidak sepenuhnya jelas, apakah Anda ingin "A" dan "a" dibedakan atau tidak? pertanyaan Anda menyarankan Anda melakukannya.
Jacob Vlijm

Jawaban:

20

Anda bisa menggunakan ini:

sed 's/\(.\)/\1\n/g' 1.txt | sort | uniq -ic
  4  
  5 a
  1 c
  1 k
  1 M
  1 n
  5 o
  2 s
  4 t
  2 w
  1 y

Bagian ini sedmenempatkan baris baru setelah setiap karakter. Kemudian kami sortouput secara alfabet. Dan pada akhirnya uniqmenghitung jumlah kejadian. The -iBendera uniqdapat menghilangkan sebagian jika Anda tidak ingin kasus ketidakpekaan.

kekacauan
sumber
3
Ini brilian. Peringatan tambahan adalah untuk menyalurkan output lagi ke sort -k 2daftar mereka berdasarkan alfanumerik.
tetris11
3
Ini adalah cara terpendek, paling bisa dimengerti tetapi untungnya paling lambat
c0rp
Pada Mac OS XI harus menggunakan sed -e $'s/\(.\)/\\1\\\n/g'(lihat juga stackoverflow.com/a/18410122/179014 )
asmaier
Untuk memesan dengan jumlah kejadian (menurun): | sort -rnk 1. Dan jika Anda berurusan dengan file yang sangat besar, seperti saya, Anda bisa mencicipi beberapa ribu baris untuk mendapatkan proksi untuk hitungan aktual:cat 1.txt | shuf -n 10000 | sed 's/\(.\)/\1\n/g' | sort | uniq -ic | sort -rnk 1
cpury
6

Agak terlambat, tetapi untuk menyelesaikan set, pendekatan python lain (3), hasil diurutkan:

#!/usr/bin/env python3
import sys

chars = open(sys.argv[1]).read().strip().replace("\n", "")
[print(c+" -", chars.count(c)) for c in sorted(set([c for c in chars]))]

A - 1
M - 1
O - 1
T - 1
a - 4
c - 1
k - 1
n - 1
o - 4
s - 2
t - 3
w - 2
y - 1

Penjelasan

  1. Baca file, lewati spasi dan kembali sebagai "karakter":

    chars = open(sys.argv[1]).read().strip().replace("\n", "")
  2. Buat seperangkat unik (diurutkan):

    sorted(set([c for c in chars]))
  3. Hitung dan cetak kemunculan untuk masing-masing karakter:

    print(c+" -", chars.count(c)) for c in <uniques>

Cara Penggunaan

  1. Rekatkan kode ke file kosong, simpan sebagai chars_count.py
  2. Jalankan dengan file sebagai argumen oleh:

    /path/to/chars_count.py </path/to/file>

    jika skrip dapat dieksekusi, atau:

    python3 /path/to/chars_count.py </path/to/file>

    jika tidak

Yakub Vlijm
sumber
5

Secara default di , F ield S eparator (FS) adalah spasi atau tab . Karena kami ingin menghitung setiap karakter, kami harus mendefinisikan ulang FS menjadi nothing ( FS="") untuk membagi setiap karakter dalam baris yang terpisah dan menyimpannya ke dalam array dan pada akhirnya di dalam END{..}blok, cetak total kemunculannya dengan perintah berikut :

$ awk '{for (i=1;i<=NF;i++) a[$i]++} END{for (c in a) print c,a[c]}' FS="" file
A 1
M 1
O 1
T 1
a 4
c 1
k 1
n 1
o 4
s 2
t 3
w 2
y 1

Dalam {for (i=1;i<=NF;i++) a[$i]++} ... FS="" ...blok kami hanya membagi karakter. Dan
dalam END{for (c in a) print c,a[c]}blok kita mengulang ke array adan mencetak karakter yang disimpan di dalamnya print cdan jumlah kemunculannyaa[c]

αғsнιη
sumber
3

Lakukan forperulangan untuk semua karakter yang ingin Anda hitung, dan gunakan grep -iountuk mendapatkan semua kemunculan karakter dan abaikan case, dan wc -luntuk menghitung instance, dan cetak hasilnya.

Seperti ini:

#!/bin/bash

filename="1.txt"

for char in {a..z}
do
    echo "${char} - `grep -io "${char}" ${filename} | wc -l`,"
done

Script menghasilkan ini:

a - 5,
b - 0,
c - 1,
d - 0,
e - 0,
f - 0,
g - 0,
h - 0,
i - 0,
j - 0,
k - 1,
l - 0,
m - 1,
n - 1,
o - 5,
p - 0,
q - 0,
r - 0,
s - 2,
t - 4,
u - 0,
v - 0,
w - 2,
x - 0,
y - 1,
z - 0,

Sunting setelah komentar

Untuk membuat lingkaran untuk semua karakter yang dapat dicetak, Anda dapat melakukan ini:

#!/bin/bash

filename="a.txt"

for num in {32..126}
do
   char=`printf "\x$(printf %x ${num})"`
   echo "${char} - `grep -Fo "${char}" ${filename} | wc -l`,"
done

Ini akan menghitung semua karakter ANSI dari 32 hingga 126 - ini adalah yang paling umum dibaca. Perhatikan bahwa ini tidak menggunakan kasus abaikan.

output dari ini adalah:

- 0,
! - 0,
" - 0,
# - 0,
$ - 0,
% - 0,
& - 0,
' - 0,
( - 0,
) - 0,
* - 0,
+ - 0,
, - 0,
- - 0,
. - 0,
/ - 0,
0 - 0,
1 - 0,
2 - 0,
3 - 0,
4 - 0,
5 - 0,
6 - 0,
7 - 0,
8 - 0,
9 - 0,
: - 0,
; - 0,
< - 0,
= - 0,
> - 0,
? - 0,
@ - 0,
A - 1,
B - 0,
C - 0,
D - 0,
E - 0,
F - 0,
G - 0,
H - 0,
I - 0,
J - 0,
K - 0,
L - 0,
M - 1,
N - 0,
O - 1,
P - 0,
Q - 0,
R - 0,
S - 0,
T - 1,
U - 0,
V - 0,
W - 0,
X - 0,
Y - 0,
Z - 0,
[ - 0,
\ - 0,
] - 0,
^ - 0,
_ - 0,
` - 0,
a - 4,
b - 0,
c - 1,
d - 0,
e - 0,
f - 0,
g - 0,
h - 0,
i - 0,
j - 0,
k - 1,
l - 0,
m - 0,
n - 1,
o - 4,
p - 0,
q - 0,
r - 0,
s - 2,
t - 3,
u - 0,
v - 0,
w - 2,
x - 0,
y - 1,
z - 0,
{ - 0,
| - 0,
} - 0,
~ - 0,
stalet
sumber
Jika Anda tidak ingin mengabaikan case maka hapus idari grep. (dalam pertanyaan Anda, Anda hanya memiliki 3 dalam hasil yang diharapkan)
stalet
Oh terima kasih. "{a..z}" - itu semua simbol dari 'a' ke 'z'? bagaimana dengan semua simbol yang dapat dicetak, bagaimana kita dapat menetapkannya tanpa mencantumkan semuanya
Set-xx
Saya telah memperbarui jawaban saya dengan contoh tentang cara memperluas pencarian untuk semua karakter yang dapat dibaca
stalet
Itu banyak panggilan ke grepseluruh input berulang kali.
200_success
3

Di sini solusi lain (awk) ...

awk '
        { for (indx=length($0); indx >= 1; --indx)
                ++chars[tolower(substr($0, indx, 1))]
        }
END     { for (c in chars) print c, chars[c]; }
' 1.txt | sort
  • Itu menciptakan array asosiatif dengan setiap karakter sebagai nilai indeks dan hitungan sebagai nilai array.
  • Tindakan END mencetak array.
Howard H.
sumber
tidak perlu cat file | awk '...': bisa langsung di bilang awk '...' file.
fedorqui
2

perlOneliner berikut akan menghitung. Saya menempatkan regex dalam konteks daftar (untuk mendapatkan jumlah kecocokan) dan memasukkannya ke dalam konteks skalar:

$ perl -e '$a=join("",<>);for("a".."z"){$d=()=$a=~/$_/gi;print"$_ - $d,\n"}' 1.txt
a - 5,
b - 0,
c - 1,
d - 0,
e - 0,
f - 0,
g - 0,
h - 0,
i - 0,
j - 0,
k - 1,
l - 0,
m - 1,
n - 1,
o - 5,
p - 0,
q - 0,
r - 0,
s - 2,
t - 4,
u - 0,
v - 0,
w - 2,
x - 0,
y - 1,
z - 0,
Sylvain Pineau
sumber
Untuk menghilangkan tanda koma tampaknya memerlukan penulisan ulang yang signifikan:perl -Mfeature=say -e '$a=join("",<>);say join(",\n", map { sprintf("%s - %d", $_, ($d=()=$a=~/$_/gi)); } ("a".."z"))'
200_success
2

Berikut ini solusi menggunakan Python:

#!/usr/bin/env python2
import collections, string
with open('1.txt') as f:
    input_string = f.read().replace('\n', '').lower()
    count_dict = collections.Counter(input_string)
    for char in string.lowercase:
        print char + ' - ' + str(count_dict[char]) + ','

Di sini kita telah menggunakan kelas collectionsmodul Counteruntuk menghitung jumlah kemunculan setiap karakter, kemudian untuk tujuan pencetakan kita telah menggunakan stringmodul untuk mendapatkan semua huruf kecil dengan variabel string.lowercase.

Simpan skrip di atas dalam file yang memberikan nama apa pun yang Anda inginkan misalnya count.py. Sekarang dari direktori yang sama di mana file disimpan, Anda dapat menjalankan python count.pyuntuk menjalankan file, dari direktori lain menggunakan jalur absolut ke file untuk menjalankannya yaitu python /absolute/path/to/count.py.

heemayl
sumber
Bisakah Anda menjelaskan solusi Anda. Maksud saya: buat file_name file, masukkan kode ini, chmod + x dll. Dll.
c0rp
@ c0rp: selesai ....
heemayl
1

Beberapa waktu yang lalu saya menulis program C untuk melakukan itu, karena saya membutuhkannya untuk melihat file besar dan menghasilkan beberapa statika.

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <sysexits.h>


inline static double square(double x)
{
    return x * x;
}


int main()
{
    static const unsigned distribution_size = 1 << CHAR_BIT;

    int rv = EX_OK;
    uintmax_t *distribution = calloc(distribution_size, sizeof(*distribution));

    {
        int c;
        while ((c = getchar()) != EOF)
            distribution[c]++;

        if (ferror(stdin)) {
            perror("I/O error on standard input");
            rv = EX_IOERR;
        }
    }

    uintmax_t sum = 0;
    for (unsigned i = 0; i != distribution_size; i++)
        sum += distribution[i];
    double avg = (double) sum / distribution_size;

    double var_accum = 0.0;
    for (unsigned i = 0; i != distribution_size; i++)
    {
        const uintmax_t x = distribution[i];

        printf("'%c' (%02X): %20ju", isprint((int) i) ? i : ' ', i, x);
        if (x != 0) {
            var_accum += square((double) x - avg);
            printf(" (%+.2e %%)\n", ((double) x / avg - 1.0) * 100.0);
        } else {
            var_accum += square(avg);
            putchar('\n');
        }
    }

    double stdev = sqrt(var_accum / distribution_size);
    double varcoeff = stdev / avg;
    printf(
        "total: %ju\n"
        "average: %e\n"
        "standard deviation: %e\n"
        "variation coefficient: %e\n",
        sum, avg, stdev, varcoeff);

    free(distribution);
    return rv;
}

kompilasi dengan (dengan asumsi kode sumber berada di character-distribution.c):

cc -std=c99 -O2 -g0 -o character-distribution character-distribution.c

jalankan dengan:

./character-distribution < 1.txt

Jika Anda tidak memiliki kompiler C yang siap, instal GCC:

sudo apt-get install gcc build-essential
David Foerster
sumber
0

Solusi serupa dengan @heemayl, dengan kode yang lebih ketat, yang berfungsi pada Python 2.7 dan Python 3.

#!/usr/bin/python

import collections
import fileinput
import itertools
import string

count = collections.Counter(itertools.chain(*fileinput.input()))
print(',\n'.join('{} - {}'.format(c, count[c] + count[c.upper()])
                 for c in string.ascii_lowercase))

Pernyataan pertama, count = collections.Counter(…)melakukan semua pekerjaan nyata.

  • fileinput.input() membaca setiap baris input, yang dapat disalurkan melalui stdin atau sebagai argumen baris perintah.
  • * membuatnya mempertimbangkan karakter pada suatu waktu daripada garis pada suatu waktu.
  • count = Counter(…)menghitung kemunculan setiap karakter secara efisien, dalam sekali lintasan, dan menyimpan hasilnya dalam countvariabel.

Baris kedua hanya mencetak hasilnya.

  • '{} - {}'.format(c, count[c] + count[c.upper()]) for c in string.ascii_lowercase membuat daftar setiap karakter dan jumlahnya.
  • print(',\n'.join(…)) menempatkannya dalam format yang diinginkan: satu per baris, dipisahkan dengan koma, tetapi tidak ada koma di baris terakhir.
200_sukses
sumber
0

GNU awk 4.1

awk -iwalkarray '{for (;NF;NF--) b[$NF]++} END {walk_array(b)}' FS=
[A] = 1
[O] = 1
[w] = 2
[k] = 1
[y] = 1
[T] = 1
[n] = 1
[a] = 4
[o] = 4
[c] = 1
[s] = 2
[t] = 3
[M] = 1

Jika Anda memiliki versi GNU awk yang lebih lama, Anda dapat menggunakannya for (c in b) print c, b[c].

Steven Penny
sumber
0

Inilah jawabannya menggunakan ruby. Hal ini dilakukan dengan mengubah string menjadi daftar unik karakter yang berbeda dan menggunakan metode hitungan pada masing-masing karakter.

#!/usr/bin/env ruby

String content = IO.read("1.txt")
content.split("").uniq.sort.each { |chr| puts( chr + ' - ' + content.count(chr).to_s) }
stalet
sumber