Типографика: Расстановка мягких переносов на PHP

Очередной воскресный выходной в который нечем заняться…

Сегодня мы поговорим о том, как расставлять мягкие переносы в словах с использованием алгоритма П.Хpистова в модификации Дымченко и Ваpсанофьева. Мягкие переносы — это невидимые символы, которые отображаются только в местах разрыва слов в виде знака дефиса. Думаю, смысл рассатновки переносов объяснять не нужно, для этого достаточно лишь представить книгу без переносов… Под катом читайте более подробную информацию.

Описание алгоритма

Данный алгоритм сам по себе очень простой, как в плане понимания, так и в плане реализации. Логическая структура алгоритма:

  1. Преобразовать согласные буквы в s
  2. Преобразовать гласные буквы в g
  3. Преобразовать буквы й, ъ, ь в x
  4. Применить следующие правила расстановки переносов
    • gss‐ssg
    • gss‐sg
    • gs‐ssg
    • sg‐sg
    • gs‐sg
    • sg‐gg
    • sg‐gs
    • x‐gg
    • x‐gs
    • x‐sg
    • x‐ss

То есть, возьмем к примеру слово алгоритм, после первых двух преобразований оно превратится в последовательность символов gssgsgss, а после четвертой операции — в gs‐sg-sgss, то‐есть в ал‐го-ритм. Далее можно приступать к реализации.

Реализация

Алгоритм простой, а реализация еще проще =)

function hyphenize($str) {
    //Если приводить в lower-case - может возникнуть проблема
    //связанная с переносами аббирвеатур, но если это
    //не сделать - могут быть проблемы с словами "с большой буквы"
    $internal = $str; //mb_strtolower($str);
    $internal = preg_replace("/[йьъ]/u", "x", $internal);
    $internal = preg_replace("/[аеёиоуыэюя]/u", "g", $internal);
    $internal = preg_replace("/[бвгджзклмнпрстфхцчшщ]/u", "s", $internal);
    //Список правил расстановки переносов
    //Записывается от самого большого к самому маленькому, дабы не возникало
    //различных перекрываний правил
    //В качестве ключа используется правило переноса, а в качестве значения -
    //отступ для вставки переноса: 'gssssg' => 3 == 'gss-ssg'
    $rules = array(
        'gssssg' => 3,
        'gsssg' => 3,
        'gsssg' => 2,
        'sgsg' => 2,
        'gssg' => 2,
        'sggg' => 2,
        'sggs' => 2,
        'xgg' => 1,
        'xgs' => 1,
        'xsg' => 1,
        'xss' => 1
    );
    //перебираем каждое правило
    foreach ($rules as $rule => $breakOffset) {
        $offset = 0;
        //проходим по всему тексту и применяем правила переноса
        while (($pos = mb_strpos($internal, $rule, $offset)) !== false) {
            //вставляем ­ в исходный текст
            $str = self::mb_substr_replace($str, "­", $pos + $breakOffset);
            //вставляем ­ в преобразованный текст
            //необходимо для корректного расчета текущей позиции
            $internal = self::mb_substr_replace($internal, '­', $pos + $breakOffset);
            //текущая позиция + отступ вставки переноса + strlen("­")
            $offset = $pos + $breakOffset + 4;
        }
    }
    return $str;
}

Как то так =)

Заключение

Текущая реализация алгоритма не является оптимальной, и ее можно оптимизировать если появится желание, но тем не менее она работает. И конечно же есть и печальная сторона у всего этого… Хоть мягкие переносы ­ поддерживают почти все браузеры, но есть проблема при копировании и вставки текста с этими мягкими переносами. В частности, если скопировать текст с мягкими переносами, и вставить его в Word, LibreOffice, OpenOffice и некоторые обычные текстовые редакторы, то вместо нормального текста там будет каша из слов со знаком дефиса после каждого слога.

Добра вам! Счастья! Здоровья! © Анатолий

comments powered by Disqus