PSNet, developing for LiveStreet CMS

Алгоритм арабского письма (программная реализация на javascript)



На словах не раз доводилось объяснять алгоритм арабского письма. Многие знают, что в арабском языке каждая буква имеет несколько форм написания, в зависимости от места в слове. При чтении проще, можно в принципе не обращать внимание разновидность написания, а различать буквы по их типичным ярким чертам. Пусть даже они написаны все отдельно, без вязи.

Но, когда встаёт обратная задача — самому составить вязь из обрывков, то пасуют не только новички, но иногда и те, кто хорошо читают.

И на мой взгляд, основная причина сложностей — не в том, что надо запоминать по 2-4 формы для каждой буквы, так эти формы интуитивно понятные, и прямо вытекают из основного вида буквы. Проблема в наличии «исключения» из правил.

Дело в том, что 22 буквы арабского алфавита имеют 4 формы написания: отдельную, начальную, срединную и конечную. А 6 букв — только 2 формы: отдельную и конечную.

Об этой сложности я догадывался, наверное, когда вспоминал свой личный опыт изучения, а также опыт преподавания разным людям. Эти исключения реально выбивают из колеи. И вот, на днях я написал небольшую вспомогательную программку, в которой пришлось смоделировать алгоритм арабского письма. Приведу часть программного кода с комментариями. Думаю, он будет интересен и полезен всем, кому интересно устройство арабского письма, даже кто не разбирается в программировании. В конце концов, если этот алгоритм из нескольких строк учит бездушную машину составлять вязь, то вас, человека и подавно научит…

Итак, все начинается примерно с того, что у нас есть набор арабских звуков — в уме, или в виде транскрипции и надо на бумаге объединить их, согласно правилам, в вязь. Новички делают это, глядя в таблицу написаний. Вы можете наглядно её увидеть (и как из неё образуются слова), например, здесь.

Что касается программы — в неё поступает арабское слово, мы его «искусственно» разбиваем на отдельные буквы и для каждой определяем форму написания внутри вязи.

Наверное, возможны разные алгоритмы. Я же ввел понятие «разрыв вязи», чтобы легко решить задачу. Нужно перебрать всё слово по буквам и для каждой буквы определить, есть ли у неё разрыв справа и слева. Таким образом мы будем знать, какую форму написания использовать для неё. А соединение, соответственно, это инверсия разрыва (т.е. «нет разрыва» = «есть соединение»).

Разрыв вязи образуется в трёх случаях:
1) начало слова;
2) конец слова;
3) после «буквы разрыва»; (это те самые 6 букв исключений)

    var br = ['ا','د','ذ','ر','ز','و']; // Задаём массив букв разрывов
    
    s = k.split(""); // получили массив букв слова
	
	var r = new Array(); /*объявляем массив разрывов вязи справа, 
который мы должны получить. он будет состоять из нулей и единичек. 
r[i] = 0 - значит у буквы под номер i есть разрыв справа.*/ 

	var a = new Array(); /* объявляем массив алфавита, 
где будут храниться названия букв латиницей */
	
a["ا"] = "alif"; a["إ"] = "alif"; a["أ"] = "alif"; a["ب"] = "ba"; a["ت"] = "ta";
a["ة"] = "tam"; a["ث"] = "sa"; a["ج"] = "jim"; a["ح"] = "hha"; a["خ"] = "ho"; 
a["د"] = "dal"; a["ذ"] = "zal"; a["ر"] = "ro"; a["ز"] = "zajn"; a["س"] = "sin"; 
a["ش"] = "shin"; a["ص"] = "sod"; a["ض"] = "dod"; a["ط"] = "to"; a["ظ"] = "zo"; 
a["ع"] = "gajn"; a["غ"] = "gojn"; a["ف"] = "fa"; a["ق"] = "qaf"; a["ك"] = "kaf"; 
a["ل"] = "lam"; a["م"] = "mim"; a["ن"] = "nun"; a["ه"] = "ha"; a["ي"] = "ja"; 
a["و"] = "waw";

	r[0] = 0;  /* в начале слова по-любому разрыв справа */
	r[s.length] = 0; /* в конце слова тоже по-любому - 
разрыв, но уже слева у последней буквы */

/*по очереди перебираем все буквы внутри слова. если букве предшествовала 
"буква разрыва", значит у неё будет разрыв справа. в противном случае - нет */

	for (var i = 1; i < s.length; i++)
	{
	if (br.indexOf(s[i-1]) >= 0) {r[i] = 0;} else {r[i] = 1;}  
        }

	var result = new Array(); /*этот массив будет хранить 
латинское название буквы и форму написания */


/* объединяем два массива: буква и соединение (справа и слева) */
	for (var i = 0; i < s.length; i++)
	result[i] = a[s[i]] + r[i] + r[i+1]; 

/* a[s[i]] - выдаёт нам название арабской буквы латиницей; 
r[i] - говорит, есть ли соединение справа (есть, если =1 и нет, если = 0)
r[i+1] - говорит, есть ли соединение слева */
	return result;

Я немного упростил код, убрал всё то, что не относилось к теме статьи. В итоге, при заданном слове «Аллах» ألله мы получим на выходе такую последовательность: alif00, lam01, lam11, ha10



00 — отдельное написание; (с обоих сторон разрыв)
01 — начальное; (сначала был разрыв, а потом пошло соединение)
11 — срединное; (с обоих сторон соединение)
10 — конечное; (сначала было соединение, а потом произошёл разрыв)

Если кому-то интересно, что это за программа такая и где может пригодиться, скажу — это вспомогательная штучка для одной более крупной программы, над которой я сейчас работаю. Так что, следите за развитием, коли интересно.

Комментарии (4)

RSS свернуть / развернуть
На словах ни раз доводилось
исправь «ни» на «не»
+1
Моя изучалка буков заглохла — никак не могла добиться мультиплатформенности из-за диакритических знаков в транскрипции букв. Но недавно придумала, как это сделать — надо на сервере с помощью ImageMagick генерировать картинки и затем их кэшировать. Таким образом исправится и ситуация с непостоянной высотой строки арабских букв в разных шрифтах.
0
  • avatar
  • loly
  • 16 октября 2011, 11:58
Забыли в блог «Религия и IT» добавить.
0
  • avatar
  • loly
  • 16 октября 2011, 12:07
изначально туда кстати хотел, потом не знаю, промазал как-то. а теперь думаю, ссылка испортится наверное, если перемещу. А одновременно в 2 блога нельзя вроде.
0
Для комментирования можно использовать аккаунт соцсети или зарегистрироваться