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

Тема в разделе "Программирование / Скриптинг", создана пользователем Danyas, 21 авг 2016.

  1. Danyas

    Danyas Спасибо, браток © yand3xmail Модератор

    Сообщения:
    1.718
    Симпатии:
    458
    Привет всем, решил поделиться полезной информацией для скриптеров.

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

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

    PHP:

    public OnPluginStart()
    {
        new 
    Stringbuffer[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(buffersizeof(buffer), "%s 1 день"buffer);
            case 
    2,3,4:    FormatEx(buffersizeof(buffer), "%s %i дня"bufferdays);
         
            default:
            {
                if(
    days 21)
                {
                    
    FormatEx(buffersizeof(buffer), "%s %i дней"bufferdays);
                }
                else
                {
                    switch(
    days 10)
                    {
                        case 
    1:        FormatEx(buffersizeof(buffer), "%s %i день"bufferdays);
                        case 
    2,3,4:    FormatEx(buffersizeof(buffer), "%s %i дня"bufferdays);
                        default:    
    FormatEx(buffersizeof(buffer), "%s %i дней"bufferdays);
                    }
                }
            }
        }
     
     
        switch(
    hours)
        {
            case 
    0:        {}
            case 
    1:        FormatEx(buffersizeof(buffer), "%s 1 час"buffer);
            case 
    2,3,4:    FormatEx(buffersizeof(buffer), "%s %i часа"bufferhours);
         
            default:
            {
                if(
    hours 21)
                {
                    
    FormatEx(buffersizeof(buffer), "%s %i часов"bufferhours);
                }
                else
                {
                    switch(
    hours 10)
                    {
                        case 
    1:        FormatEx(buffersizeof(buffer), "%s %i час"bufferhours);
                        case 
    2,3,4:    FormatEx(buffersizeof(buffer), "%s %i часа"bufferhours);
                        default:    
    FormatEx(buffersizeof(buffer), "%s %i часов"bufferhours);
                    }
                }
            }
        }
     
        switch(
    mins)
        {
            case 
    0:        {}
            case 
    1:        FormatEx(buffersizeof(buffer), "%s 1 минута"buffer);
            case 
    2,3,4:    FormatEx(buffersizeof(buffer), "%s %i минуты"buffermins);
         
            default:
            {
                if(
    mins 21)
                {
                    
    FormatEx(buffersizeof(buffer), "%s %i минут"buffermins);
                }
                else
                {
                    switch(
    mins 10)
                    {
                        case 
    1:        FormatEx(buffersizeof(buffer), "%s %i минута"buffermins);
                        case 
    2,3,4:    FormatEx(buffersizeof(buffer), "%s %i минуты"buffermins);
                        default:    
    FormatEx(buffersizeof(buffer), "%s %i минут"buffermins);
                    }
                }
            }
        }
     
        switch(
    secs)
        {
            case 
    0:        {}
            case 
    1:        FormatEx(buffersizeof(buffer), "%s 1 секунда"buffer);
            case 
    2,3,4:    FormatEx(buffersizeof(buffer), "%s %i секунды"buffersecs);
         
            default:
            {
                if(
    secs 21)
                {
                    
    FormatEx(buffersizeof(buffer), "%s %i секунд"buffersecs);
                }
                else
                {
                    switch(
    secs 10)
                    {
                        case 
    1:        FormatEx(buffersizeof(buffer), "%s %i секунда"buffersecs);
                        case 
    2,3,4:    FormatEx(buffersizeof(buffer), "%s %i секунды"buffersecs);
                        default:    
    FormatEx(buffersizeof(buffer), "%s %i секунд"buffersecs);
                    }
                }
            }
        }
     
     
        
    PrintToServer(buffer);
    }


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

    Вложения:

    • time.sp
      Размер файла:
      2,8 КБ
      Просмотров:
      2
    • time.smx
      Размер файла:
      4,4 КБ
      Просмотров:
      0
    Последнее редактирование: 21 авг 2016
    MrBoogidy, pracc, san911 и 6 другим нравится это.
  2. Grey83

    Grey83

    Сообщения:
    322
    Симпатии:
    94
    Вот так значительно короче:
    PHP:
    new String:name[][][] = { {"день""дня""дней"}, 
    {
    "час""часа""часов"}, 
    {
    "минута""минуты""минут"}, 
    {
    "секунда""секунды""секунд"} };

    String:NumToName(numtype)
    {
        
    decl String:buffer[192];
        
    buffer[0] = '\0';
        switch(
    num)
        {
            case 
    0:        {}
            case 
    1:        FormatEx(buffersizeof(buffer), "%s 1 %s"buffername[type][0]);
            case 
    2,3,4:    FormatEx(buffersizeof(buffer), "%s %i %s"buffernumname[type][1]);
            default:
            {
                if(
    num 21FormatEx(buffersizeof(buffer), "%s %i %s"buffernumname[type][2]);
                else
                {
                    switch(
    num 10)
                    {
                        case 
    1:        FormatEx(buffersizeof(buffer), "%s %i %s"buffernumname[type][0]);
                        case 
    2,3,4:    FormatEx(buffersizeof(buffer), "%s %i %s"buffernumname[type][1]);
                        default:        
    FormatEx(buffersizeof(buffer), "%s %i %s"buffernumname[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(days0), NumToName(hours1), NumToName(mins2), NumToName(secs3));
    }
     
  3. gibs

    gibs Фитиль народного волненья

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

    AlmazON деревянный © yand3xmail

    Сообщения:
    4.515
    Симпатии:
    1.969
    Для плагина с файлом перевода не "катит". А именно для них обычно интересны подобные "извращения".
     
  5. Grey83

    Grey83

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

    R1KO Супер-модератор

    Сообщения:
    5.975
    Симпатии:
    2.982
    @Danyas, открой шоп. там норм функция получения времени
     
    Последнее редактирование: 15 сен 2016
    Danyas нравится это.
  7. Grey83

    Grey83

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

    Danyas Спасибо, браток © yand3xmail Модератор

    Сообщения:
    1.718
    Симпатии:
    458
    Я вот на счет FormatEx(buffer, ......, buffer) волнуюсь...
    --- Добавлено позже ---
    @AlmazON, не зря ли я волнуюсь?
     
    AlmazON нравится это.
  9. AlmazON

    AlmazON деревянный © yand3xmail

    Сообщения:
    4.515
    Симпатии:
    1.969
    Всё равно, чувствуется геморрой... фраги, смерти, очки, поинты, ассисты, урон... Сколько же ключей надо на это всё дело, если под каждое слово - несколько.
    Да, похоже, SM сам правит за вас.
     
    Danyas нравится это.
  10. Grey83

    Grey83

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

    Danyas Спасибо, браток © yand3xmail Модератор

    Сообщения:
    1.718
    Симпатии:
    458
    @Grey83 Вот именно, что он работает правильно, но почему?
    Везет же таким как я :crazy:
     
  12. Grey83

    Grey83

    Сообщения:
    322
    Симпатии:
    94
    количество используемых слов в плагин слов (которые используются в единственном и множественных числах в разных случаях) х 3
    Хотя мне проще: я пишу обычно весь текст на английском и редко использую переводы (английский с 3 класса изучают, нефиг школу прогуливать :cool: ).
    А там в конце стоит 's', если число не равно '1'. :ab:
    Потому что так и было задумано. :acute:
     
  13. R1KO

    R1KO Супер-модератор

    Сообщения:
    5.975
    Симпатии:
    2.982
    @Danyas, там написано что в ф-и просто нет проверки на это. т.е. нет 100 % гарантии что будет форматировать как нужно
     
  14. Grey83

    Grey83

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

    R1KO Супер-модератор

    Сообщения:
    5.975
    Симпатии:
    2.982
    в sm вроде как char нельзя возвращать это раз, char buffer[] это массив, а массивы тоже нельзя возвращать это 2
     
  16. Grey83

    Grey83

    Сообщения:
    322
    Симпатии:
    94
    в SM1.8 можно, там char - это и строки, и символы. Плагин работает без проблем.

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

    Серый™ CS:S Server

    Сообщения:
    2.563
    Симпатии:
    1.149
    @Grey83, охренеть будем знать про строки.