Saya bertanya-tanya bagaimana cara menghitung jumlah karakter tertentu di setiap baris dengan beberapa utilitas pemrosesan teks?
Misalnya, untuk menghitung "
di setiap baris teks berikut
"hello!"
Thank you!
Baris pertama memiliki dua, dan baris kedua memiliki 0.
Contoh lain adalah menghitung (
di setiap baris.
Jawaban:
Anda dapat melakukannya dengan
sed
danawk
:Di mana
dat
teks contoh Anda, sed menghapus (untuk setiap baris) semua non-"
karakter danawk
mencetak untuk setiap baris ukurannya (yaitulength
setara denganlength($0)
, di mana$0
menunjukkan baris saat ini).Untuk karakter lain, Anda hanya perlu mengubah ekspresi sed. Misalnya untuk
(
ke:Pembaruan:
sed
agak berlebihan untuk tugas -tr
cukup. Solusi yang setara dengantr
adalah:Arti yang
tr
menghapus semua karakter yang bukan (-c
berarti pelengkap) dalam set karakter"\n
.sumber
tr
&wc
.ß
(utf hex: c3 9f) (bukan"
) berfungsi seperti yang diharapkan, yaitutr
,sed
danawk
lakukan pelengkap / penggantian / penghitungan tanpa masalah - pada sistem Ubuntu 10,04.tr
, termasuk GNU tr dan Unix tr klasik, beroperasi pada karakter byte tunggal dan tidak sesuai dengan Unicode .. Dikutip dari Wikipedia tr (Unix) .. Coba cuplikan ini:echo "aā⧾c" | tr "ā⧾" b
... di Ubuntu 10.04 ...ß
adalah satu byte Diperpanjang char Latin dan ditangani olehtr
... Masalah sebenarnya di sini bukan yangtr
tidak menangani Unicode (karena SEMUA karakter adalah Unicode), itu benar-benartr
hanya menangani satu-byte pada suatu waktu ..Saya hanya akan menggunakan awk
Di sini kita mengatur pemisah bidang (dengan bendera -F) menjadi karakter,
"
maka yang kita lakukan hanyalah mencetak jumlah bidangNF
- 1. Jumlah kemunculan karakter target akan lebih sedikit daripada jumlah bidang yang dipisahkan.Untuk karakter lucu yang ditafsirkan oleh shell, Anda hanya perlu memastikan bahwa Anda dapat menghindarinya jika tidak, baris perintah akan mencoba dan mengartikannya. Jadi untuk keduanya
"
dan)
Anda harus lolos dari pemisah bidang (dengan\
).sumber
'
). Juga, ia memiliki perilaku aneh dengan garis kosong."
jadi saya merasa berkewajiban untuk membuat kode bekerja dengannya. Itu tergantung pada cangkang apa yang Anda gunakan saat karakter harus diloloskan tetapi bash / tcsh harus melarikan diri "-F'"'
.awk -F"$1" '{print NF==0?NF:NF-1}' filename
Menggunakan
tr
ardwc
:Pemakaian:
sumber
tr
tidak menangani karakter yang menggunakan lebih dari satu byte .. lihat Wikipedia tr (Unix) .. yaitu.tr
tidak sesuai dengan Unicode.$IFS
, jika tidakread
akan memangkasnya dari awal dan akhir.echo
data yang sewenang-wenangtr
implementasi mendukung karakter multibyte, tetapiwc -c
menghitung byte, bukan karakter (memerlukanwc -m
karakter).Namun implementasi lain yang tidak bergantung pada program eksternal, di
bash
,zsh
,yash
dan beberapa implementasi / versiksh
:Gunakan
line="${line//[!(]}"
untuk menghitung(
.sumber
eof=false; IFS=; until $eof; do read -r || eof=true; echo "$REPLY"; done
/
yang tidak diperlukan di bash. Apakah ini persyaratan ksh?/
dibutuhkan di versi ksh yang lebih lama, dan IIRC di versi bash yang lebih lama juga.Jawaban menggunakan
awk
gagal jika jumlah kecocokan terlalu besar (yang terjadi pada situasi saya). Untuk jawaban dari loki-astari , kesalahan berikut dilaporkan:Untuk jawaban dari enzotib (dan setara dengan manatwork ), kesalahan segmentasi terjadi:
The
sed
solusi dengan maxschlepzig bekerja dengan benar, tetapi lambat (timing bawah).Beberapa solusi belum disarankan di sini. Pertama, menggunakan
grep
:Dan menggunakan
perl
:Berikut adalah beberapa pengaturan waktu untuk beberapa solusi (dipesan paling lambat hingga tercepat); Saya membatasi hal-hal menjadi satu-baris di sini. 'foo.txt' adalah file dengan satu baris dan satu string panjang yang berisi 84922 kecocokan.
sumber
awk
Solusi lain :sumber
Kemungkinan implementasi lain dengan awk dan gsub:
Fungsinya
gsub
setara dengan sed's///g'
.Gunakan
gsub("[^(]", "")
untuk menghitung(
.sumber
awk '{print gsub(/"/,"")}' input-file
akan cukup, karena "Untuk setiap substring yang cocok dengan ekspresi reguler r dalam string t, gantikan string s, dan kembalikan jumlah penggantian." (man awk)Saya memutuskan untuk menulis program C karena saya bosan.
Anda mungkin harus menambahkan validasi input, tetapi selain itu sudah diatur.
sumber
free(line)
mengabaikannya karena keluar dari program secara implisit membebaskan semua memori yang dialokasikan - maka ada tempat untukreturn 0;
...;). Bahkan dalam contoh itu bukan gaya yang baik untuk membiarkan kode kembali tidak terdefinisi. Btw,getline
adalah ekstensi GNU - kalau-kalau ada yang bertanya-tanya.f
, yang dipanggil beberapa kali dari kode lain, maka Anda harus memanggilfree
setelah panggilan terakhirgetline
pada akhir fungsi inif
.Untuk string, yang paling sederhana adalah dengan
tr
danwc
(tidak perlu berlebihan denganawk
ataused
) - tetapi perhatikan komentar di atas tentangtr
, menghitung byte, bukan karakter -di mana
$x
variabel yang berisi string (bukan file) untuk dievaluasi.sumber
Berikut ini adalah solusi C lain yang hanya membutuhkan STD C dan lebih sedikit memori:
sumber
\n
bukanlah garis nyata. Ini adalah perilaku yang sama dengan jawaban sed / awk (tr / awk) saya yang lain.Kita dapat menggunakannya
grep
denganregex
membuatnya lebih sederhana dan kuat.Untuk menghitung karakter tertentu.
Untuk menghitung karakter khusus termasuk karakter spasi.
Di sini kita memilih karakter apa saja dengan
[\S\s]
dan dengan-o
opsi yang kita buatgrep
untuk mencetak setiap kecocokan (yaitu, masing-masing karakter) dalam baris terpisah. Dan kemudian gunakanwc -l
untuk menghitung setiap baris.sumber
"
di setiap baris; dan untuk karakter lainnya. lihat pertanyaannya dan juga jawaban yang diterima.Mungkin jawaban yang lebih jujur, murni awk adalah menggunakan split. Split mengambil string dan mengubahnya menjadi array, nilai kembalinya adalah jumlah item array yang dihasilkan +1.
Kode berikut akan mencetak berapa kali "muncul di setiap baris.
info lebih lanjut tentang split http://www.staff.science.uu.nl/~oostr102/docs/nawk/nawk_92.html
sumber
Berikut ini adalah skrip Python sederhana untuk menemukan hitungan
"
di setiap baris file:Di sini kita telah menggunakan
count
metodestr
tipe bawaan.sumber
Untuk solusi bash murni (khusus untuk bash): If
$x
adalah variabel yang berisi string Anda:Benda
${x//
menghapus semua karakter kecuali"
,${#x2}
menghitung panjang istirahat ini.(Saran asli menggunakan
expr
yang memiliki masalah, lihat komentar:)sumber
expr
dan menghitung byte, bukan karakter. Dengan yang lainexpr
:expr "x${x...}" : "x.*" - 1
Ganti
a
dengan char yang akan dihitung. Output adalah penghitung untuk setiap baris.sumber
Perbandingan waktu dari solusi yang disajikan (bukan jawaban)
Efisiensi jawaban tidak penting. Namun demikian, mengikuti pendekatan @josephwb, saya mencoba mengatur waktu semua jawaban yang disajikan.
Saya menggunakan sebagai input terjemahan bahasa Portugis dari Victor Hugo "Les Miserables" (buku hebat!) Dan menghitung kemunculan "a". Edisi saya memiliki 5 volume, banyak halaman ...
Jawaban C dikompilasi dengan gcc, (tanpa optimisasi).
Setiap jawaban dijalankan 3 kali dan pilih yang terbaik.
Jangan terlalu mempercayai angka-angka ini (mesin saya melakukan tugas-tugas lain, dll, dll.). Saya berbagi waktu ini dengan Anda, karena saya mendapat beberapa hasil yang tidak terduga dan saya yakin Anda akan menemukan lagi ...
grep -oP a
adalah waktu pohon lebih cepatgrep -o a
(10; 11 vs 12)(hasil dalam urutan acak)
sumber
di mana grep melakukan semua tugas berat: melaporkan setiap karakter yang ditemukan di setiap nomor baris. Sisanya hanya untuk menjumlahkan jumlah per baris, dan memformat output.
Hapus
-n
dan hitung untuk seluruh file.Menghitung file teks 1,5Meg di bawah 0,015 detik tampaknya cepat.
Dan berfungsi dengan karakter (bukan byte).
sumber
Solusi untuk bash. Tidak ada program eksternal yang disebut (lebih cepat untuk string pendek).
Jika nilainya dalam variabel:
Ini akan mencetak berapa banyak di
"
dalamnya:sumber