Linuxta Bash Shell Script ile Kelime ve Harf Analizi


Merhabalar,

Bir kaç defa ihtiyacım olmuştu ve türkçe karakterleri ingilizce karakterlere çevirme, kelimelerin tekrarsız halleri vb. gibi konularda, Notepad++ kullanırdım. Ancak komut satırları ile bu gibi işlemler kolaylıkla yapılabilmekte. Özellikle çok büyük boyutlu dosyalarda, kelime işlemci programlar problem çıkarmaktadır (word, notepad, notepad++ gibi). İşte tam bu anlamda scriptler çok işimizi görmektedir. Bunun için, kendi analiz yöntemimi script ile hazırladım. Bu sayede, linux ve powershell komutlarının çalışma şekli için de iyi bir eğitim olacağına inanıyorum. Bundan dolayı da, scriptleri hazırlarken olabildiğince basit, gereksiz ayrıntılar olmadan, tek satırda istediğimiz sonucu bulmaya yönelik komut satırları hazırladım.

Öncelikle yapmak istediğim şeyi açıklayayım:

Büyük bir kitapta (roman, sözlük veya büyük bir metin) geçen tüm kelimelerin istatistik bilgilerini çıkarmak, en çok kullanılan kelimeler ve harfler nedir bunları bulmak. Ne işe yaracak derseniz, birden fazla sebebi bulunmaktadır.

Tabi doğru sonucu bulmak için, bazı düzeltmeler yapmak gerekiyor metinde.

Scriptimizi önce linux shell kullanarak hazırlayalım, yapacağımız şeyler sırasıyla:

1) Elimizde büyük bir metin dosyası var, ilk önce dosyamızı yedekleyelim.
2) Tırnak işaretinden sonra gelen harfleri silelim (Örneğin <Ankara’nın> kelimesinde <‘nın> ekini silmek gibi)
3) Tüm türkçe harfleri ingilizce harflerine dönüştürelim (ö -> o gibi)
4) Tüm boşlukları, virgülleri, noktaları >> satır başlarına dönüştürelim
5) Tüm harfleri küçültelim
6) Alfabedeki harfler haricinde tüm karakterleri kaldıralım
7) Boş satırları kaldıralım
8) Harflerine göre tüm kelimeleri sıralayalım

9) Tüm kelimeleri, tekrar sayısına göre analiz edelim
10) Tüm harfleri tekrar sayısına göre analiz edelim.

Bu işlemlerin tümünde, script açıklamalarını mümkün olduğunca yazacağım. Bu sayede, bash script yazımı için de iyi bir konu anlatımı olur. Ancak tam olarak anlaşılamayan komutlar için, https://explainshell.com sitesinden yardım alabilirsiniz. Burada shell komutları açıklamaları bazen işinize yarayacaktır.

Kelime analizini yapacağımız metin olarak, NUTUK kitabını seçtim. Yaklaşık 1.5Milyon karakter ve 165Bin kelime var. İyi bir analiz olur diye düşündüm. Sizler de, elinizdeki büyük bir metni kullanabilirsiniz.

 

1) Dosyamızı yedekliyoruz:

cp Nutuk.txt Analiz1.txt
#Nutuk.txt dosyasını Analiz1.txt dosyası olarak kopyalıyoruz.

 

2) Tırnak işaretinden sonra gelen harfleri silelim (Örneğin <Ankara’nın> kelimesinde <‘nın> ekini silmek gibi)

sed -i -r "s/[\'’‘]\w+//g" Analiz1.txt

#Burada sed komutu ile, tırnak işareti ve sonrasında gelen harf grubunu, hiçbirşeyle değiştiriyoruz:
-i : Dosyanın içerisinde işlem yapılması
-r : regex kullanacağımızı belirtmektedir.
s :Bu işleç, değiştirme yapmak için kullanılır. Kullanımı şu şekildedir: seds/ali/veli/” dosya.txt : ali kelimesini veli ile değiştirir.
[\’’‘] : Burada (ters slaş, backslash) işareti kaçış karakteri olarak adlandırılıyor. Bir sonraki karakterin, string olduğunu belirtmek için kullanılır (özel karakterler için de kullanıldığı alanlar vardır, aşağıda bazı örnekleri olacaktır). Bildiğimiz tek tırnak işaretinin kendisini bulmak için kaçış karakteri kullanmak zorunda kaldık. Sonrasındaki ve İşareti ise, özellikle word programı ile yazarken çıkan tek tırnak işaretidir. Yani iki tür tırnak işaretini de gördüğü zaman eşleşme gerçekleşecektir. Buradaki köşeli parantez, içerisinde yazan karakterlerle sınırlı bir eşleşme sağlar. Örneğin [a-z] ifadesi alfabenin küçük harflerini, [5-9]: 5 ile 9 arasını ifade eder. [Mg] ifadesi: Büyük M veya küçük g karakterleri demektir.
\w+ : Bu ifade Regex içinde bilinmesi gereken özel bir ifadedir. \w ifadesi, alfabedeki tüm harfler, rakamlar ve özel olarak _ (alttire) işaretini tanımlar. + karakteri, sonrasında aynı şekilde tekrar etmesi demektir. Yani, \w ifadesine uyan tüm karakterler bu ifade ile eşleşir. Kabaca; cümle içerisinde geçen kelimeleri bununla yakalarız (boşluk ve özel karakter görene kadar)
// : Bu iki kesme işareti arasına, değiştirmek istediğimiz harfi yazabilirdik. Hiç bir harf-simge koymadığımız için, eşleşen tüm ifadeleri hiç bir şeyle değiştirmiş olacağız, yani sileceğiz.
g : Bu ifade de, metin içerisinde birden fazla eşleşen varsa, ilk eşleşmeden sonra durmaması ve devam etmesi içindir. Burada şu ayrıntı önemli olabilir: Değiştirilen ifade, aradığımız ifadeye dönüşebilir. Bunlar tekrar tekrar eşleşmez. Şöyle ki: ahmemett kelimesinde “met” ifadesini silelim. Yeni kelime ahmet olacaktır. Yukarıda sed komutunu “g” işleci ile çalıştırdığımızda, “ahmemett” kelimesi, “ahmet” olacaktır. “ah” olmayacaktır.
Bu komutu şu şekilde de kullanabiliriz: sed -i -r ‘s/[\x27’‘]\w+//g’ Analiz1.txt  # Burada, \x27 : tek tırnak işareti demektir.

BONUS1: Bu yazımda, bol bol sed komutunu kullanacağız. Hemen tüm işlemlerimizde, regex’den yararlanacağız. Eğer yazdığınız regex’in dosyanızda nelerle match ettiğini görmek isterseniz:
grep -o ‘YAZDIĞINIZ_REGEX’ dosyanız.txt komutu ile kontrol edebilirsiniz. Örneğin 2 numaralı komutumuzda kullandığımız regexi, şu şekilde kontrol edebilirsiniz: grep -o “[\’’‘]\w+” dosyanız.txt

Ayrıca, regex101.com sitesini de şiddetle tavsiye ederim. REGEX kullanımı önemlidir, bir çok platformda işinize yarayacaktır.

BONUS2 : Tek tırnak ve çift tırnak kullanımı linuxta çok önemlidir. Bu konuyla ilgili makaleleri mutlaka kontrol edin. Kabaca şu şekilde söyleyebiliriz: Tek tırnak ile açtığınız komutların içerisinde çift tırnaklı ifade kullanabilirsiniz. Veya bunun tersini yapmalısınız. Örneğin yukarıdaki komutta: grep -o “[\’’‘]\w+” dosyanız.txt -> Çift tırnak içerisinde, tek tırnaklı bir karakter kullanabildik. Eğer içeride çift tırnaklı bir ifade yazacak olsaydık, bu komut sorun çıkarabilirdi.

3) Tüm türkçe harfleri ingilizce harflerine dönüştürelim (ö -> o gibi)

#Dosyamızı yeniden kopyalıyoruz 
cp Analiz1.txt Analiz2.txt
#Türkçe harfleri ve karşılığı olacak ingilizce harfleri tanımlıyoruz ki, döngü içerisinde bu harfleri değiştirelim
harfler=$(cat <<EOF
ı,i
ğ,g
ü,u
ş,s
ö,o
ç,c
I,i
İ,i
Ç,c
Ş,s
Ü,u
Ğ,g
EOF
)

while IFS=, read turkce eng
do
    sed -i 's/'$turkce'/'$eng'/g' Analiz2.txt
done <<< $harfler


harfler : bununla bir veri seti hazırlıyoruz. EOF: End Of File nin kısaltılmış halidir.

while IFS=, read turkce eng : Döngüyü oluşturuyoruz ve son satırdaki $harfler veri setini satır satır okuyoruz. Ancak her satırı, virgülle ayırıyoruz. Virgülle ayırdığımız ilk değeri “turkce”, ikinci değeri de “eng” değişkeni olarak atamasını yapıyoruz.

sed -i ‘s/’$turkce’/’$eng’/g’ Analiz2.txt : Analiz2.txt içerisinde her bir turkce karakteri, eng karakteri ile değiştiriyoruz.

4) Tüm boşlukları, virgülleri, nokta, noktalı virgül ve iki nokta üstüste karakterlerini >> satır başlarına dönüştürelim. Buradaki amacımız, tüm kelimeleri ayırmak ve metnimizi analiz edebilecek hale getirmektir.

cp Analiz2.txt Analiz3.txt
sed -i -r 's/[ ,\.:;]/\n/g' Analiz3.txt

[ ,\.:;] : Boşluk,nokta,iki nokta üstüste ve noktalı virgül karakterleri demektir. Noktanın başına yine kaçış işareti koyduk (backslash). Regexte nokta işareti, herhangi bir karakter anlamına gelir. Ama başına backslash işareti konulursa, sadece nokta işareti olduğu anlamı kazanır. \n : Yeni satır demektir. Sadece n olsaydı, n karakteri anlamına gelirdi.

5) Tüm harfleri küçültelim

<Analiz3.txt tr '[:upper:]' '[:lower:]' >Analiz4.txt

tr işlevi ile büyük harfleri küçültüyor ve Analiz4.txt dosyasına yazıyoruz.

Burayı cat Analiz3.txt | tr ‘[:upper:]’ ‘[:lower:]’ >Analiz4.txt şeklinde de kullanabilirdik. Bu yöntemi de görmeniz açısından eklemek istedim. Akılda kalıcı olabiliyor bazen.

6) Alfabedeki harfler haricinde tüm karakterleri kaldıralım

cp Analiz4.txt Analiz5.txt
sed -i -r 's/[^a-z]//g' Analiz5.txt

[^a-z] : Alfabedeki a ile z harfi haricinde olan tüm karakterler demektir. Regexde ^ işareti normal kullanımda satır başını ifade eder. Ama köşeli parantez içeresinde kullanılırsa, hariç tutmak anlamına gelir. Biz tüm harfleri küçülttüğümüz için, A-Z ye ihtiyacımız kalmadı. Rakamlara, özel karakterlere de ihtiyacımız kalmadı. Bu komutla, diğer tüm karakterleri siliyoruz.

7) Boş satırları kaldıralım

cp Analiz5.txt Analiz6.txt
sed -i '/^$/d' Analiz6.txt

^$ : ^ karakteri satır başını, $ karakteri satır sonunu ifade eder. Birlikte kullanınca, boş satır demektir.

 

8) Harflerine göre tüm kelimeleri sıralayalım

sort Analiz6.txt -o Analiz7.txt

Sıraladığımız metni Analiz7.txt dosyasına yazıyoruz.

 

9) Tüm kelimeleri, tekrar sayısına göre analiz edelim

sort Analiz7.txt | uniq -c | sort -nr -o Kelime_Sayilari.txt

1) Sort ile sıralıyoruz,
2) uniq ile kelimeleri tekrarsız hale getiriyoruz, -c ile birlikte kullandığımız için, tekrar sayısını da görüyoruz,
3) tekrar sort ve -nr ile büyükten küçüğe sıralıyoruz ve Kelime_Sayilari.txt dosyasına çıkarıyoruz

 

10) Tüm harfleri tekrar sayısına göre analiz edelim.

uniq Analiz7.txt > Analiz7_Tekrarsiz.txt
for harf in {a..z}
do
sayi=$(tr -cd "$harf" < Analiz7_Tekrarsiz.txt | wc -c)
echo $sayi,$harf >> Harf_Sayilari.txt
done

sort -nr Harf_Sayilari.txt -o Harf_Sayilari.txt

1) Uniq ile kelimelerin tekrarsız halini Analiz7_Tekrarsiz.txt dosyasına yazıyoruz. Çünkü, en çok kullanılan harfi bulmak için, kelimelerin tekrarsız hali daha iyi olacaktır. Aksi halde, tekrar eden kelimelerin harf sayıları daha çok çıkacaktır.
2) for döngüsü için alfabenin a’dan z harfine kadarını {a..z} işaret ediyoruz ki, tüm alfabeyi tek tek sayabilelim.
3) Her bir harf için, tr komutu ile dosyadaki harfleri sayıyoruz ve sayi değişkenine atıyoruz. Ancak burada harf sayma yöntemimiz biraz farklı. Aslında yaptığımız şey, örneğin m harfi için: m harfi haricindeki tüm karakterleri silmek (tr -cd “$harf” < Analiz7_Tekrarsiz.txt). Geriye sadece m harfi kalıyor. wc -c ile de bu m harfini sayıyoruz.
4) echo ile  Saydığımız harf sayısını ve harfi, Harf_Sayilari.txt dosyasına yazdırıyoruz.
5) Son olarak, yine sort ile büyükten küçüğe sıralıyoruz.

Harf sayısı için farklı metotlar da bulunabilir. Eğer böyle bir metodunuz varsa, paylaşırsanız sevinirim. Buradaki amacımız, bakış açısıyla bir çok farklı işlem yapılabileceğini göstermektir. Bir yandan da bash script yazım için bir eğitimdir.

Son çıktılarımız, Kelime_Sayilari.txt ve Harf_Sayilari.txt dosyalarıdır.

 


 

Tüm bu işlemlerin tek dosya hali:

Bash:

#1) Elimizde büyük bir metin dosyası var, ilk önce dosyamızı yedekleyelim.
cp Nutuk.txt Analiz1.txt
#2) Tırnak işaretinden sonra gelen harfleri silelim (Örneğin &lt;Ankara'nın&gt; kelimesinde &lt;'nın&gt; ekini silmek gibi)
sed -i -r "s/[\'’‘]\w+//g" Analiz1.txt
#3) Tüm türkçe harfleri ingilizce harflerine dönüştürelim (ö -&gt; o gibi)

cp Analiz1.txt Analiz2.txt
harfler=$(cat <<EOF
ı,i
ğ,g
ü,u
ş,s
ö,o
ç,c
I,i
İ,i
Ç,c
Ş,s
Ü,u
Ğ,g
EOF
)

while IFS=, read turkce eng; do
    sed -i 's/'$turkce'/'$eng'/g' Analiz2.txt
done <<< $harfler

#4) Tüm boşlukları, virgülleri, nokta, noktalı virgül ve iki nokta üstüste karakterlerini >> satır başlarına dönüştürelim
cp Analiz2.txt Analiz3.txt
sed -i -r 's/[ ,\.:;]/\n/g' Analiz3.txt

#5) Tüm harfleri küçültelim
<Analiz3.txt tr '[:upper:]' '[:lower:]' >Analiz4.txt

#6) Alfabedeki harfler haricinde tüm karakterleri kaldıralım
cp Analiz4.txt Analiz5.txt
sed -i -r 's/[^a-z]//g' Analiz5.txt

#7) Boş satırları kaldıralım
cp Analiz5.txt Analiz6.txt
sed -i '/^$/d' Analiz6.txt


#8) Harflerine göre tüm kelimeleri sıralayalım
sort Analiz6.txt -o Analiz7.txt

#9) Tüm kelimeleri, tekrar sayısına göre analiz edelim
sort Analiz7.txt | uniq -c | sort -nr -o Kelime_Sayilari.txt

#10) Tüm harfleri tekrar sayısına göre analiz edelim.
uniq Analiz7.txt > Analiz7_Tekrarsiz.txt

for harf in {a..z}
do
sayi=$(tr -cd "$harf" < Analiz7_Tekrarsiz.txt | wc -c)
echo $sayi,$harf >> Harf_Sayilari.txt
done

sort -nr Harf_Sayilari.txt -o Harf_Sayilari.txt

 

Aynı işlemlerin PowerShell ile yapımına da aşağıdaki makalemizle göz atabilirsiniz:

PowerShell ile Kelime ve Harf Analizi

, , , , ,

  1. Henüz hiç yorum yok.
(yayınlanmayacak)