it-swarm-tr.com

Her satırdaki belirli bir karakterin sayısı nasıl sayılır?

Bazı metin işleme yardımcı programları tarafından her satırda belirli bir karakter sayısını saymak nasıl merak ediyordum?

Örneğin, " metninin her satırında

"hello!" 
Thank you!

İlk satır iki ve ikinci satır 0'dır.

Başka bir örnek ( her satırda.

97
Tim

Bunu sed ve awk ile yapabilirsiniz:

$ sed 's/[^"]//g' dat | awk '{ print length }'
2
0

dat örnek metniniz olduğunda sed, (her satır için) tüm - " Olmayan karakterleri siler ve awk her satır için boyutlarını yazdırır (yani lengthlength($0) ile eşdeğerdir; burada $0 geçerli satırı gösterir).

Başka bir karakter için sed ifadesini değiştirmeniz yeterlidir. Örneğin ( İçin:

's/[^(]//g'

Güncelleme:sed görev için bir miktar aşırıya kaçma - tr yeterli. tr ile eşdeğer bir çözüm:

$ tr -d -c '"\n' < dat | awk '{ print length; }'

Yani tr, -c Karakter kümesinde olmayan ("\n Tamamlayıcı anlamına gelir) tüm karakterleri siler.

115
maxschlepzig

Ben sadece awk kullanırdım

awk -F\" '{print NF-1}' <fileName>

Burada alan ayırıcısını (-F bayrağıyla) " o zaman tek yaptığımız alan sayısını yazdırmak NF - 1. Hedef karakterin oluşum sayısı, ayrılmış alan sayısından bir az olacaktır.

Kabuk tarafından yorumlanan komik karakterler için, onlardan kaçtığınızdan emin olmanız gerekir, aksi takdirde komut satırı bunları dener ve yorumlar. Yani her ikisi için " ve ) alan ayırıcısından kaçmanız gerekiyor (\).

52
Martin York

tr ard wc kullanarak:

function countchar()
{
    while IFS= read -r i; do printf "%s" "$i" | tr -dc "$1" | wc -m; done
}

Kullanımı:

$ countchar '"' <file.txt  #returns one count per line of file.txt
1
3
0

$ countchar ')'           #will count parenthesis from stdin
$ countchar '0123456789'  #will count numbers from stdin
15
Stéphane Gimenez

Harici programlara dayanmayan başka bir uygulama, bash, zsh, yash ve ksh 'nin bazı uygulamaları/sürümleri:

while IFS= read -r line; do 
  line="${line//[!\"]/}"
  echo "${#line}"
done <input-file

line="${line//[!(]}" Saymak için ( Kullanın.

11
enzotib

awk kullanan cevaplar, eşleşme sayısı çok fazlaysa (bu benim durumum olur) başarısız olur. loki-astari yanıtı için aşağıdaki hata bildirilir:

awk -F" '{print NF-1}' foo.txt 
awk: program limit exceeded: maximum number of fields size=32767
    FILENAME="foo.txt" FNR=1 NR=1

enzotib (ve manatwork ) 'den eşdeğer bir cevap için bir segmentasyon hatası oluşur:

awk '{ gsub("[^\"]", ""); print length }' foo.txt
Segmentation fault

maxschlepzig ile sed çözümü doğru çalışıyor, ancak yavaş (aşağıdaki zamanlamalar).

Burada henüz önerilmeyen bazı çözümler. İlk olarak, grep kullanarak:

grep -o \" foo.txt | wc -w

Ve Perl kullanarak:

Perl -ne '$x+=s/\"//g; END {print "$x\n"}' foo.txt

İşte birkaç çözüm için bazı zamanlamalar (en yavaş - en hızlı); Buradaki şeyleri tek satırlarla sınırladım. 'foo.txt', 84922 eşleşme içeren bir satır ve bir uzun dize içeren bir dosyadır.

## sed solution by [maxschlepzig]
$ time sed 's/[^"]//g' foo.txt | awk '{ print length }'
84922
real    0m1.207s
user    0m1.192s
sys     0m0.008s

## using grep
$ time grep -o \" foo.txt | wc -w
84922
real    0m0.109s
user    0m0.100s
sys     0m0.012s

## using Perl
$ time Perl -ne '$x+=s/\"//g; END {print "$x\n"}' foo.txt
84922
real    0m0.034s
user    0m0.028s
sys     0m0.004s

## the winner: updated tr solution by [maxschlepzig]
$ time tr -d -c '\"\n' < foo.txt |  awk '{ print length }'
84922
real    0m0.016s
user    0m0.012s
sys     0m0.004s
10
josephwb

Başka bir awk çözümü:

awk '{print gsub(/"/, "")}'
9

Awk ve gsub ile bir başka olası uygulama:

awk '{ gsub("[^\"]", ""); print length }' input-file

gsub işlevi sed'in 's///g' İfadesine eşdeğerdir.

( Saymak için gsub("[^(]", "") kullanın.

8
enzotib

Bir C programı yazmaya karar verdim çünkü sıkıldım.

Muhtemelen giriş doğrulaması eklemelisiniz, ancak hepsi dışında.

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
        char c = argv[1][0];
        char * line = NULL;
        size_t len = 0;
        while (getline(&line, &len, stdin) != -1)
        {
                int count = 0;
                char * s = line;
                while (*s) if(*s++ == c) count++;
                printf("%d\n",count);
        }
        if(line) free(line);
}
6
user606723

Bir dize için en basit olanı tr ve wc ile olur (awk veya sed ile aşırıya kaçmanıza gerek yoktur) - ancak tr, karakter değil, bayt sayar -

echo $x | tr -d -c '"' | wc -m

nerede $x, değerlendirilecek dizeyi (dosya değil) içeren değişkendir.

6
Ocumo

İşte sadece STD C ve daha az bellek gerektiren başka bir C çözümü:

#include <stdio.h>

int main(int argc, char **argv)
{
  if (argc < 2 || !*argv[1]) {
    puts("Argument missing.");
    return 1;
  }
  char c = *argv[1], x = 0;
  size_t count = 0;
  while ((x = getc(stdin)) != EOF)
    if (x == '\n') {
      printf("%zd\n", count);
      count = 0;
    } else if (x == c)
      ++count;
  return 0;
}
4
maxschlepzig

Belki daha düz ileri, tamamen garip bir cevap split kullanmak olacaktır. Split bir dize alır ve onu bir diziye dönüştürür, dönüş değeri üretilen dizi öğesi sayısı + 1'dir.

Aşağıdaki kod her satırda "kaç kez yazdırılacağını gösterir.

awk ' {print (split($0,a,"\"")-1) }' file_to_parse

split hakkında daha fazla bilgi http://www.staff.science.uu.nl/~oostr102/docs/nawk/nawk_92.html

3
bleurp

Daha basit ve güçlü hale getirmek için grep ile regex kullanabiliriz.

Belirli bir karakteri saymak için.

$ grep -o '"' file.txt|wc -l

Boşluk karakterleri de dahil olmak üzere özel karakterleri saymak için.

$ grep -Po '[\W_]' file.txt|wc -l

Burada [\S\s] İle herhangi bir karakteri seçiyoruz ve -o Seçeneğiyle her bir eşleşmeyi (her karakter) ayrı bir satıra yazdırmak için grep yapıyoruz. Ve sonra her satırı saymak için wc -l Kullanın.

3
Kannan Mohan

Saf bir bash çözümü için (ancak bash'a özgüdür): $x Dizenizi içeren değişken ise:

x2="${x//[^\"]/}"
echo ${#x2}

${x// İşlemi " Dışındaki tüm karakterleri kaldırır, ${#x2} Bu geri kalan sürenin uzunluğunu hesaplar.

(Sorunları olan expr kullanarak orijinal öneri, yorumlara bakın:)

expr length "${x//[^\"]/}"
2
Marian

Bir dosyanın her satırındaki " Sayısını bulmak için basit bir Python komut dosyası:

#!/usr/bin/env python2
with open('file.txt') as f:
    for line in f:
        print line.count('"')

Burada yerleşik count türünün str yöntemini kullandık.

2
heemayl

a değerini sayılacak karakterle değiştirin. Çıktı, her satır için sayaçtır.

Perl -nE 'say y!a!!'
2
JJoao

Sunulan çözümlerin zaman karşılaştırması (cevap değil)

Cevapların etkinliği önemli değildir. Yine de, @ josephwb yaklaşımını takiben, sunulan tüm cevapları zamanlamaya çalıştım.

Ben Victor Hugo "Les Miserables" (büyük kitap!) Portekizce çeviri girdi olarak kullanın ve "a" oluşumları saymak. Sürümümde 5 cilt, birçok sayfa var ...

$ wc miseraveis.txt 
29331  304166 1852674 miseraveis.txt 

C cevapları gcc ile derlendi (optimizasyon yok).

Her cevap 3 kez çalıştırıldı ve en iyisini seçti.

Bu sayılara çok fazla güvenmeyin (makinem başka işler yapıyor vb.). Bu zamanları sizinle paylaşıyorum, çünkü beklenmedik sonuçlar elde ettim ve eminim biraz daha fazlasını bulacaksınız ...

  • 16 zamanlı çözeltiden 14'ü 1 saniyeden az sürdü; 9'u 0,1 saniyeden az, çoğu boru kullanıyor
  • 2 satır, bash satır satır kullanarak, yeni süreçler oluşturarak 30k satırları işledi, 10s/20s'de doğru çözümü hesaplayın.
  • grep -oP a, ağaç sürelerinden grep -o a (10; 11'e karşı 12)
  • C ve diğerleri arasındaki fark beklediğim kadar büyük değil. (7; 8 vs 2; 3)
  • (sonuçlar kabul edilir)

(rastgele bir sırayla sonuçlanır)

=========================1 maxschlepzig
$ time sed 's/[^a]//g' mis.txt | awk '{print length}' > a2
real    0m0.704s ; user 0m0.716s
=========================2 maxschlepzig
$ time tr -d -c 'a\n' < mis.txt | awk '{ print length; }' > a12
real    0m0.022s ; user 0m0.028s
=========================3 jjoao
$ time Perl -nE 'say y!a!!' mis.txt  > a1
real    0m0.032s ; user 0m0.028s
=========================4 Stéphane Gimenez
$ function countchar(){while read -r i; do echo "$i"|tr -dc "$1"|wc -c; done }

$ time countchar "a"  < mis.txt > a3
real    0m27.990s ; user    0m3.132s
=========================5 Loki Astari
$ time awk -Fa '{print NF-1}' mis.txt > a4
real    0m0.064s ; user 0m0.060s
Error : several -1
=========================6 enzotib
$ time awk '{ gsub("[^a]", ""); print length }' mis.txt > a5
real    0m0.781s ; user 0m0.780s
=========================7 user606723
#include <stdio.h> #include <string.h> // int main(int argc, char *argv[]) ...  if(line) free(line); }

$ time a.out a < mis.txt > a6
real    0m0.024s ; user 0m0.020s
=========================8 maxschlepzig
#include <stdio.h> // int main(int argc, char **argv){if (argc < 2 || !*argv[1]) { ...  return 0; }

$ time a.out a < mis.txt > a7
real    0m0.028s ; user 0m0.024s
=========================9 Stéphane Chazelas
$ time awk '{print gsub(/a/, "")}'< mis.txt > a8
real    0m0.053s ; user 0m0.048s
=========================10 josephwb count total
$ time grep -o a < mis.txt | wc -w > a9
real    0m0.131s ; user 0m0.148s
=========================11 Kannan Mohan count total
$ time grep -o 'a' mis.txt | wc -l > a15
real    0m0.128s ; user 0m0.124s
=========================12 Kannan Mohan count total
$ time grep -oP 'a' mis.txt | wc -l > a16
real    0m0.047s ; user 0m0.044s
=========================13 josephwb Count total
$ time Perl -ne '$x+=s/a//g; END {print "$x\n"}'< mis.txt > a10
real    0m0.051s ; user 0m0.048s
=========================14 heemayl
#!/usr/bin/env python2 // with open('mis.txt') as f: for line in f: print line.count('"')

$ time pyt > a11
real    0m0.052s ; user 0m0.052s
=========================15 enzotib
$ time  while IFS= read -r line; do   line="${line//[!a]/}"; echo "${#line}"; done < mis.txt  > a13
real    0m9.254s ; user 0m8.724s
=========================16 bleurp
$ time awk ' {print (split($0,a,"a")-1) }' mis.txt > a14
real    0m0.148s ; user 0m0.144s
Error several -1
2
JJoao
grep -n -o \" file | sort -n | uniq -c | cut -d : -f 1

burada grep tüm ağır kaldırmayı yapar: her satır numarasında bulunan her karakteri rapor eder. Gerisi sadece satır başına sayımı toplamak ve çıktıyı biçimlendirmektir.

Kaldır -n ve tüm dosya için sayı alın.

0.015 saniyenin altında bir 1.5 Meg metin dosyasını saymak hızlı görünüyor.
Ve karakterlerle (bayt değil) çalışır.

1
user79743

Bash için bir çözüm. Harici program çağrılmaz (kısa dizeler için daha hızlı).

Değer bir değişken içindeyse:

$ a='"Hello!"'

Bu, kaç tane " Bu içerir:

$ b="${a//[^\"]}"; echo "${#b}"
2
1
Isaac