Переводим целочисленную запись в письменную или как сделать из 109 сто девять

в 8:43, , рубрики: ruby, Алгоритмы, метки:
Как все начиналось

Здравствуйте, хаброобщество.

Я молодой, начинающий программист в недавнем прошлом решил перейти на новый, для меня, язык программирования Ruby. Учить принялся по учебнику «Учись программировать» автора Криса Пайна. И в очередной главе, посвященной методам, наткнулся на интересную задачу:

Думаю, было бы очень полезно привести ещё один пример метода. Мы назовём его englishNumber. Он будет принимать число, например, 22, и возвращать его английское название (в данном случае, строку 'twenty-two'). Для начала, пусть он работает только с целыми числами от 0 до 100.

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

Шаг первый, идея

Для примера возьмем число 1234567. Как известно нам еще со школьной скамьи любое число состоит из единиц, десятков, сотен, тысяч, десятков тысяч и тд. Между ними есть что то общее не так ли? Теперь вооружимся примером. Вот смотрите, есть сотни — 5 и есть сотни тысяч — 2 также есть десятки 6 и десятки тысяч 3, теперь когда у нас остались только единицы 7 им в соответствии имеются также единицы тысяч 4. То есть при увеличении числа единицы, десятки и сотни остаются неизменными, и очевидным становится то что изменяется лишь степень тысячи (тысяча, миллион, миллиард ...).
Что это значит для нас программистов? А значит это все то, что в памяти будем хранить массивы единиц («один»,«два»,… ,«девятнадцать»), десятков («двадцать», «тридцать»,…, «девяносто»), сотен («сто»,«двести»,… «девятьсот») и числа степеней тысячи («тысяча»,«миллион»,«миллиард», ...) Очевидно есть не понимания почему единицы от 1-го до 19-ти и где же ноль, рекомендую читать далее…

Шаг второй, как мне этим воспользоватся

Да верно идея есть, а что дальше? Элементарно, поделим число на тройки разделив их *, начиная с последнего символа, 1*234*567. Теперь вместо звездочек проставим степени тысячи, также записав их в квадратные скобки, 1[2]234[1]567. Далее все становится все просто вместо единиц пишем единицы, вместо десятки записываем десятки и тд., а вместо степеней тысячи запишем принадлежащее ему число.

Выйдет следующее: один миллион двести тридцать четыре тысяча пятьсот шестьдесят семь

Шаг второй, нюансы

  • Из примера видно один ярко выраженный нюанс у нас вышло четыре тысяча, а не четыре тысячи.
  • И второй нюанс когда десятков больше двух все ясно 21 двадцать и один, 56 пятьдесят и шесть, но возьмем 17 это ведь не десять и сем, а семнадцать, стоит задуматься не так ли ?
  • Ах да ноль как же без него, ведь за него ни где и речи не шло, здесь немного проще ноль внутри числа не произносится (пишется), остается лишь само число ноль, так что это тоже необходимо учесть.
Шаг третий, реализация метода numberToString number

Далее я предлагаю свою реализацию метода с максимальной степенью тысячи 7 (реализация склонений в данном методе не предусмотрена)

def numberToString number
  
  arrayTo20 = ['',' один',' два',' три',' четыре',' пять',' шесть',
                ' семь',' восемь',' девять',' десять',' одиннадцать',
                  ' двенадцать',' тринадцать',' четырнадцать',' пятнадцать',
                    ' шестнадцать',' семнадцать',' восемнадцать',' девятнадцать']
  arrayTo100 = ['',' двадцать',' тридцать',' сорок',' пятьдесят',' шестьдесят',
                  ' семьдесят',' восемьдесят',' девяносто']
  arrayTo1000 = ['',' сто',' двести',' триста',' четыреста',' пятьсот',
                    ' шестьсот',' семьсот',' восемьсот',' девятьсот']
  array1000 = ['',' тысяча',' миллион',' миллиард',' биллион',' биллиард',' триллион']

  #число с которым выполняются действия
  myNumber = number
  #переменная для контроля обработанных троек
  stepCountIndex = 0
  #переменная для хранения степени тысячи
  thousendIndex = 0;
  #общая длинна числа
  myNumberLength = myNumber.to_s.length
  #признак ноля
  if ((myNumberLength == 1) and (myNumber == 0))
    return resultNumberText = 'ноль'
  end
  
  resultNumberText = ''
  
    while (myNumberLength > stepCountIndex)
        
        #строка отвечает за вывод текста степени тысячи
        resultNumberText = array1000[thousendIndex] + resultNumberText
        
        #временная переменная для хранения последних троек числа
        tempNumber = myNumber % 1000
         #убираем три последних элемента
        myNumber   = myNumber / 1000
        
        #временная переменная для хранения длинны отобранной тройки
        tempNumberLength = tempNumber.to_s.length
        #временная переменная для хранения символьного описания тройки
        tempNumberText = ''
        
        #проверяем трёхзначное ли число ?
        if (tempNumberLength == 3)
            tempNumberText = arrayTo1000[tempNumber / 100]
            #после обработки сотен нас интересуют десятки
            tempNumberLength = 2;
        end
        #проверяем двухзначное ли число ?
        if (tempNumberLength == 2)
            #проверяем меньше ли число 20-ти ?
            if(tempNumber%100 < 20)
                tempNumberText = tempNumberText + arrayTo20[tempNumber%100]
                #обработаны последние два числа
                tempNumberLength = 0
            #иначе обрабатываем только десятки
            else
                tempNumberText = tempNumberText + arrayTo100[(tempNumber%100)/10 - 1]
                #после обработки десятков нас интересуют единицы
                tempNumberLength = 1
            end
        end
        #проверяем однозначное ли число ?
        if (tempNumberLength == 1)
            tempNumberText = tempNumberText + arrayTo20[tempNumber%10]
        end
        
        #увеличиваем степень тысячи
        thousendIndex = thousendIndex + 1
        #увеличение количества обработанных троек
        stepCountIndex = stepCountIndex + 3
        #формирование строки
        resultNumberText = tempNumberText + resultNumberText
        
    end
  
  return resultNumberText
end

Всем спасибо, Ваши вопросы, предложения?

Автор: by_better

Источник

Поделиться

* - обязательные к заполнению поля