Bagaimana cara menghitung jumlah kemunculan kata dalam file teks dengan baris perintah?

43

Saya memiliki file JSON besar yang ada di satu baris, dan saya ingin menggunakan baris perintah untuk dapat menghitung jumlah kemunculan kata dalam file. Bagaimana saya bisa melakukan itu?

mitos
sumber
Tidak jelas apakah kata tersebut harus dicocokkan dengan kunci dan nilai data JSON, yaitu apakah { "key": "the key" }harus menghitung string keysekali atau dua kali.
Kusalananda

Jawaban:

46
$ tr ' ' '\n' < FILE | grep WORD | wc -l

Di mana trmenggantikan spasi dengan baris baru, grepfilter semua garis yang dihasilkan cocok dengan KATA dan wcmenghitung yang tersisa.

Satu bahkan dapat menyimpan wcbagian menggunakan -copsi grep:

$ tr ' ' '\n' < FILE | grep -c WORD

The -copsi didefinisikan oleh POSIX.

Jika tidak dijamin ada spasi di antara kata-kata, Anda harus menggunakan beberapa karakter lain (sebagai pembatas) untuk menggantikan. Sebagai contoh tradalah bagian alternatif

tr '"' '\n'

atau

tr "'" '\n'

jika Anda ingin mengganti tanda kutip ganda atau tunggal. Tentu saja, Anda juga dapat menggunakan truntuk mengganti beberapa karakter sekaligus (pikirkan berbagai jenis spasi putih dan tanda baca).

Jika Anda perlu menghitung WORD tetapi bukan awalanWORD, WORDsuffix, atau prefixWORDsuffix, Anda dapat melampirkan pola WORD di marker begin / end-of-line:

grep -c '^WORD$'

Yang setara dengan penanda awal-akhir kata, dalam konteks kami:

grep -c '\<WORD\>'
maxschlepzig
sumber
bagaimana jika tidak ada spasi, yaitu nama bidang dikelilingi oleh tanda kutip? misalnya "bidang"
mythz
@mythz: Lalu Anda mengganti tanda kutip dengan baris baru dengan tr. Saya akan memperbarui jawabannya.
maxschlepzig
1
Jawaban ini salah dalam banyak hal. Itu tidak jelas: Anda harus menjelaskan cara membuat trperintah yang melakukan pekerjaan alih-alih menyarankan contoh yang tidak akan pernah berhasil dalam semua situasi. Itu juga akan cocok dengan kata-kata yang mengandung kata yang Anda cari. The grep -o '\<WORD\>' | wc -lsolusi adalah jauh lebih unggul.
sam hocevar
1
@ Sam, pertanyaannya agak terbuka, jika kata yang dicari harus dicari seperti 'WORD' atau '\ <WORD \>' - Anda dapat membacanya dengan dua cara. Bahkan jika Anda membacanya dengan cara 2 dan hanya dengan cara 2, maka jawaban saya hanya akan salah dalam 1 cara. ;) Dan solusi 'grep -o' hanya unggul, jika mendukung opsi -o - yang tidak ditentukan oleh POSIX ... Yah, saya tidak berpikir bahwa penggunaan tr adalah sesuatu yang eksotis untuk menyebutnya kabur ...
maxschlepzig
1
@ Kusalananda, yah, itu masih terjadi. Tetapi jika Anda tidak ingin menghitung pertandingan substring seperti itu, silakan baca paragraf terakhir dari jawaban saya dan komentar saya sebelumnya di sini.
maxschlepzig
24

Dengan GNU grep, ini berfungsi: grep -o '\<WORD\>' | wc -l

-o mencetak setiap bagian yang cocok dari setiap baris pada baris yang terpisah.

\<menegaskan awal kata dan \>menegaskan akhir kata (mirip dengan Perl \b), jadi ini memastikan bahwa Anda tidak mencocokkan string di tengah kata.

Sebagai contoh,

$ python -c 'impor ini' | grep '\ <one \>'
Seharusnya ada satu - dan lebih disukai hanya satu - cara yang jelas untuk melakukannya.
Namespaces adalah salah satu ide bagus - mari kita lakukan lebih dari itu!
$ python -c 'impor ini' | grep -o '\ <one \>'
 one 
one 
one 
$ python -c 'impor ini' | grep -o '\ <one \>' | wc -l
3
singkat
sumber
1
Atau hanyagrep -wo WORD | wc -l
Stéphane Chazelas
10

Sayangnya ini tidak bekerja dengan GNU coreutils.

grep -o -c WORD file

Jika itu berfungsi pada platform Anda, itu adalah solusi yang elegan dan cukup intuitif; tetapi orang-orang GNU masih berpikir.

tripleee
sumber
2
Sayangnya
1
Sayang sekali ini akan menjadi yang paling elegan
MasterScrat
Ini berhasil untuk saya!
ThisaruG
Ini salah. Ini menghitung jumlah garis dengan pola KATA. OP menginginkan jumlah total kejadian.
Pierre B
@PierreB Itu sebabnya saya katakan GNU grepmemiliki bug di sini. Tidak jelas dari POSIX apa semantik menggabungkan -cdan -oharus jadi ini saat ini tidak portabel. Terima kasih atas komentarnya; Saya telah memperbarui jawaban ini.
tripleee
7
sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl 

Perintah ini membuat yang berikut:

  1. Gantikan semua karakter non alfanumerik dengan spasi kosong.
  2. Semua jeda baris juga dikonversi menjadi spasi.
  3. Mengurangi semua ruang kosong menjadi satu ruang kosong
  4. Semua spasi sekarang dikonversi ke jeda baris. Setiap kata dalam satu baris.
  5. Menerjemahkan semua kata ke huruf kecil untuk menghindari 'Halo' dan 'Halo' menjadi kata-kata yang berbeda
  6. Urutkan de teks
  7. Menghitung dan menghapus garis yang sama
  8. Urutkan terbalik untuk menghitung kata yang paling sering
  9. Tambahkan nomor baris ke setiap kata untuk mengetahui posisi kata secara keseluruhan

Misalnya jika saya ingin menganalisis pesan Linus Torvald pertama:

Dari: [email protected] (Linus Benedict Torvalds) Newsgroup: comp.os.minix Subjek: Apa yang paling ingin Anda lihat dalam minix? Ringkasan: jajak pendapat kecil untuk sistem operasi baru saya Message-ID: <[email protected]> Tanggal: 25 Agustus 91 20:57:08 GMT Organisasi: University of Helsinki

Halo semua di luar sana menggunakan minix -

Saya sedang melakukan sistem operasi (gratis) (hanya hobi, tidak akan besar dan profesional seperti gnu) untuk 386 (486) klon AT. Ini telah dibuat sejak bulan April, dan mulai bersiap-siap. Saya ingin umpan balik tentang hal-hal yang orang suka / tidak suka dalam minix, karena OS saya agak mirip (tata letak fisik yang sama dari sistem file (karena alasan praktis) antara lain).

Saat ini saya telah porting bash (1,08) dan gcc (1,40), dan hal-hal tampaknya berhasil. Ini menyiratkan bahwa saya akan mendapatkan sesuatu yang praktis dalam beberapa bulan, dan saya ingin tahu fitur apa yang diinginkan kebanyakan orang. Ada saran yang diterima, tetapi saya tidak akan berjanji akan menerapkannya 🙂

Linus ([email protected])

PS. Ya - ini gratis dari kode minix apa pun, dan memiliki fs multi-utas. Ini TIDAK protable (menggunakan 386 task switching dll), dan mungkin tidak akan pernah mendukung apa pun selain AT-hardisk, karena hanya itu yang saya miliki :-(.

Saya membuat file bernama linus.txt , saya tempel kontennya dan kemudian saya tulis di konsol:

sed -e 's/[^[:alpha:]]/ /g' linus.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl 

Hasil akhirnya adalah:

 1        7 i
 2        5 to
 3        5 like
 4        5 it
 5        5 and
 6        4 minix
 7        4 a
 8        3 torvalds
 9        3 of
10        3 helsinki
11        3 fi
12        3 any
13        2 would
14        2 won
15        2 what
16        ...

Jika Anda ingin memvisualisasikan hanya 20 kata pertama:

sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl | head -n 20

Penting untuk dicatat bahwa perintah tr 'AZ' 'a-z' tidak suport UTF-8 belum , sehingga dalam bahasa asing sekian menyala kata akan diterjemahkan sebagai Apres.

Jika Anda hanya ingin mencari kemunculan satu kata, Anda dapat menambahkan grep di bagian akhir:

sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl | grep "\sword_to_search_for$"

Dalam skrip yang disebut search_freq :

#!/bin/bash
sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl | grep "\s$1$"

Script harus disebut:

 search_freq word_to_search_for
Roger Borrell
sumber
sed: -e expression #2, char 7: unterminated 'perintah`, ini juga menghitung semua kata, kan? Tapi OP hanya bertanya satu. Juga sedikit penjelasan akan menyenangkan.
phk
Maaf saya punya kesalahan. Saya telah membuat ulang perintah dan mengomentari jawabannya. Menurut pendapat saya, dari pertanyaan itu, tidak mungkin untuk mengetahui apakah dia ingin mendapatkan mata uang hanya dari satu kata atau frekuensi kejadian. Tetapi jika Anda ingin mendapatkan hanya satu kata, Anda dapat menambahkan grep di akhir.
Roger Borrell
3

Bergantung pada apakah Anda ingin mencocokkan kata dalam kunci atau dalam nilai data JSON, Anda cenderung ingin mengekstrak hanya kunci atau hanya nilai dari data. Kalau tidak, Anda dapat menghitung beberapa kata terlalu banyak jika muncul sebagai kunci dan nilai.

Untuk mengekstrak semua kunci:

jq -r '..|objects|keys[]' <file.json

Ini secara rekursif menguji apakah benda saat ini adalah objek, dan jika ya, ia mengekstrak kunci. Output akan berupa daftar kunci, satu per baris.

Untuk mengekstrak semua nilai:

jq -r '..|scalars' <file.json

Ini bekerja dengan cara yang serupa, tetapi memiliki langkah lebih sedikit.

Anda kemudian dapat menyalurkan output di atas melalui grep -c 'PATTERN'(untuk mencocokkan beberapa pola terhadap kunci atau nilai), atau grep -c -w -F 'WORD'(untuk mencocokkan kata dalam kunci atau nilai), atau grep -c -x -F 'WORD'(untuk mencocokkan kunci atau nilai lengkap), atau serupa, dengan lakukan penghitungan Anda.

Kusalananda
sumber
0

Saya memiliki json dengan sesuatu seperti ini: "number":"OK","number":OK"diulang beberapa kali dalam satu baris.

Penghitung "OK" saya yang sederhana:

sed "s|,|\n|g" response | grep -c OK

khazad-dum_miner
sumber
-1

i Telah menggunakan perintah awk di bawah ini untuk menemukan jumlah kemunculan

contoh file

file cat1

praveen ajay 
praveen
ajay monkey praveen
praveen boy praveen

perintah:

awk '{print gsub("praveen",$0)}' file1 | awk 'BEGIN{sum=0}{sum=sum+$1}END{print sum}'

keluaran

awk '{print gsub("praveen",$0)}' file1 | awk 'BEGIN{sum=0}{sum=sum+$1}END{print sum}'

5
Praveen Kumar BS
sumber
Atau adil awk '{sum+=gsub("praveen","")} END {print sum+0}'.
G-Man Mengatakan 'Reinstate Monica'
Beri tahu saya mengapa harus memilih jawaban saya
Praveen Kumar BS