(This content is also available in English)
Bu proje, sözlük veri tabanı gerektirmeyen, algoritmik bir heceleme yönteminin anlatımı ve uygulamasıdır.1
Demo için güncel bir Chrome, Edge, Firefox, vs sürümü kullanın.
Kendi girdiğiniz metinin hecelenişini görmek içindir. Bir sözcük veya kısa metin girip
Hecele
ye tıklayın. Tireleri silmek içinGeri al
ı tıklayın.
Bulduğunuz hataları alper.goplay@gmail.com adresine bildirin, veya Issues altında bir kayıt açın.
Basit ve yalın bir morfolojik yapısı olan Türkçede heceleme (hyphenation) Hint-Avrupa dillerindekinden farklıdır. Bitişken (agglutinative) bir dil olan Türkçede teorik olarak sözcük uzunluğunun bir üst sınırının olmaması, sözlük veri tabanı kullanımını (dictionary lookup) anlamsız kılar. O dillere göre tasarlanmış yazılım ve/veya kütüphanelere Türkçeyi eklemeye çalışmak yerine özgün ve rasyonel bir yaklaşım mümkündür. Türkçe heceleme deterministiktir, sade ve açık kurallar ile formüle edilebilir.
Türkçe üzerine birinci bulgu:
Türkçe sözcükteki bir hecenin yeri, kendinden önce gelen hecelerden bağımsızdır.
Bu çok iddialı gibi görünen bulguyu açıklayan bir örnek verelim:
sözcük | hecelenişi |
---|---|
arkadaşlarından |
ar-ka-daş-la-rın-dan |
Şimdi bu sözcüğün sadece ilk hecesini bulalım, sonra o heceyi sözcükten ayıralım:
ilk hece | kalanı |
---|---|
ar-kadaşlarından |
kadaşlarından |
Geriye kalan kadaşlarından anlamlı bir Türkçe sözcük değil, ancak hecelenmesine engel bir durum yok. İlkokul 1. sınıf bilgimizi kullanarak bu sözcük parçasının ilk hecesini bulalım, sonra gene bu heceyi ayıralım:
ilk hece | kalanı |
---|---|
ka-daşlarından |
daşlarından |
Görüldüğü üzere ka- hecesini, öncesinde ar- olup olmadığını hesaba katmadan doğru olarak bulabiliyoruz. İşte bir hece yerinin, önceki hecelerden bağımsızlığı ilkesi budur.
Sözcük parçasının sonuna ulaşana kadar işleme devam edelim:
ilk hece | kalanı |
---|---|
daş-larından |
larından |
la-rından |
rından |
rın-dan |
dan |
dan |
- |
Bu aşamada Türkçe üzerine ikinci bir bulguyu belirtelim:
Türkçede henüz bilinmeyen, icat edilmemiş sözcüklerin bile nasıl heceleneceği bellidir.
Çözümün algoritmik çatısı şöyledir: Sözcükte ilk heceyi bul, bunu ayır, kalanı yeni bir sözcükmüş gibi ele al, ilk hecesini bul, bunu ayır, kalanı yeni bir sözcükmüş gibi... ta ki sözcük bitene kadar. Bu tipik bir özyinelemeli (recursive) algoritmadır. Bu aşamada problemi “bir sözcüğün (veya sözcük parçasının) ilk hecesinin bulunması”na indirgemiş olduk. Sonraki bölümde bunu ele alacağız.
Bu bölümde bir sözcük (veya sözcük parçasının) ilk hecesini bulan kurallar belirtilmektedir. Kurallara sırayla bakılacak ve uyan ilk kural heceyi bulmuş kabul edilecek, sonraki kurallara bakılmayacaktır. Her kuralda sözel anlatımı takiben örnekler, simgesel gösterim ve heceyi saptayan bir RegEx örüntü (pattern) verilmiştir.2 Sözel anlatımda geçen “sözcük” terimi “sözcük veya sözcük parçası” anlamındadır. Simgesel gösterimde N ünlü, z ünsüzü temsil eder. Kolaylık sağlaması için sözcükte noktalama imleri ve rakamlar olmadığı varsayılmıştır.
-
Sözcük 3 harften kısa ise ilk hece sözcüğün tamamıdır.
ev
şu
il
at- -
-
Sözcük ünlü-ünsüz-ünlü olarak başlıyorsa ilk hece 1 harftir.
ö-de-me
i-liş-kin
e-mir
a-raNzN :1 /^[aeiouöüıİ][bcçdfgğhjklmnprsştvyz][aeiouöüıİ]/i
-
Sözcük ünlü-ünlü-ünsüz olarak başlıyorsa ilk hece 1 harftir.
a-i-le
a-it
a-i-di-yet
i-a-şe
i-a-neNNz :1 /^[aeiouöüıİ]{2}[bcçdfgğhjklmnprsştvyz]/i
-
Sözcük ünsüz-ünlü-ünlü olarak başlıyorsa ilk hece 2 harftir.
sa-at-ler
fi-il
ka-i-de
me-sa-izNN :2 /^[bcçdfgğhjklmnprsştvyz][aeiouöüıİ]{2}/i
-
Sözcük ünlü-ünsüz-ünsüz-ünlü olarak başlıyorsa ilk hece 2 harftir.
em-ri-ne
iş-le-min
ak-tar-maNzzN :2 /^[aeiouöüıİ][bcçdfgğhjklmnprsştvyz]{2}[aeiouöüıİ]/i
-
Sözcük ünsüz-ünlü-ünsüz-ünlü olarak başlıyorsa ilk hece 2 harftir.
ve-rir
ta-li-mat
ma-hi-ye-ti-nezNzN :2 /^([bcçdfgğhjklmnprsştvyz][aeiouöüıİ]){2}/i
-
Sözcük ünlü-ünsüz-ünsüz-ünsüz olarak başlıyorsa ilk hece 3 harftir.
Sözcük ünlü-ünsüz-ünsüz olarak tam 3 harf ise ilk hece sözcüğün tamamıdır.ilk-ba-har
üst-te-ki
alt-lık
ilk
alt
üstNzzz :3
Nzz. :3/^[aeiouöüıİ][bcçdfgğhjklmnprsştvyz]{2}($|[bcçdfgğhjklmnprsştvyz])/i
-
Sözcük ünsüz-ünlü-ünsüz-ünsüz-ünlü olarak başlıyorsa ilk hece 3 harftir.
Sözcük ünsüz-ünlü-ünsüz olarak tam 3 harf ise ilk hece sözcüğün tamamıdır.bil-gi
müş-te-ri
sağ-lam
son
kal
gelzNzzN :3
zNz. :3/^[bcçdfgğhjklmnprsştvyz][aeiouöüıİ][bcçdfgğhjklmnprsştvyz]($|[bcçdfgğhjklmnprsştvyz][aeiouöüıİ])/i
-
Sözcük ünsüz-ünsüz-ünlü-ünsüz-ünlü olarak başlıyorsa ilk hece 3 harftir.
pro-je
kra-li-çe
tra-fo
pro-fes-yo-nelzzNzN :3 /^[bcçdfgğhjklmnprsştvyz]{2}[aeiouöüıİ][bcçdfgğhjklmnprsştvyz][aeiouöüıİ]/i
-
Sözcük ünsüz-ünlü-ünsüz-ünsüz-ünsüz olarak başlıyorsa ilk hece 4 harftir.
Sözcük ünsüz-ünlü-ünsüz-ünsüz olarak tam 4 harf ise ilk hece sözcüğün tamamıdır.borç-lan-mak
fark-lı-laş-tır
kont-rol
kang-ren
mert
hurç
Türk
sant-ralzNzzz :4
zNzz. :4/^[bcçdfgğhjklmnprsştvyz][aeiouöüıİ][bcçdfgğhjklmnprsştvyz]{2}($|[bcçdfgğhjklmnprsştvyz])/i
-
Sözcük ünsüz-ünsüz-ünlü-ünsüz-ünsüz-ünlü olarak başlıyorsa ilk hece 4 harftir.
Sözcük ünsüz-ünsüz-ünlü-ünsüz olarak tam 4 harf ise ilk hece sözcüğün tamamıdır.prog-ram-cı
Trak-ya
spor
trenzzNzzN :4
zzNz. :4/^[bcçdfgğhjklmnprsştvyz]{2}[aeiouöüıİ][bcçdfgğhjklmnprsştvyz]($|[bcçdfgğhjklmnprsştvyz][aeiouöüıİ])/i
-
Sözcük ünsüz-ünsüz-ünlü-ünsüz-ünsüz-ünsüz olarak başlıyorsa ilk hece 5 harftir.
Sözcük ünsüz-ünsüz-ünlü-ünsüz-ünsüz olarak tam 5 harf ise ilk hece sözcüğün tamamıdır.prens
trend
trans
prens-ler
trans-for-mas-yon
sport-men-ce
trans-krip-si-yonzzNzzz :5
zzNzz. :5/^[bcçdfgğhjklmnprsştvyz]{2}[aeiouöüıİ][bcçdfgğhjklmnprsştvyz]{2}($|[bcçdfgğhjklmnprsştvyz])/i
Bu çalışma standart web teknolojilerini baz almaktadır (gerekirse şirkete/markaya özel teknolojilere uyarlanabilir). Bu bağlamda CSS hyphens property odaklı bir uygulama yapılmıştır.3 Elektronik belgelerin düzgün gösterimi (satır sonu doğru yerde bölme) için tire olarak U+00AD (gizli tire / soft hyphen), tüm hecelerin açıkça gösterimi için tire olarak U+2010 (açık tire / hard hyphen) kullanılmaktadır. Yukarıda bahsedilen 12 kurala göre heceleme yapan ve tire türünü (gizli veya açık) argüman olarak alabilen örnek bir Javascript modülü aşağıda gösterilmiştir.
const SHY = '\u00AD'; // gizli tire (soft hyphen)
const HRD = '\u2010'; // açık tire (hard hyphen)
const kurallar = [
{ ptn: /^[aeiouöüıİ][bcçdfgğhjklmnprsştvyz][aeiouöüıİ]/i, len: 1}, // 2.
{ ptn: /^[aeiouöüıİ]{2}[bcçdfgğhjklmnprsştvyz]/i, len: 1}, // 3.
{ ptn: /^[bcçdfgğhjklmnprsştvyz][aeiouöüıİ]{2}/i, len: 2}, // 4.
{ ptn: /^[aeiouöüıİ][bcçdfgğhjklmnprsştvyz]{2}[aeiouöüıİ]/i, len: 2}, // 5.
{ ptn: /^([bcçdfgğhjklmnprsştvyz][aeiouöüıİ]){2}/i, len: 2}, // 6.
{ ptn: /^[aeiouöüıİ][bcçdfgğhjklmnprsştvyz]{2}($|[bcçdfgğhjklmnprsştvyz])/i, len: 3}, // 7.
{ ptn: /^[bcçdfgğhjklmnprsştvyz][aeiouöüıİ][bcçdfgğhjklmnprsştvyz]($|[bcçdfgğhjklmnprsştvyz][aeiouöüıİ])/i, len: 3}, // 8.
{ ptn: /^[bcçdfgğhjklmnprsştvyz]{2}[aeiouöüıİ][bcçdfgğhjklmnprsştvyz][aeiouöüıİ]/i, len: 3}, // 9.
{ ptn: /^[bcçdfgğhjklmnprsştvyz][aeiouöüıİ][bcçdfgğhjklmnprsştvyz]{2}($|[bcçdfgğhjklmnprsştvyz])/i, len: 4}, // 10.
{ ptn: /^[bcçdfgğhjklmnprsştvyz]{2}[aeiouöüıİ][bcçdfgğhjklmnprsştvyz]($|[bcçdfgğhjklmnprsştvyz][aeiouöüıİ])/i, len: 4}, // 11.
{ ptn: /^[bcçdfgğhjklmnprsştvyz]{2}[aeiouöüıİ][bcçdfgğhjklmnprsştvyz]{2}($|[bcçdfgğhjklmnprsştvyz])/i, len: 5} // 12.
];
function hecele(szck, tire = SHY)
{
if (szck.length < 3) // 1.
return szck;
for (const kural of kurallar)
if (kural.ptn.test(szck))
if (szck.length > kural.len)
return `${szck.slice(0, kural.len)}${tire}${hecele(szck.slice(kural.len), tire)}`;
else
return szck;
return szck; // hiçbiri uymadı, aynen döndür.
}
Object.defineProperty(hecele, 'SHY', { value: SHY});
Object.defineProperty(hecele, 'HRD', { value: HRD});
export default hecele;
Heceleme modülü noktalama imleri içermeyen tek sözcük üzerinde çalışmaktadır. Tüm bir belgenin bu modülden fayda sağlaması için noktalama imleri atlanarak sözcükler sırayla bu modüle gönderilmeli, tireler yerleştirilmiş sözcükler noktalama imlerini kaybetmeden ve orjinal sırasında belge içerisine geri konulmalıdır (veya yeni bir belge oluşturulmalıdır). Bu işlemi gösteren örnek bir Javascript bloğu şöyle olabilir:
const nokim = /([\s\u00AD\u2010,;:.'"’“”!?\/()-]+)/; /* noktalama imleri örüntüsü */
belge.split(nokim)
.map((e) => {
if (nokim.test(e)) return e;
return hecele(e, hecele.SHY);
})
.join("");
Ayırmada satır sonunda ve satır başında tek harf bırakılmaz4
Bu duruma uyan harfler 2, 3 ve 4. kurallarda gözlenir, örneğin ö-deme
, a-ile
, mesa-i
.
Her üç durumda da tek kalan harf bir ünlüdür.
Bu kuralı uygulamak için hecelenmiş sözcüğün ilk ve son tirelerine bakılır,
öncesinde veya sonrasında tek bir ünlü varsa bu tire kaldırılır, böylece satır sonunda ayırma engellenir.
const nokim = /([\s\u00AD\u2010,;:.'"’“”!?\/()-]+)/; /* noktalama imleri örüntüsü */
const k13 = /^([aeiouöüıİ])[\u00AD\u2010]|[\u00AD\u2010]([aeiouöüıİ])$/gi; // 13.
belge.split(nokim)
.map((e) => {
if (nokim.test(e)) return e;
return hecele(e, hecele.SHY).replace(k13, '$1$2');
})
.join("");
Buraya kadar anlatılan çözüm, bazı yabancı kökenli sözcükler ve yabancı kökenli sözcüklerin bulunduğu bazı birleşik sözcüklerde doğru çalışmamaktadır (Vanspor, Demirspor, şokokrem, popstar, elektrik, vs). Bu durumları kapsayacak şekilde çözümü revize etmek harf analizinden çıkıp sözcük analizine yönelmeye sebep olacağından algoritmayı karmaşıklaştırır. Ana yoldan çıkmadan bir kısayol (kestirme) çözüme entegre edilebilir. Böyle sözcüklerde bir kılavuz nokta tespit edip iki farklı sözcük varmış gibi hecelemeye başlamak sorunu ortadan kaldırmaktadır (Van·spor, Demir·spor, şoko·krem, elek·tronik, vs). ➡️
Borçlanma, gençlik, somurtkan, farklılık gibi sözcüklerin hecelenmesini sağlayan 10. kural kontrol, santral, kangren gibi batı kökenli bazı sözcüklere de uyup hatalı hecelenmelerine sebep olmaktadır. Böyle sözcükler bu listeye eklenip doğru hecelenmeleri sağlanabilir.
Footnotes
-
Bu anlatım 2016’da yapılmış bir çalışmaya dayanmaktadır. ↩
-
Örüntüler standart Javascript RegEx nesnesini baz alır. Sistem locale ayarlarına göre değişkenlik gösterdiği için character class ve range kullanımı tercih edilmemiştir. ↩
-
https://www.tdk.gov.tr/icerik/yazim-kurallari/hece-yapisi-ve-satir-sonunda-kelimelerin-bolunmesi/ ↩