Преобразование целого числа в письменной форме


Для моего домашнего задания, я должен создать класс, который преобразует целое число между 0 и 9999 в письменной форме. Например, 713 было бы написано как "семьсот тринадцатый".

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

Я перечислю только важные выдержки из .СРР и файлы.

Ниже представлены все статические члены номерами класса:

const char* Numbers::lessThan20[] = {
  "zero",     "one",      "two",      "three",   "four",    "five",
  "six",      "seven",    "eight",    "nine",    "ten",     "eleven",
  "twelve",   "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
  "eighteen", "nineteen"
};
const char* Numbers::over19[] = {
  "",       "",      "twenty", "thirty", "fourty", "fifty", "sixty", "seventy",
  "eighty", "ninety"
};
const char* Numbers::hundred  = "hundred";
const char* Numbers::thousand = "thousand";

И это моя функция для преобразования числа в строку:

std::string Numbers::print() const
{
  std::string text;
  int whole, remainder;

  remainder = this->number; // <- number is a member variable of the Numbers class

  whole = remainder / 1000;
  remainder %= 1000;

  if (whole > 0)
    text = text + lessThan20[whole] + " " + thousand + " ";

  whole = remainder / 100;
  remainder %= 100;

  if (whole > 0)
    text = text + lessThan20[whole] + " " + hundred + " ";

  if (remainder > 19)
  {
    whole = remainder / 10;
    remainder %= 10;
    text = text + over19[whole];
    if (remainder > 0)
      text = text + "-" + lessThan20[remainder];

  }
  else if (remainder > 0)
    text = text + lessThan20[remainder];

  return text;
}


1197
6
задан 12 декабря 2011 в 09:12 Источник Поделиться
Комментарии
4 ответа

Использование контейнеров STL

Предпочитают использовать с std::массив (если ваш компилятор поддерживает это или) СТД::вектор вместо необработанных массивов. Также, я бы рекомендовал использовать СТД::строка вместо сырьевой характер указатели.

const std::array<std::string, 20> Numbers::lessThan20 = {
"zero", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten", "eleven",
"twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
"eighteen", "nineteen"
};
const std::array<std::string, 10> Numbers::over19 = {
"", "", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy",
"eighty", "ninety"
};
const std::string Numbers::hundred = "hundred";
const std::string Numbers::thousand = "thousand";

Крайние Случаи

В настоящее время нет обработки для особых случаев. Если число равно 0 , он будет возвращать пустую строку вместо "ноль". Числа больше или равна 20000 будет привести к доступа. Таким образом, цифры слишком большие должны быть правильно обработаны. Эти случаи можно проверить в начале функции.

Еще пара незначительных моментов: я хотел бы удалить строку инт все, остальные и объявите переменные, когда они инициализируются. Это позволит уменьшить объем переменных и не оставлять их инициализации. Кроме того, предпочитаю текст += ... за текст = текст + .... Это более понятно, что вы не добавляя и меньше набирать. Наконец, я бы порекомендовал всегда использовать фигурные скобки, даже если имеется только одно заявление.

Вот ваша функция с моими рекомендациями:

std::string Numbers::print() const
{
int remainder = this->number; // <- number is a member variable of the Numbers class
if(remainder == 0)
{
return lessThan20[0];
}

if(remainder >= 20000)
{
// handle this case
}

int whole = remainder / 1000;
remainder %= 1000;

std::string text;
if (whole > 0)
{
text += lessThan20[whole] + " " + thousand + " ";
}

whole = remainder / 100;
remainder %= 100;

if (whole > 0)
{
text = text + lessThan20[whole] + " " + hundred + " ";
}

if (remainder > 19)
{
whole = remainder / 10;
remainder %= 10;
text = text + over19[whole];
if (remainder > 0)
{
text = text + "-" + lessThan20[remainder];
}
}
else if (remainder > 0)
{
text = text + lessThan20[remainder];
}
return text;
}

10
ответ дан 13 декабря 2011 в 12:12 Источник Поделиться

const char* Numbers::lessThan20[] = {
"zero", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten", "eleven",
"twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
"eighteen", "nineteen"
};
const char* Numbers::over19[] = {
"", "", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy",
"eighty", "ninety"
};

За 19-это немного странное имя для этого массива. Возможно, есть лучше

const char* Numbers::hundred  = "hundred";
const char* Numbers::thousand = "thousand";

std::string Numbers::print() const
{
std::string text;
int whole, remainder;

remainder = this->number; // <- number is a member variable of the Numbers class

Он сделал бы для меня больше смысла, чтобы сдать номер в качестве параметра.

  whole = remainder / 1000;

Я бы назвал здесь целые тысячи , чтобы сделать код легче следовать

  remainder %= 1000;

if (whole > 0)
text = text + lessThan20[whole] + " " + thousand + " ";

Некоторым учителям не нравится вам, не поставив скобки вокруг вашего заявления. Я бы тоже справиться с этим по-разному. Как мне кажется, есть параллель с тем, как цифры обрабатываются. Так что я бы сделать что-то вроде:

if( number >= 1000 )
return threeDigitNumber(number / 1000) + " thousand " + threeDigitNumber(number % 1000)
else
return threeDigitNumber(number)

Я думаю, что будет просто код, он также будет работать с некоторыми крупных дел, то ваш код делает.

  whole = remainder / 100;
remainder %= 100;

Опять же я бы назвал это сотни для ясности, не все

  if (whole > 0)
text = text + lessThan20[whole] + " " + hundred + " ";

if (remainder > 19)
{
whole = remainder / 10;
remainder %= 10;
text = text + over19[whole];
if (remainder > 0)
text = text + "-" + lessThan20[remainder];

}
else if (remainder > 0)
text = text + lessThan20[remainder];

Я не люблю прыгать между скобками и без бандажа. Я бы поставил брекеты во второй раз за консистенции.

  return text;
}

5
ответ дан 13 декабря 2011 в 12:12 Источник Поделиться

Дизайн ваш алгоритм не очень растяжимо. Есть система для обработки этого. Например, сто пятьдесят миллионов шестьдесят три тысячи пятьсот семьдесят шесть может быть сделано довольно просто, если вы повторно организовать, как ваш алгоритм работает немного. Как это так, нужно особый случай все.

#include <iostream>
#include <stdexcept>

namespace {
void less_than_100_to_english(::std::ostream &os, unsigned int num)
{
const char *needed_space = "";
static const char * const under_20[20] = {
"zero", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten", "eleven",
"twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
"eighteen", "nineteen" };
static const char * const tens[10] = {
"", "", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy",
"eighty", "ninety" };

if (num >= 100) {
needed_space = " ";
os << under_20[num / 100] << " hundred";
}
num %= 100;
if ((num != 0) && (num < 20)) {
os << needed_space << under_20[num];
} else {
os << needed_space << tens[num / 10];
num %= 10;
if (num != 0) {
os << ' ' << under_20[num];
}
}
}

void number_to_english(::std::ostream &os, unsigned int num, unsigned int multiplier)
{
const char * const multipliers[] = {
"", "thousand", "million", "billion", "trillion", "quadrillion",
"quintillion", "sextillion", "septillion", "octillion" };
const char *needed_space = "";

if (multiplier >= (sizeof(multipliers) / sizeof(multipliers[0]))) {
throw ::std::overflow_error("Number too big to print in English.");
}
if (num >= 1000) {
number_to_english(os, num / 1000, multiplier + 1);
needed_space = " ";
}
const unsigned int part = num % 1000;
if (part != 0) {
os << needed_space;
less_than_100_to_english(os, part);
if (multiplier > 0) {
os << ' ' << multipliers[multiplier];
}
}
}
} // anonymous namespace

void number_to_english(::std::ostream &os, unsigned int num)
{
if (num == 0) {
os << "zero";
} else {
number_to_english(os, num, 0);
}
}

int main()
{
using ::std::cout;
number_to_english(cout, 1535201229u);
cout << '\n';
number_to_english(cout, 3115654019u);
cout << '\n';
number_to_english(cout, 0);
cout << '\n';
number_to_english(cout, 1);
cout << '\n';
return 0;
}

4
ответ дан 13 декабря 2011 в 01:12 Источник Поделиться

Я не могу комментировать (не хватает рэп, я думаю), но одна незначительная вещь, которую я заметил заключается в том, что если входное число делится на 100 или 1000, это будет иметь место в конце напечатанной строкой. Пример: 2000 -> "две тысячи "

Если это даже является проблемой, вы можете либо:


  • обрезать пробельные символы из строки

  • добавление пробела в конец текста в любом месте вы добавляете к нему, а затем удалить последний символ (пробел) перед возвращением

2
ответ дан 12 декабря 2011 в 10:12 Источник Поделиться