LINUX.ORG.RU

 Числа прописью

 , ,


0

1

Написал такую вот библиотечку на scala.  Умеет превращать 123 в сто двадцать три, 12345 => сто двадцать три рубля сорок пять копеек.

Может пригодится кому нибудь... Если какие нибудь дельные замечания по коду - буду только рад, совсем недавно я программированием занимаюсь...

No licence, no warranty))

И всех с праздником!

123 в сто двадцать три, 12345 => сто двадцать три рубля сорок пять копеек

Боюсь спросить, но сделаю:
а 100500 во что превратит?
Может всё-таки стоило парсить какой-то разделитель (запятая-точка) чтобы из 100 получалось 100 тугриков, а из 100,15 получалось 100 тугриков 15 мунгу?

Stahl ★★☆ ()
Ответ на: комментарий от Stahl

На входе ожидается сумма в копейках. Возможно стоит добавить поддержку float и double. Для моих целей этого не требовалось.

100500 => одна тысяча пять рублей ноль копеек.

kardapoltsev ★★★★ ()
Ответ на: комментарий от anonymous

А я ожидал больше подобных ответов... Хм. Неужели никто больше не хочет попробовать поострить?))

kardapoltsev ★★★★ ()

Интересен принцип. Почему 123 - сто двадцать три, а не 1 рубль 23 коп? И почему рубли, а не тугрики?

И почему не заюзать что-нибудь готовое на жабе?

Kadi ()
Ответ на: комментарий от Kadi

Посмотри по ссылке примеры использования. Там вроде понятно почему разные вещи получаются.

123 => сто двадцать три - это общий случай. А 123 => рубль двадцать три копейки - нужно было мне по работе. У меня все суммы хранятся в копейках.

Почему не использовал готовое на жабе - с ходу ничего полностью подходящего не нашлось.

kardapoltsev ★★★★ ()
Ответ на: комментарий от kardapoltsev

Значит нужно запилить на жабе. Странно как то, недавно занимаешься «программированием» и при этом фигачишь либы на Scala.

anonymous ()

Я как бы стесняюсь спросить, но зачем. Я таких библиотек видел уже «туеву хучу». Зачем очередной велосипед? Или просто практика в кодинге? Но все же поздравляю с реализацией. Надо будет тексты взглянуть... все же способ интересен. Спасибо за проделанную работу.

( q9 - c возвращением)

ivanlex ★★★★★ ()
Ответ на: комментарий от Anret

Я как раз подумал что неплохо бы

«1/2» => одна вторая

Как будет вечерок свободный - сделаю. Или что подразумевалось под

еще какие-нибудь числа

?

kardapoltsev ★★★★ ()
Ответ на: комментарий от ivanlex

Просто практика) Я понимаю что это еще в школе как домашнее задание пишут.

Надо будет тексты взглянуть...

Именно замечаний по текстам и хочется больше всего.

kardapoltsev ★★★★ ()
Ответ на: комментарий от ivanlex

Я таких библиотек видел уже «туеву хучу».

Сишную не подскажешь?

Eddy_Em ☆☆☆☆☆ ()

кстати, а время там есть? типа на входе 14*24*3600, на выходе «четырнадцать дней». Нужная фича.

drBatty ★★ ()
Ответ на: комментарий от drBatty

Я как-то заморачивался. Думал, за полчасика набросаю, но не получилось. Сложность была с кластеризацией чисел — преобразовать, например, 123456789012 в «сто двадцать три миллиарда четыреста пятьдесят шесть миллионов семьсот восемьдесят девять тысяч двенадцать». Начал разбивать на тройки, но пришло время обеда, а после обеда принялся за другой велосипед. Забросил.

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Eddy_Em

Сложность была с кластеризацией чисел — преобразовать, например, 123456789012 в «сто двадцать три миллиарда четыреста пятьдесят шесть миллионов семьсот восемьдесят девять тысяч двенадцать». Начал разбивать на тройки, но пришло время обеда, а после обеда принялся за другой велосипед. Забросил.

ничего сложного, но писать да, долго. я рабочий день ковырялся. Да, там в цикле делим на 1000, и получаем единицы, тысячи, миллионы и т.д. Потом выводим в обратном порядке. Рекурсивно например.

drBatty ★★ ()
Ответ на: комментарий от drBatty

Вот у меня тогда и была проблема с этим обратным порядком. А сейчас придумал: можно сразу же, получая остаток от деления на тысячу, заполнять им структуру-список с припиской текущего порядка. Потом выводить в обратном порядке.

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Eddy_Em

можно. но мне проще было заюзать рекурсию. Т.е. делим на 1000, получаем единицы, но не печатаем, а входим в рекурсию, и опять делим. Пока не будет <1000. Вот тогда печатаем и выходим из рекурсии.

drBatty ★★ ()
Ответ на: комментарий от drBatty

Пока нет. Но спасибо за идею, возможно и дни появятся)

kardapoltsev ★★★★ ()
Ответ на: комментарий от Eddy_Em

преобразовать, например, 123456789012 в «сто двадцать три миллиарда четыреста пятьдесят шесть миллионов семьсот восемьдесят девять тысяч двенадцать»

Если без склонений, то что-то вроде

const char *ns[3][9] = {
    { "один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять" },
    { "десять", "двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят", "семьдесят", "восемьдесят", "девяносто" },
    { "сто", "двести", "триста", "четыреста", "пятьсот", "шестьсот", "семьсот", "восемьсот", "девятьсот" }
};

const char *ns_exc[9] = {
    "одиннадцать", "двенадцать", "тринадцать", "четырнадцать", "пятьнадцать", "шестнадцать", "семьнадцать", "восемнадцать", "девятнадцать"
};

const char *ns_big[4] = {
    "тысяча", "миллион", "миллиард", "триллион" // ...
};

void sound(unsigned long n)
{
    if (n == 0) return;

    if (n > 10 && n < 20) {
        printf("%s ", ns_exc[n - 11]);
        return;
    }

    if (n < 1000) {
        unsigned long e = floor(log10(n));
        unsigned long p = floor(pow(10, e));
        printf("%s ", ns[e][n / p - 1]);
        sound(n % p);
    } else {
        unsigned long e = floor(log(n) / log(1000));
        unsigned long p = floor(pow(1000, e));
        sound(n / p);
        printf("%s ", ns_big[e - 1]);
        sound(n % p);
    }
}

вроде бы работает.

quasimoto ★★★★ ()
Ответ на: комментарий от Eddy_Em

С полноценными склонениями это сразу с динамическими строками в куче - неохота. Можно захардкодить склонения конкретных числительных:

const char *ns_big[3][10] = {
    { "тысяч", "тысяча", "тысячи", "тысячи", "тысячи", "тысяч", "тысяч", "тысяч", "тысяч", "тысяч" },
    { "миллионов", "миллион", "миллиона",  "миллиона",  "миллиона", "миллионов",  "миллионов",  "миллионов",  "миллионов",  "миллионов" },
    { "миллиардов", "миллиард", "миллиарда", "миллиарда", "миллиарда", "миллиардов", "миллиардов", "миллиардов", "миллиардов", "миллиардов" }
};

unsigned sound(unsigned long n, bool next_female)
{
    if (n == 0) {
        return 0;
    } else if (n > 10 && n < 20) {
        printf("%s ", ns_exc[n - 11]);
        return 0;
    } else if (n < 1000) {
        unsigned long e = floor(log10(n));
        unsigned long p = floor(pow(10, e));
        if (next_female && n == 1) printf("одна ");
        else if (next_female && n == 2) printf("две ");
        else printf("%s ", ns[e][n / p - 1]);
        return e == 0 ? n : sound(n % p, next_female);
    } else {
        unsigned long e = floor(log(n) / log(1000));
        unsigned long p = floor(pow(1000, e));
        printf("%s ", ns_big[e - 1][sound(n / p, e == 1)]);
        return sound(n % p, false);
    }
}
123456789012
// сто двадцать три миллиарда четыреста пятьдесят шесть миллионов семьсот восемьдесят девять тысяч двенадцать 
121123
// сто двадцать одна тысяча сто двадцать три 
122321
// сто двадцать две тысячи триста двадцать один 
100500
// сто тысяч пятьсот
quasimoto ★★★★ ()
Ответ на: комментарий от anonymous

Значит нужно запилить на жабе.

нет, не нужно ;)

недавно занимаешься «программированием» и при этом фигачишь либы на Scala.

совершенно нормальная практика. хотя да, «быдлокодить» некоторым привычнее ;)

Rastafarra ★★★★ ()
Ответ на: комментарий от quasimoto

с динамическими строками в куче

Хотя с VLA из C99 можно сделать char new_str[strlen(str) + 2] и потом склоняй_числительное_по_роду(&new_str, str, gender) или количеству(&new_str, str, n).

quasimoto ★★★★ ()
Ответ на: комментарий от kardapoltsev

Именно замечаний по текстам и хочется больше всего.

а кстати весьма :)

Rastafarra ★★★★ ()
Ответ на: комментарий от quasimoto
{ "миллионов", "миллион", "миллиона",  "миллиона",  "миллиона", "миллионов",  "миллионов",  "миллионов",  "миллионов",  "миллионов" }

А где «миллионе», «миллиону», «миллионах» и «миллионам»? =)

korvin_ ★★★★★ ()
Ответ на: комментарий от korvin_

А без контекста не понятно какой там падеж, тогда это должно быть уже sound(number n, enum род род_следующей_формы, enum падеж падеж_этого_числительного_в_данном_контексте) и sound(n, род, падеж) == map((слово => склонить(слово, падеж)), sound(n, род, именительный)). Если продолжать расписывать таблички вместо функций склонения, то с учётом склонений по числам, родам и падежам это будет уже char *ns[3][10][3][6], char *ns_exc[9][6] и char *ns_big[][10][6].

quasimoto ★★★★ ()
Ответ на: комментарий от quasimoto

ns[3][10][3][6]

То есть отображение порядок x номер x род x падеж -> слово.

ns_exc[9][6]

номер x падеж -> слово.

ns_big[][10][6]

порядок x склонение_по_числу x падеж -> слово.

Всё в data segment и O(1), с функциями придётся возиться с анализом слов при выполнении, памятью и т.п.

quasimoto ★★★★ ()

А теперь еще она умеет дроби. Например

«1/2» => одна вторая

И все таки. Неужто никто не поругает мой код? Очень хочется конструктивной критики

kardapoltsev ★★★★ ()
Ответ на: комментарий от quasimoto

Да, есть такое. Можно конечно, только пока вроде нужды особой нет во всех падежах.

kardapoltsev ★★★★ ()

Вот может кто тут подскажет... Мне думается можно как то красивее чем

x match {
case a if Set(1,2,3,4,5) contains a => do smth
case _ =>
}

kardapoltsev ★★★★ ()
Ответ на: комментарий от ivanlex

Как не как человек полезную вещь сделал.Велосипеды всегда были и будут , но некоторые будут из них выделятся тюнингом и громким клаксоном. p.s. Ещё пока не вернулся Score: 40 до толксов ещё 10-15 дней

q9 ()
Ответ на: комментарий от quasimoto

А склонения?! Видел много библиотек, но почему-то склонения учитываются только в финансовых библиотеках. А такие обычно с закрытым исходным кодом.

ivanlex ★★★★★ ()
Ответ на: комментарий от quasimoto

Вот, уже вижу склонения, хотя это не склонения самих чисел. Но да, библиотека с полноценными склонениями будет адовой. Ведь еще один/одного два/двух и прочее.

ivanlex ★★★★★ ()

Конструктивная критика.

Если библиотека будет не только числовой, но и денежной, при этом не завязанной на определенную валюту, при этом что бы поддерживала склонения - тогда она не будет уступать коммерческим библиотекам. Ну и она должна быть кроссплатформенной (а наличие исходников - огромный плюс).

По поводу наименования валют, их ведь можно держать во внешних ресурсах. Что бы была возможность добавлять именования валют не пересобирая библиотеку. Добавить дополнительный параметр, с указанием кода валюты, например «RUR», а в файле с ресурсами кодом RUR помечены рубли и копейки. Библиотека становиться универсальной, ведь в будущем любой пользователь библиотеки сможет добавить свой код с наименованием валюты (и вариациями склонений), без доработки самой библиотеки.

А вообще - автору респект. Пусть всего лишь практика, главное, что бы была полезна.

ivanlex ★★★★★ ()
Ответ на: комментарий от q9

Полезную - не спорю. И для него плюс - практика, и для окружающих. Велосипедов вокруг множество, и плохо, если автор остановится на данном этапе. Автору респект, особенно, если он сделает свою библиотеку не уступающей комерческим аналогам. Да даже если не сделает - все равно молодец. Хорошо, что он интересуется мнением других, и адекватно реагирует на критику. Молодец.

ivanlex ★★★★★ ()
Ответ на: комментарий от ivanlex

Вынести валюту из кода - хороший совет, обязательно воспользуюсь.

А вот склонения - если будет свободное время... Русский язык такой весь исключительный))

kardapoltsev ★★★★ ()
Ответ на: комментарий от ivanlex

хотя это не склонения самих чисел

Решается дописыванием таблички до... более тысячи вариантов :) Либо заменой таблиц на функции склонения.

quasimoto ★★★★ ()
Ответ на: комментарий от quasimoto

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

ivanlex ★★★★★ ()
Ответ на: комментарий от kardapoltsev

А вот склонения - если будет свободное время... Русский язык такой весь исключительный))

Ага. И греческий с латынью тоже. Я не говорю о множестве других языков, где тоже есть склонения.

З.Ы. Попробуй переписать паттерн-матчинг через обычный if. У тебя там новое множество создается на каждой проверке, что совсем не комиль-фо, т.е. не по фен-шую.

dave ★★★★★ ()
Ответ на: комментарий от dave

Я как раз об этом спрашивал выше... Но по другому я могу только

x match {
case a if (a==1 || a==2 || a==3 || a ==5) => do smth
case _ =>
}

Так лучше что ли?

kardapoltsev ★★★★ ()
Ответ на: комментарий от kardapoltsev

В таком коде паттер-матчинг не нужен. Ведь ты не на Nemerle программируешь, где даже if определяют через match :)

dave ★★★★★ ()
Ответ на: комментарий от dave

А почему не использовать? В примере выше ясно, там один случай. Потому что мне писать было лень. Но если случаев 3 и более я использовал «pattern matching». Есть резонные причины использовать if ?

kardapoltsev ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.