Ru-MaNGOS

Ru-MaNGOS (http://mangos.ytdb.ru/index.php)
-   Языки программирования (http://mangos.ytdb.ru/forumdisplay.php?f=34)
-   -   Регулярные выражения (http://mangos.ytdb.ru/showthread.php?t=2777)

Hantet 31.10.2010 00:00

Регулярные выражения
 
"Похожие темы не найдены" - так молвил форум при введённом поле "Заголовок". :yes3:

Сразу к делу.
Пытаюсь составить регулярное выражение на php.
Изучил литературу, ссылки на которую мне выдал гугл.

Дано:
Строка, в которой может находится ноль или несколько выражений, отделённых от строки символами "{" и "}" соответственно.
После открывающей фигурной скобки идёт символ "@", затем содержимое текстового блока.
Текстовый блок состоит из 4ёх частей, разделённых между собой символом ";":
1. 1-е окончание.
2. 2-е окончание.
3. 3-е окончание.
4. Число-параметр.

Пример строки:
На Вашем счёте {@рубль;рубля;рублей;5}.

Выходящее значение:
На Вашем счёте 5 рублей.

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

Пытался сделать так:
Код:

$str = 'На Вашем счёте {@рубль;рубля;рублей;5}.';
preg_match_all("/[{][@][;a-zA-Zа-яА-Я0-9]+[}]/", $str, $matches);
if(count($matches) == 0)
return false;

...

Функция возвращает false.
Буду очень благодарен за помощь.



Добавлено через 1 час 12 минут
Проблему решил сам, всем спасибо =)
Пожалуй, поделюсь кодом =)

Функция:
Код:

public function ending($str = null)
{
        if($str == null)
                return false;
       
        if(!preg_match_all("/{[@]([a-zA-Zа-яА-Я0-9;]+)}/", $str, $arr))
                return false;

        $cnt = count($arr);
        if($cnt < 2)
                return false;

        for($i=1;$i<$cnt;$i++)
        {
                foreach($arr[$i] as $one)
                {
                        $end = explode(';', $one);
                        if(strlen($end[3]) == 0)
                                continue;
                       
                        $num100 = $end[3] % 100;
                        $num10 = $end[3] % 10;
                       
                        if($num100 >= 5 && $num100 <= 20)
                                $replace = $end[2];
                        else if($num10 == 0)
                                $replace = $end[2];
                        else if($num10 == 1)
                                $replace = $end[0];
                        else if($num10 >= 2 && $num10 <= 4)
                                $replace = $end[1];
                        else if($num10 >= 5 && $num10 <= 9)
                                $replace = $end[2];
                        else
                                $replace = $end[1];
                       
                        $search = '{@'.$end[0].';'.$end[1].';'.$end[2].';'.$end[3].'}';
                        $str = str_replace($search, $end[3].' '.$replace, $str);
                }
        }
        return $str;
}

Вызывается таким нехитрым способом:
Код:

$online = 272; //предположим
$txt = "Сейчас в игре {@человек;человека;человек;$online}.";
echo ending($txt);

Результат выполнения функции следующий:
Сейчас в игре 272 человека.

Соль данной функции в том, что она позволяет делать следующее:
Код:

$str = "Всего в игре {@человек;человека;человек;$online}.<br/>";
$str.= "Из них {@орк;орка;орков;$orc} и {@гном;гнома;гномов;$gnome}";
echo ending($txt);


LordJZ 31.10.2010 00:07

Напомнило «каждому символу — по домику».

Тег php кривой, потому без подсветки:
Код:

$str = 'На Вашем счёте {@рубль;рубля;рублей;5}.';
// Создает callback-функцию, обрабатывающую каждое попадание конструкции {@a;b;c;[d;[e;...]];x}
$callback = function ($matches)
{
        $words = explode(';', $matches[1]); // Разделяем a;b;c на array(a, b, c)
        $n = $matches[2]; // Число x
        // Взято на просторах этого вашего интернета
        return $n.' '.$words[$n%10==1&&$n%100!=11?0:($n%10>=2&&$n%10<=4&&($n%100<10||$n%100>=20)?1:2)];
};
echo preg_replace_callback('/{@([^}]+);(\d+)}/', $callback, $str);


Hantet 31.10.2010 00:11

Супер, спасибо, буду вникать :)
Всё-таки хорошо, что я дошёл до цели сам, пусть криво, долго и громоздко, но сам!
Так бы никогда и не начал работать с регулярками.

Праведник 31.10.2010 17:36

Зачем вообще регулярки?)

Код:

function number_ending($number, $ending0, $ending1, $ending2) {
    $num100 = $number % 100;
    $num10 = $number % 10;
    if ($num100 >= 5 && $num100 <= 20) {
        return $ending0;
    } else if ($num10 == 0) {
        return $ending0;
    } else if ($num10 == 1) {
        return $ending1;
    } else if ($num10 >= 2 && $num10 <= 4) {
        return $ending2;
    } else if ($num10 >= 5 && $num10 <= 9) {
        return $ending0;
    } else {
        return $ending2;
    }
}

всё... аргументы: число, окончание 1, окончание 2, окончание 3

Hantet 31.10.2010 17:48

Праведник, я именно эту функцию и использую, только немного её модернизировал и привязал к регуляркам. Зачем? Очень просто!

Мой движок использует один шаблон (html каркас), в котором в определённых местах (шапка, футер, меню, контент) выставлены блоки а-ля {HEADER}, {BODY} и т.д.
В этом шаблоне исключительно HTML, он у меня даже находится в txt файле =)

Ну не суть, php читает шаблон, подставляет вместо блоков вида {ИМЯ} содержимое.
И вот у меня появилась идея вынести все элементы, которые отображаются на всех страницах сайта, прямо в шаблон.

Вот как-то так:
Код:

...
<div id="online">В игре {@человек;человека;человек;{online}}.</div>
...

В результате мы получаем сразу на всех страницах сайта строку с показателем онлайна, вида:

<div id="online">В игре 232 человека.</div>

Тем самым эту строку не приходится определять всякий раз на страницах сайта.


Текущее время: 03:20. Часовой пояс GMT +3.

ru-mangos.ru - Русское сообщество MaNGOS