[ANY] Определение окончания слова день (дня, дней)

Danyas

Участник
Сообщения
2,173
Реакции
1,072
Привет всем, решил поделиться полезной информацией для скриптеров.

Бывает такое, что нужно выводить, например количество дней, убийств, смертей, очков и прочей информации, которая имеет разное окончание слова при разном значении информации.
Не лаконично ведь смотреть на фразу: "Вы наиграли 0 день 21 часов 5 минута 39 секунда" :haha:

В многих ЯП есть функция mod (modulo), в SourcePawn она так же имеется.
К чему она? Сейчас покажу пример, который будет править окончания разной информации.

PHP:
public OnPluginStart()
{
    new String: buffer[192] = "Время, которое прошло после написания поста:";
    new time = GetTime() - 1471777116;
    new days = time/3600/24;
    new hours = time/3600%24;
    new mins = time/60%60;
    new secs = time%60;
 
    switch(days)
    {
        case 0:        {}
        case 1:        FormatEx(buffer, sizeof(buffer), "%s 1 день", buffer);
        case 2,3,4:    FormatEx(buffer, sizeof(buffer), "%s %i дня", buffer, days);
     
        default:
        {
            if(days < 21)
            {
                FormatEx(buffer, sizeof(buffer), "%s %i дней", buffer, days);
            }
            else
            {
                switch(days % 10)
                {
                    case 1:        FormatEx(buffer, sizeof(buffer), "%s %i день", buffer, days);
                    case 2,3,4:    FormatEx(buffer, sizeof(buffer), "%s %i дня", buffer, days);
                    default:    FormatEx(buffer, sizeof(buffer), "%s %i дней", buffer, days);
                }
            }
        }
    }
 
 
    switch(hours)
    {
        case 0:        {}
        case 1:        FormatEx(buffer, sizeof(buffer), "%s 1 час", buffer);
        case 2,3,4:    FormatEx(buffer, sizeof(buffer), "%s %i часа", buffer, hours);
     
        default:
        {
            if(hours < 21)
            {
                FormatEx(buffer, sizeof(buffer), "%s %i часов", buffer, hours);
            }
            else
            {
                switch(hours % 10)
                {
                    case 1:        FormatEx(buffer, sizeof(buffer), "%s %i час", buffer, hours);
                    case 2,3,4:    FormatEx(buffer, sizeof(buffer), "%s %i часа", buffer, hours);
                    default:    FormatEx(buffer, sizeof(buffer), "%s %i часов", buffer, hours);
                }
            }
        }
    }
 
    switch(mins)
    {
        case 0:        {}
        case 1:        FormatEx(buffer, sizeof(buffer), "%s 1 минута", buffer);
        case 2,3,4:    FormatEx(buffer, sizeof(buffer), "%s %i минуты", buffer, mins);
     
        default:
        {
            if(mins < 21)
            {
                FormatEx(buffer, sizeof(buffer), "%s %i минут", buffer, mins);
            }
            else
            {
                switch(mins % 10)
                {
                    case 1:        FormatEx(buffer, sizeof(buffer), "%s %i минута", buffer, mins);
                    case 2,3,4:    FormatEx(buffer, sizeof(buffer), "%s %i минуты", buffer, mins);
                    default:    FormatEx(buffer, sizeof(buffer), "%s %i минут", buffer, mins);
                }
            }
        }
    }
 
    switch(secs)
    {
        case 0:        {}
        case 1:        FormatEx(buffer, sizeof(buffer), "%s 1 секунда", buffer);
        case 2,3,4:    FormatEx(buffer, sizeof(buffer), "%s %i секунды", buffer, secs);
     
        default:
        {
            if(secs < 21)
            {
                FormatEx(buffer, sizeof(buffer), "%s %i секунд", buffer, secs);
            }
            else
            {
                switch(secs % 10)
                {
                    case 1:        FormatEx(buffer, sizeof(buffer), "%s %i секунда", buffer, secs);
                    case 2,3,4:    FormatEx(buffer, sizeof(buffer), "%s %i секунды", buffer, secs);
                    default:    FormatEx(buffer, sizeof(buffer), "%s %i секунд", buffer, secs);
                }
            }
        }
    }
 
 
    PrintToServer(buffer);
}


upload_2016-8-21_14-34-25.png
 

Вложения

  • time.sp
    2.8 КБ · Просмотры: 10
  • time.smx
    4.4 КБ · Просмотры: 8
Последнее редактирование:

Grey83

не пишу плагины с весны 2022
Сообщения
8,569
Реакции
5,071
Вот так значительно короче:
PHP:
new String:name[][][] = { {"день", "дня", "дней"}, 
{"час", "часа", "часов"}, 
{"минута", "минуты", "минут"}, 
{"секунда", "секунды", "секунд"} };

String:NumToName(num, type)
{
    decl String:buffer[192];
    buffer[0] = '\0';
    switch(num)
    {
        case 0:        {}
        case 1:        FormatEx(buffer, sizeof(buffer), "%s 1 %s", buffer, name[type][0]);
        case 2,3,4:    FormatEx(buffer, sizeof(buffer), "%s %i %s", buffer, num, name[type][1]);
        default:
        {
            if(num < 21) FormatEx(buffer, sizeof(buffer), "%s %i %s", buffer, num, name[type][2]);
            else
            {
                switch(num % 10)
                {
                    case 1:        FormatEx(buffer, sizeof(buffer), "%s %i %s", buffer, num, name[type][0]);
                    case 2,3,4:    FormatEx(buffer, sizeof(buffer), "%s %i %s", buffer, num, name[type][1]);
                    default:        FormatEx(buffer, sizeof(buffer), "%s %i %s", buffer, num, name[type][2]);
                }
            }
        }
    }
    return buffer;
}

public OnPluginStart()
{
    new time = GetTime() - 1471777116;
    new days = time/3600/24;
    new hours = time/3600%24;
    new mins = time/60%60;
    new secs = time%60;

    PrintToServer("Время, которое прошло после написания поста:%s%s%s%s", NumToName(days, 0), NumToName(hours, 1), NumToName(mins, 2), NumToName(secs, 3));
}
 

gibs

Фитиль народного волненья
Сообщения
722
Реакции
407
Мошенник
@Danyas, почти каждый раз как открываю твою тему, то вспоминаю фразу учительницы укр. языка в школе "дурному не нудно і самому")))
ЗЫ: я всегда пишу просто дней, минут, секунд и тд. Не стоит на таком даже заморачиваться.
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,569
Реакции
5,071
@AlmazON, просто в строковом массиве поменять значение ячеек.
Да и в других языках будет несколько иначе всё равно.
Я для теста вообще так делал (у меня вместо кириллицы в консоли абракадабра):
PHP:
new String:name[][][] = { {"day", "day's", "days"},
{"hour", "hour's", "hours"}, 
{"minute", "minute's", "minutes"}, 
{"second", "second's", "seconds"} };
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #6
@Danyas, открой шоп. там норм функция получения времени
 
Последнее редактирование:

Grey83

не пишу плагины с весны 2022
Сообщения
8,569
Реакции
5,071
@AlmazON, так а я про что?
Меняются значения в массиве, а потом эти значения используются как ключи в переводе.
Оригинал и так только для русскоязычных плагинов.
Я просто сделал сам плагин короче раза в 4 за счёт функции 'NumToName'.
 

Danyas

Участник
Сообщения
2,173
Реакции
1,072
Я вот на счет FormatEx(buffer, ......, buffer) волнуюсь...
--- Добавлено позже ---
@AlmazON, не зря ли я волнуюсь?
 

AlmazON

Не путать с самим yand3xmail
Сообщения
5,099
Реакции
2,755
как ключи в переводе
Всё равно, чувствуется геморрой... фраги, смерти, очки, поинты, ассисты, урон... Сколько же ключей надо на это всё дело, если под каждое слово - несколько.
FormatEx(buffer, ......, buffer)
Да, похоже, SM сам правит за вас.
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,569
Реакции
5,071
@Danyas, как я понял по пометке на SourceMod API
'Это то же самое , как Format ( ) , за исключением того, ни один из входных буферов не может перекрываться ту же память что и исходящий буфер . Так как эта проверка безопасности удаляется, он немного быстрее.'
имеется в виду буфер вывода, а не строковая переменная. Т.е. плагин будет использовать память неэкономно, но работать будет быстрее.
Хотя хз, но так плагин выдаёт результаты корректно, то волнуешься ты зря, похоже.
 

Danyas

Участник
Сообщения
2,173
Реакции
1,072
@Grey83 Вот именно, что он работает правильно, но почему?
Везет же таким как я :crazy:
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,569
Реакции
5,071
Всё равно, чувствуется геморрой... фраги, смерти, очки, поинты, ассисты, урон... Сколько же ключей надо на это всё дело, если под каждое слово - несколько.
количество используемых слов в плагин слов (которые используются в единственном и множественных числах в разных случаях) х 3
Хотя мне проще: я пишу обычно весь текст на английском и редко использую переводы (английский с 3 класса изучают, нефиг школу прогуливать :cool: ).
А там в конце стоит 's', если число не равно '1'. :ab:
@Grey83 Вот именно, что он работает правильно, но почему?
Потому что так и было задумано. :acute:
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #13
@Danyas, там написано что в ф-и просто нет проверки на это. т.е. нет 100 % гарантии что будет форматировать как нужно
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,569
Реакции
5,071
И вообще, я когда писал себе функцию перевода времени в дни/часы/минуты/секунды вот такое получилось :biggrin: :
PHP:
char SecondsToTime(float time)
{
    int t, days, hours, minutes, seconds;
    char buffer[64];
    t = RoundToFloor(time);
    if (t >= 86400)
    {
        days = RoundToFloor(t / 86400.0);
        t -= days * 86400;
    }
    if (t >= 3600)
    {
        hours = RoundToFloor(t / 3600.0);
        t -= hours * 3600;
    }
    if (t >= 60)
    {
        minutes = RoundToFloor(t / 60.0);
        t -= minutes * 60;
    }
    if (t > 0) seconds = t;
    if(days > 0) Format(buffer, sizeof(buffer), "%dd %dh:%dm:%ds", days, hours, minutes, seconds);
    else if(hours > 0) Format(buffer, sizeof(buffer), "%dh:%dm:%ds", hours, minutes, seconds);
    else if(minutes > 0) Format(buffer, sizeof(buffer), "%dm:%ds", minutes, seconds);
    return buffer;
}
У Danyas вышло гораздо компактней с переводом. Нужно не забыть спереть решение себе (и пофиксить нахождение дней, а то там может получиться float 9 случаях из 10).:mocking:
 
Последнее редактирование:

Grey83

не пишу плагины с весны 2022
Сообщения
8,569
Реакции
5,071
в sm вроде как char нельзя возвращать это раз, char buffer[] это массив, а массивы тоже нельзя возвращать это 2
в SM1.8 можно, там char - это и строки, и символы. Плагин работает без проблем.

В общем после всех правок получилась вот такая лабуда:
PHP:
char SecondsToTime(float time)
{
    char buffer[64];
    t = RoundToFloor(time);
    Format(buffer, sizeof(buffer), "%2ds", t%60);
    if(t >= 60) Format(buffer, sizeof(buffer), "%2dm:%s", t/60%60, buffer);
    if(t >= 3600) Format(buffer, sizeof(buffer), "%2dh:%s", t/3600%24, buffer);
    if(t >= 86400) Format(buffer, sizeof(buffer), "%2dd %s", t/86400, buffer);
    return buffer;
}
Как будет работать - посмотрим.
 
Последнее редактирование:
Сверху Снизу