Для разрешения этой ситуации можно составить словарь, содержащий в себе все слова-исключения и их правильные разложения на слоги. Решение это несомненно правильное, но чересчур трудоёмкое и неблагодарное.
Более простой, но менее удобный в использовании способ – проверка разложения пользователем и в случае ошибочного разложения ввод правильного варианта с клавиатуры.
Поскольку основной целью курсовой работы является всё-таки разработка генератора, то такие недочеты программы можно опустить в связи с их непринципиальностью.
При разработке функции деления слова на слоги, удобно воспользоваться учебником русского языка и основными правилами деления на слоги:
1. Слова делятся на слоги: го-ло-ва, ка-пу-ста(ка-пус-та),<…>, мо-я, я-ма и др.
2. Слог может состоять из одного звука, из двух и более: о-на, у-зел, ко-выль,<…> и др.
3. В состав слога обязательно входит гласный звук, поэтому в слове столько слогов, сколько гласных звуков. <…>
4. Согласные звуки или начинают слог (го-ло-ва), или заканчивают его (он, ум и др.), или окружают гласный звук с обеих сторон (шум, дым и др.)[1].
1.3.2 Алгоритм группировки слогов в слова
Слоги можно группировать по нескольким признакам:
1. по принадлежности к тому или иному ключевому слову, например, не включать в новое слово более n слогов из одного ключевого слова (где n от 1 до количества слогов в слове).
2. по их положению в ключевых словах. Скажем, слоги в новых словах не могут идти в обратном порядке, чем в ключевых; или последние слоги ключевых слов не могут использоваться в качестве первых в новых, и т.д.
3. по повторяемости. Наиболее разумное ограничение – не допускать повторения слога в пределах одного нового слова.
По этим признакам можно вводить ограничения на постановку слога в слово. На данном этапе для нас это не главное. По этому мы рассмотрим общий случай, когда любой слог может оказаться на любом месте нового слова.
Стоит также задуматься о производительности данного алгоритма. Ведь чем больше ключевых слов будет введено, тем больше можно из них создать новых. Стоит учитывать также, что можно формировать слова с количеством слогов от 2-х до n, где n – общее число слогов. Этот фактор также увеличивает количество возможных вариантов.
Поэтому необходимо вводить какие-либо ограничения для выходных данных. Это может быть длина слов, количество слогов в них, степень повторяемости отдельных сочетаний (можно ввести в процентах от длины слова допустимое количество совпадения букв) или что-нибудь в этом роде.
При установке ограничений время выполнения программы значительно сократится. Реализация предложенных ограничений выглядит приблизительно одинаково, по этому для упрощения далее я буду ограничивать только количество слогов в слове, но стоит не забывать, что это не единственная возможность.
Реализацию полученного алгоритма я решила осуществить на языке PHP 4.0. Свой выбор я обосновываю его синтаксической близостью к языку программирования Си, с которым я наиболее знакома, и простотой работы с данными различных типов (что может особенно пригодиться для создания массивов строк). Кроме того, в процессе работы я смогу улучшить свои навыки работы с PHP, изучить его особенности.
Для ввода входных данных создадим с помощью языка разметки HTMLстраничку, содержащую форму. В её поля должны вводиться:
· количество ключевых слов (поле kol);
· непосредственно слова, записанные через запятую (поле slova);
· количество слогов в генерируемых словах (поле slog).
Данные этой формы будут обрабатываться файлом kurs.php, в результате работы которого будет генерироваться страничка со списком сгенерированных слов.
Сначала необходимо считать данные из формы и записать их в соответствующие переменные.
$kol=$_POST["kol"];
$slova=$_POST["slova"];
$slog=$_POST["slog"];
В переменных kol и slogсейчас находятся какие-либо числа, а в переменной slova находится строка, состоящая из слов, разделенных запятыми и пробелами. Преобразуем её в массив строк (s):
$s=explode(",",$slo);
Для дальнейшей работы нам необходимо еще избавиться от ненужных нам пробельных символов (которые могут появиться при заполнении формы). Для этого воспользуемся встроенной функцией string trim (string str [, string charlist]). После такого рода обработки, можно будет приступить непосредственно к реализации алгоритма разбиения слова на слоги.
Слова из массива строк sпо одному будем посылать на обработку в функцию delslog($str).
functiondelslog($str)
{$k=k_slog($str); //посчитаем количество слогов
$mas=slog($str, $k); //разобьём слово на слоги
$f=fopen("slogi.txt","a");//откроем файл slogi.txt
for($i=0;$i<count($mas);$i++) //длязаписии
{//через «-» запишем в
$mas[$i].='-'; //него слоги
fwrite( $f,$mas[$i]);}
fclose($f);} //закроем файл
В этой части программы происходит вызов функций k_slog($str)и slog($s, $k). Рассмотрим их подробнее.
functionk_slog($str) //считает количество слогов
{//бежим по строке
for($i=0, $q=0; $i < strlen($str); $i++)
if(glas($str[$i])) // если очередная буква
$q++; //гласная, увеличим счетчик
return $q; } //вернём значение счетчика
Функция slog($s, $k)выполняет непосредственно разбиение слова на слоги. Как видно из примеров в п. 1.3.1, многие слова можно разделить на слоги несколькими способами. По этому определить принадлежность каждой буквы к тому или иному слогу – довольно-таки сложная задача.
Разберемся сначала с гласными буквами. Каждая из них является основой слога, по этому достаточно только отслеживать, чтобы в слог не попала вторая гласная (в этом случае должен осуществиться переход к новому слогу). За это будет отвечать флажок q.
С согласными все сложнее. Из-за разночтений в правилах деления слов на слоги я решила придерживаться следующих пунктов:
1. Согласная и последующая гласная относятся к одному и тому же слогу;
2. Все согласные буквы, находящиеся перед первой гласной принадлежат одному слогу;
3. Все согласные буквы, расположенные после последней гласной принадлежат одному и тому же слогу;
4. Из нескольких согласных, расположенных в середине слова, первая относится к текущему слогу, остальные – к следующему (исключения составляют буквы «ъ» и «ь», которые «привязываются» к предыдущей согласной).
Последний пункт вызывает наибольшее количество сомнений относительно правильности, но вполне удовлетворяет изложенным в учебнике [1] правилам.
Получилифункцию:
function slog($s, $k) //разбиваетсловонаслоги
{for($i=0, $q=0, $j=0; $i<strlen($s);)
{if(glas($s[$i]) && $q==0)//если очередная буква
{ //гласная и первая
$mas[$j].=$s[$i]; //припишем ее к слогу
$q=1; //установим флажок
$i++; //перейдем на след. букву}
else
if(!glas($s[$i]) && ($i==0 || $q!=1 || (glas($s[$i-1]) && !glas($s[$i+1])) || $j==$k-1))
/*если буква не гласная и: первая, или до гласной, или между гласной и согласной, или последняя*/
{
$mas[$j].=$s[$i];//припишем её к слогу
$i++; //перейдем на след. букву}
else
{ $q=0; //иначе снимем флажок и
$j++;} //перейдем на след. слог}
return $mas;} //вернём массив слогов
В приведенных функциях вызывается функция glas($a). Она выглядит так:
functionglas($a) //проверяет, гласная ли буква 'а'
{
$gls='аеёиоуыэюя'; //Запишем строки из строчных и
$glb='АЕЁИОУЫЭЮЯ'; //заглавныхбукв
for($i=0; $i < 11; $i++)
if(substr_count($gls,$a)>0|| //если 'а' входит
substr_count($glb,$a) > 0)//в одну из строк
return 1; // вернём 1
return 0;}
Эта функция ищет вхождение переданной ей буквы a в двух строках, gls и glb, состоящих из строчных и заглавных гласных букв русского алфавита. Она возвращает 1, если буква присутствует в одной из строк (т.е. является гласной), иначе – 0.
Мы получили кусок основной программы, выполняющий первую задачу – разбиение слов на слоги.
В результате работы этой части программы файл slogi.txtзаполняется слогами всех введенных слов, разделёнными знаком «-». Использование файла для временного хранения информации я считаю наиболее выгодным. Этот способ наиболее надежен и прост, потому что в противном случае пришлось бы либо вводить дополнительно переменные под хранение массивов слогов, либо наращивать один массив, но тогда могла бы возникнуть проблема с индексом, т.к. его надо было бы отправлять в качестве ещё одного параметра в функцию delslog($str). Использование нескольких функций вместо одной большой мне кажется также оправданным, т.к. это существенно упрощает восприятие текста программы. К тому же отдельные функции легче исправлять и дополнять.
После разбиения всех введенных слов на слоги запускается функция группировки слогов в слова (group($k)). У неё только один входной параметр – количество слогов в новых словах.
В основе этой функции лежит алгоритм размещения с повторениями чисел 1..n в последовательности по kэлементов.[5]
Рассмотрим эту функцию.
function group($k)
{
$f=fopen("slogi.txt","rt");//откроемфайл slogi.txt
$a=explode("-",fgets($f));//запишем слоги в масс. а
fclose($f); //закроемфайл
$n=count($a)-1; //посчитаемколичествослогов
for($i=0;$i<$k;$i++){
$x[$i]=1; //зададим начальную и
$y[$i]=$n;} //конечную комбинацию чисел
while(prov($x,$y)) //пока они различны
{$p=$k; //пост. инд. в конец посл-ти
while($x[$p]==$n)//пока не найдем эл-т, отличный от
$p--; //максимального, уменьш. р
$x[$p]++; //увелич р-й эл-т послед-ти
for($i=$p+1;$i<$k;$i++)
$x[$i]=1; //все след-ие делаем единицами
if(correct($x)) //если комбинация нам подходит
{for($i=0;$i<$k;$i++) //выводим слоги с соотв.
{ print $a[$x[$i]-1];}//номерами на экран
echo "<br>";} //переход на новую строку}
Эта функция вызывает prov($x, $y)и correct($x). Функция prov($x, $y)следит за совпадением начальной и конечной комбинациями. Это осуществляется методом простого перебора всех элементов массивов x и y. Если в результате количество совпадающих элементов равно количеству элементов в любом из массивов, то возвращается 0 (и алгоритм размещений с повторениями заканчивает свою работу).