Her karakterin oluşumları nasıl sayılır?


14

Örneğin 1.txt, aşağıdakileri içeren dosya var :

Moscow
Astana
Tokyo
Ottawa

Ben tüm char sayısını saymak istiyorum:

a - 4,
b - 0,
c - 1,
...
z - 0

4
Kabul edilen cevaptan tamamen açık değil, "A" ve "a" seçkin mi, değil mi? sorunuz bunu yapmanızı önerir.
Jacob Vlijm

Yanıtlar:


21

Bunu kullanabilirsiniz:

sed 's/./&\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

sedKısmında, her karakterin ardından bir yeni satır yerleştirir. Sonra biz sortalfabetik olarak çıkıyoruz . Ve sonunda uniqmeydana gelen olayları sayar. Büyük -i/ uniqküçük harf duyarsızlığı istemiyorsanız bayrağı kaldırılabilir.


3
Bu harika. Ek bir uyarı, sort -k 2alfanümerik olarak listelemek için çıktıyı tekrar boruya bağlamak olacaktır .
tetris11

3
Bu en kısa yol, en anlaşılır ama ne yazık ki en yavaş
c0rp

Mac OS XI'de kullanmak zorundaydı sed -e $'s/\(.\)/\\1\\\n/g'(ayrıca bkz. Stackoverflow.com/a/18410122/179014 )
asmaier

Oluş sayısına (azalan) tarafından sipariş etmek için: | sort -rnk 1. Ve benim gibi çok büyük dosyalarla uğraşıyorsanız, gerçek sayılar için bir proxy almak için sadece birkaç bin satır cat 1.txt | shuf -n 10000 | sed 's/\(.\)/\1\n/g' | sort | uniq -ic | sort -rnk 1
örnekleyebilirsiniz

6

Biraz geç, ancak seti tamamlamak için başka bir python (3) yaklaşımı, sonucu sıraladı:

#!/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

açıklama

  1. Dosyayı okuyun, boşlukları atlayın ve "karakter" olarak döndürür:

    chars = open(sys.argv[1]).read().strip().replace("\n", "")
  2. Bir (sıralı) benzersiz set oluşturun:

    sorted(set([c for c in chars]))
  3. Karakterlerin her birinin oluşumunu sayın ve yazdırın:

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

Nasıl kullanılır

  1. Kodu boş bir dosyaya yapıştırın, olarak kaydedin chars_count.py
  2. Dosyayla bağımsız değişken olarak aşağıdakilerden birini kullanarak çalıştırın:

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

    komut dosyası yürütülebilirse veya:

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

    değilse


5

Varsayılan olarak F IELD S eparator (FS) 'dir uzay veya sekme . Her karakteri saymak istiyor bu yana, hiçbir şey (FS yeniden tanımlamak zorunda kalacak FS="") bir diziye ve iç sonunda her ayrı satırda karakteri ve ona tasarrufu bölmek END{..}takip ederek toplam oluşumlarını yazdırmak bloğun komutu:

$ 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

Gelen {for (i=1;i<=NF;i++) a[$i]++} ... FS="" ...blokta sadece karakterleri böler. Ve
de END{for (c in a) print c,a[c]}bloğa biz diziye döngü vardır ave içinde karakterini kurtardı yazdırma'den print cve olaylar onun sayıa[c]


3

forSaymak istediğiniz tüm karakterler için bir döngü yapın grep -iove karakterin ve görmezlik durumunun tüm oluşumlarını elde etmek, wc -lörnekleri saymak ve sonucu yazdırmak için kullanın.

Bunun gibi:

#!/bin/bash

filename="1.txt"

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

Komut dosyası bunu verir:

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,

Yorumdan sonra DÜZENLE

Yazdırılabilir tüm karakterler için bir döngü oluşturmak için bunu yapabilirsiniz:

#!/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

Bu 32 ila 126 arasındaki tüm ANSI karakterlerini sayar - bunlar en yaygın olarak okunabilir karakterlerdir. Bunun yoksayma durumunu kullanmadığını unutmayın.

bundan çıktı:

- 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,

Davayı görmezden gelmek istemiyorsanız, grep'ten kaldırın i. (sorunuzda beklenen sonuçta yalnızca 3 tane vardı)
15'te

Oh teşekkürler. "{a..z}" - hepsi 'a' ile 'z' arasındaki semboller mi? yazdırılabilir tüm sembollere ne dersiniz, hepsini listelemeden bunları nasıl belirleyebiliriz?
Set-xx

Cevabımı, tüm okunabilir karakterler için aramanın nasıl genişletileceğine ilişkin bir örnekle güncelledim
stalet

Bu bir var çok çağrı grepdefalarca tüm girişi.
200_success

3

İşte başka bir çözüm (awk olarak) ...

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
  • Dizin değeri olarak her karakter ve dizi değeri olarak sayı ile ilişkilendirilebilir bir dizi oluşturur.
  • END eylemi diziyi yazdırır.

gerek yok cat file | awk '...': doğrudan söyleyebilirsin awk '...' file.
fedorqui

2

Aşağıdaki perloneliner sayımı yapar. Normal ifadeleri (eşleşme sayısını elde etmek için) liste bağlamına koydum ve skaler bağlama koydum:

$ 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,

Sondaki virgülden kurtulmak için önemli bir yeniden yazma gerekiyor gibi görünüyor:perl -Mfeature=say -e '$a=join("",<>);say join(",\n", map { sprintf("%s - %d", $_, ($d=()=$a=~/$_/gi)); } ("a".."z"))'
200_success

2

İşte Python kullanan bir çözüm:

#!/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]) + ','

Burada , her karakterin tekrarlama sayısını saymak için collectionsmodül Countersınıfını kullandık, daha sonra yazdırma amacıyla, stringtüm küçük harfleri değişken tarafından almak için modülü kullandık string.lowercase.

Yukarıdaki komut dosyasını istediğiniz herhangi bir ad vererek bir dosyaya kaydedin, örn count.py. Şimdi dosyanın kaydedildiği python count.pydizinden dosyayı yürütmek için çalıştırabilirsiniz, diğer herhangi bir dizinden dosyayı yürütmek için mutlak yolu kullanın yani python /absolute/path/to/count.py.


Lütfen çözümünüzü açıklığa kavuşturabilir misiniz? Yani: dosya_adı dosyası oluşturun, bu kodu koyun, chmod + x vb.
Vs

@ c0rp: bitti ....
heemayl

1

Bir süre önce bunu yapmak için bir C programı yazdım, çünkü büyük dosyalara bakmak ve bazı statikler üretmek için programa ihtiyacım vardı .

#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;
}

ile derleyin (kaynak kodun içinde olduğu varsayılarak character-distribution.c):

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

şununla koş:

./character-distribution < 1.txt

Hazır bir C derleyiciniz yoksa GCC'yi yükleyin:

sudo apt-get install gcc build-essential

0

@Heemayl'e benzer bir çözüm, Python 2.7 ve Python 3 üzerinde çalışan daha sıkı kod ile.

#!/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))

İlk açıklama, count = collections.Counter(…)tüm gerçek işi yapar.

  • fileinput.input() stdin aracılığıyla veya komut satırı argümanları olarak girilebilen girdinin her satırını okur.
  • * her seferinde bir satır yerine bir karaktere bakmasını sağlar.
  • count = Counter(…)her karakterin oluşumunu tek bir geçişte verimli bir şekilde sayar ve sonucu countdeğişkene kaydeder.

İkinci satır sadece sonuçları yazdırır.

  • '{} - {}'.format(c, count[c] + count[c.upper()]) for c in string.ascii_lowercase her karakterin ve sayılarının bir listesini yapar.
  • print(',\n'.join(…)) istenen biçime koyar: her satıra bir tane, virgülle ayrılmış ancak son satırda virgül yoktur.

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

GNU awk'nin önceki bir sürümüne sahipseniz kullanabilirsiniz for (c in b) print c, b[c].


0

İşte yakut kullanan cevap. Dizeyi farklı karakterlerin tek bir listesine dönüştürerek ve her birinde sayma yöntemini kullanarak yapılır.

#!/usr/bin/env ruby

String content = IO.read("1.txt")
content.split("").uniq.sort.each { |chr| puts( chr + ' - ' + content.count(chr).to_s) }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.