Pull to refresh

PHP RUtils — небольшая библиотека для обработки русского текста

Reading time 5 min
Views 20K
В работе на языке Python я частенько использую библиотеку Pytils для работы с русским текстом, и мне очень не хватало этой библиотеки при работе на PHP. Возможно, я искал плохо, но все, что я находил, не предоставляло подобных возможностей либо не слишком отвечало моим понятиям о чистом коде.

И вот, однажды я решил портировать библиотеку на PHP, и теперь хочу поделиться ею с народом и очень надеюсь на помощь в ее улучшении: буду рад советам, баг-репортам и особенно pull-реквестам. Библиотека находится на GitHub'е: github.com/Andre-487/php_rutils

UPD от 26.10.2013: теперь библиотека так же доступна через Composer: packagist.org/packages/andre_487/php_rutils
Так же хочу сказать спасибо всем, кто помог улучшить библиотеку и довести ее до стабильного релиза.

Возможности библиотеки


PHP RUtils — порт Pytils на PHP. Это утилиты для работы с русским текстом. Утилиты разделены на следующие модули (классы):

  • Numeral — работа с числами: склонение существительных в зависимости от количества, числа прописью, суммы денег в рублях и копейках прописью.
  • Dt — работа с датами: расширение формата дат PHP русскими именами месяцев, дней недели; временные периоды (например, 24 976 дней назад).
  • Translit — транслитерация, подготовка строк для использования в URL'ях, именах файлов.
  • Typo — небольшой набор правил типографики простого текста.


Примеры кода


Модуль Numeral

Выбор формы множественного числа

$variants = array(
    'гвоздь', //1
    'гвоздя', //2
    'гвоздей' //5
);
$amount = 15;
echo $amount, ' ', RUtils::numeral()->choosePlural($amount, $variants);
//Result: 15 гвоздей

echo RUtils::numeral()->getPlural(2, $variants);
//Result: 2 гвоздя

Выбор формы и вывод прописью

echo RUtils::numeral()->sumString(1234, RUtils::MALE, $variants);
//Result: одна тысяча двести тридцать четыре гвоздя

Вывод числа прописью

$numeral = RUtils::numeral();
echo $numeral->getInWordsInt(100);
//Result: сто

echo $numeral->getInWordsFloat(100.025);
//Result: сто целых двадцать пять тысячных

echo $numeral->getInWords(100.0);
//Result: сто

Вывод суммы денег в рублях

echo RUtils::numeral()->getRubles(100.25);
//Result: сто рублей двадцать пять копеек


Модуль Dt

Сегодняшняя дата

Параметры передаются в качестве инстанса класса \php_rutils\struct\TimeParams, так же возможно передавать их в виде массива

$params = new TimeParams();
$params->date = null; //это значение по умолчанию
$params->format = 'сегодня d F Y года';
$params->monthInflected = true;
echo RUtils::dt()->ruStrFTime($params);
//Result: сегодня 22 октября 2013 года

Историческая дата

Параметры передаются в качестве массива, поля такие же как в классе TimeParams.
Дата передается как строка в свободном формате. Так же возможно передавать дату как Unix timestamp или как инстанс класса DateTime.

$params = array(
    'date' => '09-05-1945',
    'format' => 'l d F Y была одержана победа над немецко-фашистскими захватчиками',
    'monthInflected' => true,
    'preposition' => true,
);
echo RUtils::dt()->ruStrFTime($params);
//Result: в среду 9 мая 1945 была одержана победа над немецко-фашистскими захватчиками

Временной период до фиксированной даты в прошлом

Форматы времени для данной функции аналогичны форматам для Dt::ruStrFTime.
Параметр $accuracy отвечает за подробность информации.

$toTime = new \DateTime('05-06-1945');
echo RUtils::dt()->distanceOfTimeInWords($toTime);
//Result: 24 976 дней назад

$toTime = strtotime('05-06-1945');
$fromTime = null; //now
$accuracy = 3; //дни, часы, минуты
echo RUtils::dt()->distanceOfTimeInWords($toTime, $fromTime, $accuracy);
//Result: 24 976 дней, 11 часов, 21 минуту назад

Временной период между фиксированными датами

$fromTime = '1988-01-01 11:40';
$toTime = '2088-01-01 12:35';
$accuracy = 3; //дни, часы, минуты
echo RUtils::dt()->distanceOfTimeInWords($toTime, $fromTime, $accuracy);
//Result: через 36 525 дней, 0 часов, 55 минут


Модуль Translit

//Транслитерация
echo RUtils::translit()->translify('Муха — это маленькая птичка');
//Result: Muha - eto malen'kaya ptichka

//Обратное преобразование
echo RUtils::translit()->detranslify("SCHuka");
//Result: Щука

//Подготовка для использования в URL'ях или путях
echo RUtils::translit()->slugify('Муха — это маленькая птичка');
//Result: muha---eto-malenkaya-ptichka


Модуль Typo

$text = <<<TEXT
...Когда В. И. Пупкин увидел в газете ( это была "Сермяжная правда" № 45) рубрику Weather Forecast (r),
он не поверил своим глазам - температуру обещали +-451F.
TEXT;

//Стандартные правила
echo RUtils::typo()->typography($text);
/**
 * Result:
 * ...Когда В. И. Пупкин увидел в газете (это была «Сермяжная правда» №45) рубрику Weather Forecast®,
 * он не поверил своим глазам — температуру обещали ±451°F.
 */


//Правила из набора "extended"
echo RUtils::typo()->typography($text, TypoRules::$EXTENDED_RULES);
/**
 * Result:
 * …Когда В. И. Пупкин увидел в газете (это была «Сермяжная правда» №45) рубрику Weather Forecast®,
 * он не поверил своим глазам — температуру обещали ±451 °F.
 */

//Пользовательские правила
echo RUtils::typo()->typography($text, array(TypoRules::DASHES, TypoRules::CLEAN_SPACES));
/**
 * Result:
 * ...Когда В. И. Пупкин увидел в газете (это была "Сермяжная правда" № 45) рубрику Weather Forecast (r),
 * он не поверил своим глазам — температуру обещали +-451F.
 */

Так же (это не получится показать здесь) модуль Typo расставляет неразрывные пробелы (NBSP, THIN NBSP). Этот модуль рассчитан больше на простой текст, поэтому специальные символы HTML не используются, используются непосредственно символы UTF-8.

Подробности


Когда я портировал Pytils, я старался реализовать всю функциональность и сделать интерфейсы узнаваемыми, чтобы другие пользователи Pytils могли без труда воспользоваться PHP-версией. Так же большая часть тест-кейсов взята из тестов Pytils. Так же я позаимствовал из репозитория Pytils многие комментарии и примеры. Но, конечно же, не обошлось без «улучшений» в связи с моим авторским видением и спецификой PHP.

Например, было решено изменить сигнатуру метода Dt::ruStrFTime и вместо большого списка аргументов использовать структуру. В Пайтоне не случится драмы, если вдруг из огромного числа аргументов, имеющих значения по умолчанию, нужно изменить только последний — именованные аргументы придут на помощь; но если подобная ситуация случится в PHP, это будет настоящей трагедией. А параметров у функции прилично.

Так же, так как часто разработчики на PHP не любят передавать в функцию объект класса, но любят передавать массив, реализована возможность передавать все эти параметры в виде ассоциативного массива.

Так же учтены предпочтения разработчиков на PHP относительно дат, я постарался сделать работу с ними максимально комфортной. Как известно, со временем в PHP частенько работают в двух форматах: свободный строковой (02.03.2005, 2005-03-02) и Unix timestamp. Так же порой используется класс DateTime. Я решил, что функции, работающие с датами, должны работать со всеми тремя этими типами. Так же я добавил возможность указать временную зону для передаваемого времени.

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

Все примеры, приведенные в статье доступны в виде скриптов, приспособленных к выполнению как на веб-сервере, так и в консоли (в том числе в консоли Windows с ее cp866).

В данный момент я выбрал версию 0.1 для своей библиотеки, но я надеюсь, что для нее найдутся пользователи, которые помогут развивать ее дальше, и она доберется до версии 1.0 и даже, чем черт не шутит, 2.0.
Tags:
Hubs:
+86
Comments 26
Comments Comments 26

Articles