Сегодня надо было решить одну задачку, а именно — вывести цифру и слово, у которого окончание зависит от числа. 5 Человек, 3 человека, 1928 человек и так далее. Самих чисел может быть сколько угодно.
Полез в нет за готовым решением, нашел там одни циклы по условию
if( тут всякие деления по модулю == столько то){ то вывести так} if( тут еще как нибудь){ вывести так}
Или тоже самое, но вариант switch … case…
Крайне громоздко, особенно если требуется вывести строку только в одном месте.Ну и работает до определенного потолка — если число будет миллион, то надо либо внутри цикла циклом цифру для умножения увеличивать, либо прописывать с руки все варианты.
Еще есть вариант забить все данные в массив и там искать нужную пару значений:
$array = ( "1", "человек", "2", "человека", .... if(in_array(....
Проблемы те же, надо либо генерить все возможные варианты, либо какую то хитрую функцию писать, чтобы искать там.
Еще один знакомый прогер подсказал вариант с ngettext. Но там также надо колдовать с расчетами:
<?php /** * Returns: * 0, if $n == 1, 21, 31, 41, ... * 1, if $n == 2..4, 22..24, 32..34, ... * 2, if $n == 5..20, 25..30, 35..40, ... */ function plural( $n ) { if ( $n % 10 == 1 && $n % 100 != 11 ) { return 0; } if ( $n % 10 >= 2 && $n % 10 <= 4 && ( $n % 100 < 10 || $n % 100 >= 20 ) ) { return 1; } return 2; } // usage for ( $i = 0; $i < 100; $i++ ) { $x = plural( $i ); printf( "%d тетрад%s<br/>\n", $i, ( 0 == $x ? 'ь' : ( 1 == $x ? 'и' : 'ей' ) ) ); } ?> Output: 0 тетрадей 1 тетрадь 2 тетради 3 тетради 4 тетради 5 тетрадей 6 тетрадей 7 тетрадей 8 тетрадей 9 тетрадей 10 тетрадей ... Also here is short version: <?php $n = 17; print ($n%10==1 && $n%100!=11 ? 0 : ($n%10>=2 && $n%10<=4 && ($n%100<10 || $n%100>=20) ? 1 : 2)); ?> output: 2
Тут один фиг на 100 делится, большие числа ну никак не пролезут. Мой вариант, делает тоже самое, только без ограничения на число, вычисляет по последней цифре:
$result = '19321'; $mess = preg_replace("(2|3|4)","тетради", substr($result, -1)); ((substr($mess, -1) * 1) > 1 OR (substr($mess, -1) * 1) == 0) ? $mess = "тетрадей" : $mess = "тетрадь"; echo $result . ' ' .$mess;
В одну строку так и не сумел придумать ((
UPD А вот сумел
echo (( (substr($str, -1) * 1) 1)) ? "тетради" : ( (( (substr($str, -1) * 1) == 0) OR ( (substr($str, -1) * 1) > 4)) ? "тетрадей" : "тетрадь" );
И полезный линк на тернарный оператор
27 комментариев
Я, не стал писать свой велосипед, использую такой вариант http://cshrc.blog.ru/92267443.html Оригинал был размещен на Хабре, но пост не нашел.
Neolot, я просто хотел найти решение в одну строку, а тут вариант с предварительным заданием массива.
ПыСы, прочитал твой комент и придумал, как сделать в одну строку 🙂
$str = "329"; // tetradey
echo (( (substr($str, -1) * 1) 1)) ? "тетради" : ( (( (substr($str, -1) * 1) == 0) OR ( (substr($str, -1) * 1) > 4)) ? "тетрадей" : "тетрадь" );
Выглядит крайне ужасно ))
Более понятно, когда выносим сравниваемую строку отдельно
$str = "325"; // tetradey
$a = (substr($str, -1) * 1);
$a = (($a 1)) ? "тетради" : ( (($a == 0) OR ($a > 4)) ? "тетрадей" : "тетрадь" );
echo $a . "\r\n";
И все равно это не идеальный вариант потому, что 11 тетрадей но 21, 31, 41 тетрадь. Ну тут только исключение добавлять.
а зачем в одну строку ?:
Краткость сестра таланта ?
Ну да ))
Да, решение надо использовать, а то всегда смешно, когда в каких нибудь сервисах пишут вам 24 «лет»:)
спасибо за подсказку
есть же хорошие плагины для wordpress, чем вам не нравиться?
Да, без исключений не обойтись, таков русский язык. Это еще хорошо получилось, в три строки.
Поддерживаю Yaroslavgrust для вордпрес сейчас же есть плагины зачем что то самому изобретать, если можно просто поискать в буржунете и потом останетса только русифицыровать что есть гораздо легче и быстрее
Видел некоторые плагины на wordpress полезные например и сохранении вашего времени.
Да, но кто говорит, чтоб использовать код в WordPress, не все же на этом движке написано.
Здорово ) я обычно пользуюсь функцией, которую написал давным-давно, предварительно проштудировав учебник русского ) но в одну строчку все то же самое — это круто!
О да! Нашел таки решение. Еле выцарапал из Гоши ваш пост… Спасибо, помогли ломаку в пхп 🙂
как то сталкивался с подобной задачей, но не смог найти рационального решения! спасибо за статью!
Трындец, как же это все сложно…
Да уж, в английском языке всё гораздо проще)
Всегда юзал самописное. Юзаю в «количестве найдных документов» (найдено 10 документов).
function inclination($time,$arr)
{
$timex = substr($time, -1);
if ($time >=10 AND $time <=20) return $arr[2];
elseif ($timex == 1) return $arr[0];
elseif ($timex>1 AND $timex<5) return $arr[1];
else return $arr[2];
}
Забыл указать пример:)
$x = 5;
print inclination($x,array(‘лошадь’,’лошади’,’лошадей’)); //возвратит «лошадей»
Вот это тема!!! 🙂 Надо было её раньше найти.
Я бился над этой задачей в июле этого (2011) года.
Написал сначала один вариант… но он меня совершенно не устроил, тогда написал следующую функцию:
// номер, если 0, если 1, от 2 до 4 включ, от 5 до 9, от 11 до 14, неизвестное значение
function word_number($num, $word0, $word1, $word2_4, $word5_9, $word11_14, $word_n)
{
$order_1=$num-floor($num/10)*10;
$order_2=$num-floor($num/100)*100;
if($order_2>=11 && $order_2=2 && $order_1=5 && $order_1<=9) return ($word5_9);
else return ($word);
}
И такой вызов:
$txt_users=word_number($users,'участников','участник','участника','участников','участников','users');
Если $users=3, то присвоит "участника".
В одну строчку
declensions($users, array(«участник»,»участника»,»участников»));
function declensions($count, $variants)
{
return ($count > 10 && $count 1 AND $count%10 < 5) ? $variants[1] : $variants[2] ) );
}
Обрезалось прошлое сообщение
function declensions($count, $variants)
{
return ($count > 10 && $count 1 AND $count%10 < 5) ? $variants[1] :
$variants[2]));
}
вариант с геттекстом более верен
есть слова с двумя окончаниями, есть с четырьмя
поэтому геттекст более кошерен в этом плане
Alex, мою функцию здорово порезало 🙁
Мож сделаешь нормальное комметирование? Желательно с тегами, чтоб код можно было показать красиво.
А сама функция такая, кстати:
function word_number($num, $word0, $word1, $word2_4, $word5_9, $word11_14, $word_n){
$order_1=$num-floor($num/10)*10;
$order_2=$num-floor($num/100)*100;
if($order_2>=11 && $order_2=2 && $order_1=5 && $order_1<=9) return ($word5_9);
else return ($word);
}
Мож щас-то не порежет двиг блога… 🙂
Чувак, открой для себя http://pastie.org/ ))
Блин всё равно резануло(((
Моя функция работает норм с любыми числами и нормальными существительными.
По ссылке моего ника из этого сообщения пройти если, то можно увидеть работу функции в деле.
Там слева в сайдбаре, есть список популярных форумов. И в этом списке указано кол-во «участников», «тем» и «сообщений» на каждом форуме. Вот эти существительные указываются в тексте соответственно числительным.
Интересный сайтег), но хочется видеть читаемый код, именно в постах в блоге.
Alex, прикрутил бы приблуду-плагин для разметки и раскраски кода — было бы супер.
А пока я занят созданием скрипта для тысяч чатов 🙂 типо специализированного _http://cbox.ws
Но как появится свободное время, посмотрю другие записи блога 😉
Проще вот так: колдуем над словом РЕЦЕПТ
function getTermRecipes ($num)
{
$number = substr($num, -1);
if($number == 0) {$term = «ов»;}
if($number == 1 ) {$term = «»;}
if($number > 1 ) {$term = «а»;}
if($number > 4 ) {$term = «ов»;}
return $num.’ рецепт’.$term;
}
А подробнее можно посмотреть в этой статье: http://www.makannikov.ru/blog.php?id=19