Chris Maunder Ответов: 8

Задача кодирования: преобразовать целое число в предложение.


Задача на этой неделе, как всегда, проста.

Учитывая 64-битное целое число, создайте метод, который преобразует значение в его устный эквивалент.

Например: 1,203 приведет к "тысяче, двумстам и трем"

Возможности сделать это излишне запутанным велики. Давай! ..

Что я уже пробовал:

Упрощение моей жизни.

Победителем прошлой недели стал Graeme_Grant, хотя решения excel были чертовски близки к этому. Отправьте Шону свои данные и выиграйте приз!

Patrice T

"хотя решения excel были чертовски близки."
Нажать. почти получилось :-)

Graeme_Grant

Спасибо, Крис. Надеюсь, я правильно связалась с Шоном. :)

Chris Maunder

Ты ведь все еще в Мельбурне, верно? Я буду там через неделю, если вы хотите кофе (или, может быть, что-нибудь холодное)

PIEBALDconsult

Он хочет футболку...

Graeme_Grant

Немного подвинулись... Прошло много времени с тех пор, как я в последний раз проверял свой профиль... пришло время обновить его. [редактировать] Похоже, я держал его в курсе. :)

Chris Maunder

А-а, похоже, мне придется только лениво помахать рукой, когда я пролетаю над ними по пути на юг. В следующий раз!

Graeme_Grant

:) ... мог бы бросить его на почте (GPO) в Мельбурне, когда вы здесь, и сохранить таким образом... ;)

PIEBALDconsult

Это одна из тем, которые я люблю ненавидеть.

https://www.codeproject.com/Lounge.aspx?msg=4667570

https://www.codeproject.com/script/Membership/View.aspx?mid=2587207&fid=252480&select=4878556

PIEBALDconsult

Я просмотрел код, который написал осенью 2013 года, и ему не хватает только возможности ставить запятые и "и" ; я добавлю эту функцию, но код уже занимает десять страниц и не подходит в качестве решения QA, поэтому я думаю, что Совет в порядке...

Система.Приставка.WriteLine (1203.Метод toString&ЛТ;пегий.типов.shortscale&ГТ;() ) ;
Тысяча Двести Три

Kornfeld Eliyahu Peter

Как сказать 18,446,744,073,709,551,615? Или даже 9,223,372,036,854,775,807?
Разве 64 бит-это не большой размер?

Graeme_Grant

восемнадцать квинтриллионов, четыреста сорок шесть квадриллионов, семьсот сорок четыре триллиона, семьдесят три миллиарда, семьсот девять миллионов, пятьсот пятьдесят одна тысяча, шестьсот пятнадцать

Graeme_Grant

Как насчёт:

Двадцать восемь Миллиниллионов, шестьсот тридцать восемь Нонгентиллионов, Девятьсот три Октингентиллионов, Девятьсот восемнадцать Септингентиллионов, Четыреста семьдесят четыре Сесцентиллиона, Девятьсот сорок восемь Кингентиллионов, Семьсот семьдесят один Квадрингентиллион, восемь сто пятьдесят три трецентиллиона, девятьсот дуцентиллион, семьсот восемьдесят девять нонагинтацентиллион, шестьсот октоджинтацентиллион, сто семьдесят шесть септуагинтацентиллион, восемьсот тринадцать секагинтацентиллион, триста семьдесят четыре квинквагинтацентиллион, пятьсот шестьдесят четыре квинквагинтацентиллион , шестьсот семьдесят два тригинтацентиллиона, семьсот восемьдесят семь Унвигинтициентиллион, девятьсот пять виджинтициентиллион, пятьсот сорок девять ундецициентиллионов, девятьсот пятьдесят один децициентиллион, восемьдесят семь тресентиллион, четыреста восемьдесят восемь Дуоцентиллион, одиннадцать унсентиллионов, триста восемьдесят два сентиллиона, сорок девять нонагинтиллионов, триста шестьдесят один октогинтиллион, четыреста семьдесят семь септуагинтиллионов, девятьсот семь сексагинтиллионов, четыреста тридцать два квинквагинтиллиона, четыреста шестьдесят восемь квадрагинтиллионов, семьдесят семь новентригинтиллионов , двести семьдесят пять октотригинтиллионов, девятьсот девятнадцать септентригинтиллионов, четыреста тридцать девять сестригинтиллионов, восемьдесят шесть квинкватригинтиллионов, сто сорок пять кваттуортригинтиллионов, семьсот двадцать пять трестригинтиллионов, двести шестьдесят восемь Дуотригинтиллион, пятьсот девяносто девять унтригинтиллионов, семьсот двадцать семь тригинтиллионов, пятьсот девять новемвигинтиллионов, двести шестьдесят один октовигинтиллион, шестьсот девять сентябрьвинтиллионов, пятьсот сорок пять сесвигинтиллионов, сто девяносто -один квинквавинтиллион, девятьсот тридцать четыре кваттуорвигинтиллион, триста сорок два тресвигинтиллиона, триста семьдесят шесть дуовигинтиллионов, девяносто шесть унвигинтиллионов, сто шесть виджинтиллионов, четыреста двадцать шесть ноябемдециллионов, триста двадцать семь октодециллионов, восемьсот двенадцать сентендециллионов, девятьсот девятьсот девяносто девять. двадцать шесть секдециллионов, двести шестьдесят два квиндециллионов, восемьдесят шесть кваттуордециллионов, восемьсот тридцать четыре тредециллионов, девятьсот семьдесят семь дуодециллионов, восемьдесят семь ундециллионов, восемьсот пятьдесят восемь дециллионов, шестьсот и восемьдесят нониллионов, триста двадцать два октиллиона, двести сорок один септиллион, пятьсот сорок шесть секстиллионов, сто тринадцать квинтриллионов, пятьсот четырнадцать квадриллионов, триста восемьдесят три триллиона, сто и сорок три миллиарда пятьсот один миллион пятьсот девятнадцать тысяч сто пятьдесят один

-- или --

28,638,903,918,474,948,771,853,900,789,600,176,813,374,560,672,787,905,549,951,087,488,011,382,049,361,477,907,432,468,077,
275,919,439,086,145,725,268,599,727,509,261,609,545,191,934,342,376,096,106,426,327,812,926,262,086,834,977,087,858,680,
322,241,546,113,514,383,143,501,519,151

Kornfeld Eliyahu Peter

Это не совсем то, что я имел в виду... Но, вы когда-нибудь говорите! такое количество?
У нас есть какой-то код для печати платежных ваучеров, которые тоже должны содержать сумму в цифрах и словах, но никогда даже не доходили до миллионов...

Graeme_Grant

Не практично, я знаю, но было интересно посмотреть, как этот метод работает с любым размером числа... У меня есть округленные версии в моем решении. :)

PIEBALDconsult

Я использую BigInteger в своем. Мухахаха...

Richard Deeming

Попробуйте это с помощью Число Грэма [^]. :Д

Graeme_Grant

Отличное название для номера. ;)

8 Ответов

Рейтинг:
60

Graeme_Grant

Вы не указали диапазон int для тестирования или режим масштабирования[^]. Еще в школьные годы, а миллиард[^] не был таким же, как некоторые другие части мира, однако, к счастью, мир использует американский стандарт.

Итак, вот моя версия, которая поддерживает как положительные, так и отрицательные Инты от Int16 прямо до конца UInt64 (теперь тоже BigInteger); короткие, "традиционные" британские и длинные масштабные числа; полностью масштабируемые как независимый размер значения; формальное и неформальное округление; и могут быть сделаны для поддержки любого языка без каких-либо изменений в ядре.

ОБНОВЛЕНИЕ: Добавлена поддержка BigIntegers &" Tradition " British english numbers... Также 4 уровня нормального и неформального округления.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;

namespace NumToWords
{
    class Program
    {
        static void Main(string[] args)
        {
            Int64 testMin = Int64.MinValue;
            Int64 testMax = Int64.MaxValue;
            UInt64 testUMax = UInt64.MaxValue;
            Int64 testQMin = testMin / 1000;
            Int64 testQMax = testMax / 1000;
            UInt64 testQUMax = testUMax / 1000;

            BigInteger testNegBig = -BigInteger.Pow(testQUMax, 13);
            BigInteger testBig = BigInteger.Pow(testQUMax, 13);

            int[] tests =
                {
                  -1,
                  0,
                  1,
                  11,
                  101,
                  1234,
                  10001,
                  100001,
                  1100101,
                  10110011,
                  100011011,
                  1001010101,
                  -1001010101
                };

            Console.WriteLine("SHORT SCALE NUMBERS");
            Console.WriteLine("===================\r\n");
            for (int i = 0; i < tests.Length; i++)
                ShowResult(tests[i]);

            ShowResult(testQMin);
            ShowResult(testMin);
            ShowResult(testQMax);
            ShowResult(testMax);
            ShowResult(testQUMax);
            ShowResult(testUMax);
            ShowResult(testNegBig);
            ShowResult(testBig);

            Console.WriteLine();
            Console.WriteLine("TRADITIONAL BRITISH SCALE NUMBERS");
            Console.WriteLine("=================================\r\n");
            for (int i = 0; i < tests.Length; i++)
                ShowResult(tests[i], ScaleType.TraditionalBritish);

            ShowResult(testQMin, ScaleType.TraditionalBritish);
            ShowResult(testMin, ScaleType.TraditionalBritish);
            ShowResult(testQMax, ScaleType.TraditionalBritish);
            ShowResult(testMax, ScaleType.TraditionalBritish);
            ShowResult(testQUMax, ScaleType.TraditionalBritish);
            ShowResult(testUMax, ScaleType.TraditionalBritish);
            ShowResult(testNegBig, ScaleType.TraditionalBritish);
            ShowResult(testBig, ScaleType.TraditionalBritish);

            Console.WriteLine();
            Console.WriteLine("LONG SCALE NUMBERS");
            Console.WriteLine("==================\r\n");
            for (int i = 0; i < tests.Length; i++)
                ShowResult(tests[i], ScaleType.Long);

            ShowResult(testQMin, ScaleType.Long);
            ShowResult(testMin, ScaleType.Long);
            ShowResult(testQMax, ScaleType.Long);
            ShowResult(testMax, ScaleType.Long);
            ShowResult(testQUMax, ScaleType.Long);
            ShowResult(testUMax, ScaleType.Long);

            ShowResult(testNegBig, ScaleType.Long);

            ShowResult(testBig, ScaleType.Long);

            Console.WriteLine("-- Press any key to exit --");
            Console.ReadKey();

        }

        private static void ShowResult(Int16 value, ScaleType numberScale = ScaleType.Short)
        {
            Console.WriteLine(seperatorLine);
            Console.WriteLine($"VALUE: {value:N0}\r\nTEXT:  {value.ToWords(numberScale)}\r\n");
        }

        private static void ShowResult(UInt16 value, ScaleType numberScale = ScaleType.Short)
        {
            Console.WriteLine(seperatorLine);
            Console.WriteLine($"VALUE: {value:N0}\r\nTEXT:  {value.ToWords(numberScale)}\r\n");
        }

        private static void ShowResult(Int32 value, ScaleType numberScale = ScaleType.Short)
        {
            ShowResult((Int64)value, numberScale);
        }

        private static void ShowResult(UInt32 value, ScaleType numberScale = ScaleType.Short)
        {
            ShowResult((UInt64)value, numberScale);
        }

        private static void ShowResult(Int64 value, ScaleType numberScale = ScaleType.Short)
        {
            ShowResult((BigInteger)value, numberScale);
        }

        private static void ShowResult(UInt64 value, ScaleType numberScale = ScaleType.Short)
        {
            ShowResult((BigInteger)value, numberScale);
        }

        private static void ShowResult(BigInteger value, ScaleType numberScale = ScaleType.Short)
        {
            Console.WriteLine(seperatorLine);

            Console.Write($"VALUE: {value:N0}{spacer}TEXT:  {value.ToWords(numberScale).CaptalizeFirstLetter()}");

            if ((value < -999999 || value > 999999) && numberScale < ScaleType.TraditionalBritish)
            {
                Console.WriteLine($"{spacer}{spacer}{longMsgJoiner}{spacer}");

                Console.WriteLine($"{rounded}{value.ToRoundedWords(numberScale).CaptalizeFirstLetter()}");
                Console.WriteLine($"{roundedFraction1}{value.ToRoundedWords(numberScale, FractionType.Rounded).CaptalizeFirstLetter()}");
                Console.WriteLine($"{roundedFraction2}{value.ToRoundedWords(numberScale, FractionType.Short).CaptalizeFirstLetter()}");
                Console.WriteLine($"{roundedFraction3}{value.ToRoundedWords(numberScale, FractionType.Long).CaptalizeFirstLetter()}");

                Console.WriteLine($"{informal}{value.ToInformalRoundedWords(numberScale).CaptalizeFirstLetter()}");
                Console.WriteLine($"{informalFraction1}{value.ToInformalRoundedWords(numberScale, FractionType.Rounded).CaptalizeFirstLetter()}");
                Console.WriteLine($"{informalFraction1}{value.ToInformalRoundedWords(numberScale, FractionType.Short).CaptalizeFirstLetter()}");
                Console.WriteLine($"{informalFraction2}{value.ToInformalRoundedWords(numberScale, FractionType.Long).CaptalizeFirstLetter()}");
            }

            Console.WriteLine(spacer);
        }

        static string spacer = "\r\n";
        static string seperatorLine = "------------------------------------------------";
        static string longMsgJoiner = "... or, to simplify very large numbers ...";
        static string rounded = "Rounded................. : ";
        static string roundedFraction1 = "Rounded with fraction 1. : ";
        static string roundedFraction2 = "Rounded with fraction 2. : ";
        static string roundedFraction3 = "Rounded with fraction 3. : ";
        static string informal = "Informal rounding....... : ";
        static string informalFraction1 = "Informal with fraction 1 : ";
        static string informalFraction2 = "Informal with fraction 2 : ";
        static string informalFraction3 = "Informal with fraction 3 : ";
    }

    public enum ScaleType
    {
        Short,
        Long,
        TraditionalBritish
    }
    
    public enum FractionType
    {
        None,
        Rounded,
        Short,
        Long
    }

    public static class NumberToWordsExtension
    {
        static List<string> singlesScale = new List<string>() { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
        static List<string> tensScale = new List<string>() { "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
        static List<string> shortScale = new List<string>() { "hundred", "thousand", "million", "billion", "trillion", "quadrillion", "quintrillion", "sextillion", "septillion", "octillion", "nonillion", "decillion", "undecillion", "duodecillion", "tredecillion", "quattuordecillion", "quindecillion", "sexdecillion", "septendecillion", "octodecillion", "novemdecillion", "vigintillion", "unvigintillion", "duovigintillion", "tresvigintillion", "quattuorvigintillion", "quinquavigintillion", "sesvigintillion", "septemvigintillion", "octovigintillion", "novemvigintillion", "trigintillion", "untrigintillion", "duotrigintillion", "trestrigintillion", "quattuortrigintillion", "quinquatrigintillion", "sestrigintillion", "septentrigintillion", "octotrigintillion", "noventrigintillion", "quadragintillion", "quinquagintillion", "sexagintillion", "septuagintillion", "octogintillion", "nonagintillion", "centillion", "uncentillion", "duocentillion", "trescentillion", "decicentillion", "undecicentillion", "viginticentillion", "unviginticentillion", "trigintacentillion", "quadragintacentillion", "quinquagintacentillion", "sexagintacentillion", "septuagintacentillion", "octogintacentillion", "nonagintacentillion", "ducentillion", "trecentillion", "quadringentillion", "quingentillion", "sescentillion", "septingentillion", "octingentillion", "nongentillion", "


PIEBALDconsult

"Вы не указали диапазон ints для тестирования или режим масштабирования[^]. "

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

Graeme_Grant

Действительно...

PIEBALDconsult

Серьезно. И несколько языков, и все такое. Кажется, я написал ее больше трех лет назад и с тех пор не прикасался к ней. Это требует работы.

Graeme_Grant

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

PIEBALDconsult

За исключением языков (например, немецкого), которые используют двадцать четыре (vier-und-zwanzig)-мой не может этого сделать.

Graeme_Grant

Попробуй Японские цифры[^]...

Graeme_Grant

На самом деле японский язык был не так уж и сложен...

Graeme_Grant

У меня тоже есть один, но я решил проигнорировать его и выкатить новый для этого упражнения... ;)

Рейтинг:
0

Mehdi Gholam

Неужели?! вы уже должны знать, как пользоваться своим собственным сайтом! :)

using System;
using System.Speech.Synthesis;

namespace SampleSynthesis
{
    class Program
    {
        static void Main(string[] args)
        {
            // Initialize a new instance of the SpeechSynthesizer.
            SpeechSynthesizer synth = new SpeechSynthesizer();

            // Configure the audio output. 
            synth.SetOutputToDefaultAudioDevice();

            // Speak a string.
            synth.Speak(NumberToWords(1234567890123));

            Console.WriteLine();
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }

        public static string NumberToWords(long number)
        {
            if (number == 0)
                return "zero";

            if (number < 0)
                return "minus " + NumberToWords(Math.Abs(number));

            string words = "";
            if ((number / 1000000000000) > 0)
            {
                words += NumberToWords(number / 1000000000000) + " trillion ";
                number %= 1000000000000;
            }

            if ((number / 1000000000) > 0)
            {
                words += NumberToWords(number / 1000000000) + " billion ";
                number %= 1000000000;
            }

            if ((number / 1000000) > 0)
            {
                words += NumberToWords(number / 1000000) + " million ";
                number %= 1000000;
            }

            if ((number / 1000) > 0)
            {
                words += NumberToWords(number / 1000) + " thousand ";
                number %= 1000;
            }

            if ((number / 100) > 0)
            {
                words += NumberToWords(number / 100) + " hundred ";
                number %= 100;
            }

            if (number > 0)
            {
                if (words != "")
                    words += "and ";

                var unitsMap = new[] { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
                var tensMap = new[] { "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };

                if (number < 20)
                    words += unitsMap[number];
                else
                {
                    words += tensMap[number / 10];
                    if ((number % 10) > 0)
                        words += "-" + unitsMap[number % 10];
                }
            }

            return words;
        }


    }
}


Chris Maunder

Да - в последнюю минуту передумал + 3 часа сна = дурацкое время.

Mehdi Gholam

часть его была из stackoverflow ;)

Chris Maunder

?

[no name]

Вилы! Тащи сюда свои вилы!
У нас тоже есть факелы! 2 за 5 долларов.
:-)

PIEBALDconsult

Я возьму по три штуки.

Richard Deeming

Если добавить "квадриллион" и "квинтиллион", то можно охватить весь Int64 диапазон без неудобного - девять миллионов двести двадцать три тысячи триста семьдесят два триллиона ..." в начале. :)

Mehdi Gholam

Мои знания о больших числах терпят неудачу после триллиона :) но я нашел https://en.wikipedia.org/wiki/Names_of_large_numbers

Рейтинг:
0

Kornfeld Eliyahu Peter

В нашем основном приложении у нас есть функция печати платежных ваучеров, которые также должны содержать сумму в цифрах и словах (по закону)...
Сначала я думал принести сюда одну из старых версий (у нас есть COBOL, C++, VB6 и C#), но обнаружил, что моя быстрая версия JavaScript настолько уродлива, что может удовлетворить мазохизм Криса Ан ко.

var minus = 'minus ';
var ones = ['zero', 'one', 'two', ' three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'];
var tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety', 'hundred'];
var scales = ['', '', 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecillion']; // 10^42

function run() {
    var inEl = document.getElementById('in');
    var outEl = document.getElementById('out');

    outEl.innerHTML = convert(inEl.value);
}

function convert(num) {
    if (isNaN(num)) {
        return ('NaN');
    }
    else if (num == 0) {
        return (ones[0])
    }
    else {
        var len = num.toString().length;
        if (len > 0) {
            var word = '';

            if (num[0] == '-') {
                word += minus;
                num = num.substr(1);
                len--;
            }

            var str = Array.apply(null, Array((Math.ceil(len / 3) * 3) - len)).map(Number.prototype.valueOf, 0).join('') + num;
            var part = str.match(/([0-9]{3})/g);

            for (var i = 0; i < part.length; i++) {
                var n = part[i].match(/([0-9])/g);

                word += n[0] > 0 ? ones[n[0]] + ' ' + tens[10] + ' ' : '';
                word += n[1] > 1 ? tens[n[1]] + ' ' : n[1] > 0 ? ones[n[1] + n[2]] + ' ' : '';
                word += n[1] != 1 && n[2] != 0 ? ones[n[2]] + ' ' : '';

                word += scales[part.length - i] + ' ';
            }

            return (word);
        }
        else {
            return ('NaN');
        }
    }
}


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

[РЕДАКТИРОВАТЬ]
Graeme_Grant настолько педант, что мне пришлось обновить свой код, чтобы поддерживать отрицательный и нулевой тоже... :-)


Graeme_Grant

Попробуйте использовать следующие числа: -1,001,010,101, 0 - все допустимые значения Int64.

Kornfeld Eliyahu Peter

Меня не волнует - (минус), но для числа он печатает: один миллиард один миллион десять тысяч сто один

Graeme_Grant

Используя опубликованный код, я получил: сто миллионов сто одна тысяча десять вместо минус один миллиард один миллион десять тысяч сто один

Kornfeld Eliyahu Peter

Как я уже сказал - мне плевать на минус ( - ) - я без знака :-)

Kornfeld Eliyahu Peter

За 9,223,372,036,854,775 он возвращает: девять квадриллионов двести двадцать три триллиона триста семьдесят два миллиарда тридцать шесть миллионов восемьсот пятьдесят четыре тысячи семьсот семьдесят пять

Graeme_Grant

Просто проверяю тебя с последним ... да, в последний раз я забыл убрать разделитель тысяч ... но негативы и ноль действительны. ;)

Рейтинг:
0

Bryian Tan

Предположим, что диапазон составляет от -9,223,372,036,854,775,808 до 9,223,372,036,854,775,807.
В последнюю минуту я изменил код, включив в него 64-битное целое число без знака. Ниже показаны коды и выходные данные.

Выход:

------------ Text Data ------------------
Input: 9223372036854775807
Output: Nine Quintillion, Two Hundred Twenty-Three Quadrillion, Three Hundred Seventy-Two Trillion, Thirty-Six Billion, Eight Hundred Fifty-Four Million, Seven Hundred Seventy-Five Thousand, Eight Hundred and Seven
------------------------------------------
Input: 9
Output: Nine
------------------------------------------
Input: -890008509
Output: Minus Eight Hundred Ninety Million, Eight Thousand, Five Hundred and Nine
------------------------------------------
Input: 10000000001001
Output: Ten Trillion, One Thousand and One
------------------------------------------
Input: 18446744073709551615
Output: Eighteen Quintillion, Four Hundred Forty-Six Quadrillion, Seven Hundred Forty-Four Trillion, Seventy-Three Billion, Seven Hundred Nine Million, Five Hundred Fifty-One Thousand, Six Hundred and Fifteen
------------ End Text Data ------------------

Enter some integer:
18,446,744,073,709,551,615
Eighteen Quintillion, Four Hundred Forty-Six Quadrillion, Seven Hundred Forty-Four Trillion, Seventy-Three Billion, Seven Hundred Nine Million, Five Hundred Fifty-One Thousand, Six Hundred and Fifteen
Enter some integer:
1,023
One Thousand and Twenty-Three
Enter some integer:
10010
Ten Thousand and Ten
Enter some integer:
100100
One Hundred  Thousand, One Hundred
Enter some integer:
-9001001
Minus Nine Million, One Thousand and One
Enter some integer:
8,000,000,001
Eight Billion and One
Enter some integer:
8,000,080,001
Eight Billion, Eighty Thousand and One
Enter some integer:
0
Zero
Enter some integer:
001
One


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Speech.Synthesis;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static IList<string> singleNumber = new List<string>()
            {
                "", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"
            };

        static IList<string> twoNumber = new List<string>()
            {
               "", "Eleven","Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"
            };

        static IList<string> multipleOfTen = new List<string>()
            {
               "", "Ten","Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"
            };

        static IList<string> numberScales = new List<string>()
            {
                "Hundred","Thousand", "Million", "Billion", "Trillion", "Quadrillion", "Quintillion", "Seven", "Sextillion", "Septillion"
            };


        static void Main(string[] args)
        {
            CultureInfo provider = new CultureInfo("en-US"); ;

            Console.WriteLine("------------ Text Data ------------------");
            Console.WriteLine("Input: " + Int64.MaxValue.ToString());
            Console.WriteLine("Output: " + IntegerToSentence(Int64.MaxValue));
            Console.WriteLine("------------------------------------------");
            Console.WriteLine("Input: " + 9);
            Console.WriteLine("Output: " + IntegerToSentence(9));
            Console.WriteLine("------------------------------------------");
            Console.WriteLine("Input: " + -890008509);
            Console.WriteLine("Output: " + IntegerToSentence(-890008509));
            Console.WriteLine("------------------------------------------");
            Console.WriteLine("Input: " + "10000000001001");
            Console.WriteLine("Output: " + IntegerToSentence(10000000001001));
            Console.WriteLine("------------------------------------------");
            Console.WriteLine("Input: " + UInt64.MaxValue.ToString());
            Console.WriteLine("Output: " + IntegerToSentence(UInt64.MaxValue));
            Console.WriteLine("------------ End Text Data ------------------");
            Console.WriteLine();

            bool exit = false;
            Int64 userInput = 0;
            UInt64 userInputUnsigned = 0;
            do
            {
                Console.WriteLine("Enter some integer:");

                string result = Console.ReadLine();
                if (string.IsNullOrEmpty(result))
                {
                    exit = true;
                }
                else
                {

                    if (Int64.TryParse(result, NumberStyles.AllowThousands | NumberStyles.AllowLeadingSign, provider, out userInput))
                    {
                        Console.WriteLine(IntegerToSentence(userInput));
                    }
                    else if (UInt64.TryParse(result, NumberStyles.AllowThousands, provider, out userInputUnsigned))
                    {
                        Console.WriteLine(IntegerToSentence(userInputUnsigned));
                    }
                    else
                    {
                        Console.WriteLine("Integer only!");
                    }
                }

            } while (!exit);
        }

        //handle case 2, remove code redundancy
        static string IntegerToSentenceHelper(int firstElement, int secondElement, ref string output, ref IEnumerable<string> subGroupIntegers)
        {
            if (subGroupIntegers.ElementAt(firstElement) == "1")
            {
                if (subGroupIntegers.ElementAt(secondElement) == "0")
                {
                    output += multipleOfTen.ElementAt(int.Parse(subGroupIntegers.ElementAt(firstElement))) + " ";
                }
                else
                {
                    output += twoNumber.ElementAt(int.Parse(subGroupIntegers.ElementAt(secondElement))) + " ";
                }
            }
            else
            {
                //twenty
                output += multipleOfTen.ElementAt(int.Parse(subGroupIntegers.ElementAt(firstElement)));

                if (int.Parse(subGroupIntegers.ElementAt(1)) > 1 && int.Parse(subGroupIntegers.ElementAt(secondElement)) > 0)
                {
                    output += "-";
                }

                //three
                output += singleNumber.ElementAt(int.Parse(subGroupIntegers.ElementAt(secondElement)));
            }

            return output;
        }

        static string IntegerToSentence<T>(T input, bool unsigned = false)
        {
            string output = string.Empty;
            var listInteger = input.GroupInteger<T>();

            int j = 0;
            //minus sign
            if (listInteger.Item1)
            {
                output += "Minus ";
            }
            //number of group
            j = listInteger.Item2.Count - 1;

            //loop over the List
            while (j >= 0)
            {
                //group the integer into 1 number per group and return as Tuple<bool,List>
                var subGroup = Convert.ToInt64(listInteger.Item2[j]).GroupInteger(1);

                //example: 123
                var subGroupIntegers = subGroup.Item2.Reverse();

                //handle 100
                if (int.Parse(string.Join("", subGroupIntegers.ToArray())) > 0 && j != listInteger.Item2.Count - 1)
                {
                    //make sure the last three integer are in the hundreds before appending a comma
                    if (j == 0)
                    {
                        if (int.Parse(string.Join("", subGroupIntegers.ToArray())) > 99)
                        {
                            output += ", ";
                        }
                    }
                    else
                    {
                        output += ", ";
                    }
                }

                switch (subGroupIntegers.Count())
                {
                    case 3:
                        //one
                        output += singleNumber.ElementAt(int.Parse(subGroupIntegers.ElementAt(0))) + " ";

                        //hundred
                        output += numberScales[0] + " ";

                        if (j == 0 && int.Parse(subGroupIntegers.ElementAt(1) + subGroupIntegers.ElementAt(2)) > 0)
                        {
                            output += " and ";
                        }

                        if (subGroupIntegers.ElementAt(1) == "0")
                        {
                            output += singleNumber.ElementAt(int.Parse(subGroupIntegers.ElementAt(2))) + " ";
                        }
                        else
                        {
                            IntegerToSentenceHelper(1, 2, ref output, ref subGroupIntegers);
                        }

                        if (j > 0)
                        {
                            output += " " + numberScales[j] + " ";
                        }

                        break;
                    case 2:
                        //avoid "and Integer"
                        if (j == 0 && listInteger.Item2.Count > 1)
                        {
                            output += " and ";
                        }

                        IntegerToSentenceHelper(0, 1, ref output, ref subGroupIntegers);

                        if (j > 0)
                        {
                            output += " " + numberScales[j] + " ";
                        }

                        break;
                    default:
                        if (int.Parse(subGroupIntegers.ElementAt(0)) > 0)
                        {
                            if (j == 0 && listInteger.Item2.Count > 1)
                            {
                                output += " and ";
 


Рейтинг:
0

Graeme_Grant

Вот макрос Word 2010+ (протестирован на Word 2013) VBA, который будет обрабатывать положительные и отрицательные числа Int64.

Поскольку макрос VBA работает с документом word, он предназначен для проверки того, что число находится под/рядом с курсором или выбрано. Он правильно определит, если число обозначено как отрицательное (Примечание: тире" -", а не минус, является отдельной словесной сущностью, а не частью числа), и заменит целое число (включая тире, если оно присутствует) на адресную версию. Если выбрано слово, а не число, то макрос ничего не сделает.

Макрос VBA имеет несколько точек входа в зависимости от того, должно ли число быть сформулировано полностью или округлено. Существует 3 режима шкалы: (короткий/современный/американский, длинный или британский традиционный); плюс 4 варианта округления: нет (ближайшая целая шкала - например: один миллион), округленный (такой же, как нет или плюс - например: один миллион плюс), короткий (например: одна точка сто один миллион) или длинный (например: одна точка один ноль один миллион).

Инструкции по использованию макроса приведены в конце исходного кода макроса VBA. Если вы хотите запустить его быстро, то используйте этот метод NumberToWords после ввода и выбора номера в вашем документе word.

Наслаждайтесь!

' NOTE: Requires Word 2010 or newer due to LongLong (64-bit integer) support
'
' Instructions are at the end of the source code.
'
Dim singleScale() As String
Dim tensScale() As String
Dim shortScale() As String
Dim longScale() As String
Dim traditionalScale() As String

Dim zero As String
Dim hundred As String

Enum ScaleType
    Short
    [Long]
    TraditionalBritish
End Enum

Enum FractionType
    None
    Rounded
    Short
    [Long]
End Enum

'---------------------------------------
' NUMBER TO WORDS
'
Public Sub NumberToWords()
    Call NumToWords(ScaleType.Short)
End Sub

Public Sub NumberToLongWords()
    Call NumToWords(ScaleType.Long)
End Sub

Public Sub NumberToTraditionalBritishWords()
    Call NumToWords(ScaleType.TraditionalBritish)
End Sub

Private Sub NumToWords(mode As ScaleType)
    Dim num As LongLong
    If (TryParseNumber(num)) Then
        Selection = ToWords(num, mode)
        'Selection = CaptalizeFirstLetter(ToWords(num, mode))
    End If
End Sub

Private Function ToWords(num As LongLong, mode As ScaleType) As String
    
    Call InitWords

    If num = 0 Then
        ToWords = "zero"
        Exit Function
    End If
    
    isEval = False
    words = ""
    
    If num < 0 Then
        words = words & "minus "
        num = -num
    End If
    
    ' break up the number
    Dim groups() As String
    groups = Split(StrReverse(Format(num, "#,##0")), ",")
    If UBound(groups) > 7 Then
        ToWords = "A friggin huge number!"
        Exit Function
    End If
    
    ' spell it out
    Dim i As Integer
    maxGroups = UBound(groups) - LBound(groups)
    For i = maxGroups To LBound(groups) Step -1
        
        isPart = False: isJoin = False: isHyphen = False
        digits = GetDigits(groups(i))
        maxdigits = UBound(digits) - LBound(digits)
        
        For J = maxdigits To LBound(digits) Step -1
            
            index = digits(J)
            If index > 0 Then
                
                If (Not isHyphen) And (isJoin Or (i = 0 And isEval) And J < 2) Then
                    If Right(words, 1) = "," Then
                        Mid(words, Len(words) - 1, 1) = " "
                    Else
                        words = FixSpace(words)
                    End If
                    words = words & "and "
                    isJoin = False
                End If
                
                If J = 2 Or J = 0 Then ' singles
                    If words <> "" Then
                        If isHyphen Then words = words & "-"
                    Else
                        words = FixSpace(words)
                    End If
                    words = words & singleScale(index) & " "
                    isPart = True
                End If
                
                If J = 2 Then ' hundreds
                    words = words & hundred
                    isPart = True
                    isJoin = True
                End If
                
                If J = 1 Then ' tens
                    If words <> "" Then
                        words = FixSpace(words)
                    End If
                    If index = 1 Then
                        words = words & singleScale(10 + digits(J - 1)) & " "
                        J = J - 1 ' single handled
                    Else
                        words = words & tensScale(index - 1)
                        isHyphen = True
                    End If
                    isPart = True
                End If
            
            End If
            isPart = isPart And i > 0
        Next
        
        If isPart Then ' number scale
            words = FixSpace(words) & GetScaleText(i, mode) & ", "
        End If
        isEval = isEval Or isPart
        
    Next
    
    ToWords = Trim(words)

End Function

'---------------------------------------
' ABBREVIATED/ROUNDED NUMBER TO WORDS
'
Public Sub ToRoundedWords()
    Call RoundedWords(ScaleType.Short, FractionType.Rounded)
End Sub

Public Sub ToShortRoundedWords()
    Call RoundedWords(ScaleType.Short, FractionType.Short)
End Sub

Public Sub ToLongRoundedWords()
    Call RoundedWords(ScaleType.Short, FractionType.Long)
End Sub

Public Sub ToRoundedLongWords()
    Call RoundedWords(ScaleType.Long, FractionType.Rounded)
End Sub

Public Sub ToShortRoundedLongWords()
    Call RoundedWords(ScaleType.Long, FractionType.Short)
End Sub

Public Sub ToLongRoundedLongWords()
    Call RoundedWords(ScaleType.Long, FractionType.Long)
End Sub

Public Sub ToRoundedTradBritishWords()
    Call RoundedWords(ScaleType.TraditionalBritish, FractionType.Rounded)
End Sub

Public Sub ToShortRoundedTradBritishWords()
    Call RoundedWords(ScaleType.TraditionalBritish, FractionType.Short)
End Sub

Public Sub ToLongRoundedTradBritishWords()
    Call RoundedWords(ScaleType.TraditionalBritish, FractionType.Long)
End Sub

Private Sub RoundedWords(mode As ScaleType, rounding As FractionType)
    Dim num As LongLong
    If (TryParseNumber(num)) Then
        Selection = ToRoundedScale(num, mode, rounding)
        'Selection = CaptalizeFirstLetter(ToRoundedScale(num, mode, rounding))
    End If
End Sub

Private Function ToRoundedScale(num As LongLong, mode As ScaleType, rounding As FractionType)

    ' Is the number big enough to abbreviate?
    If (num > -1000001 And num < 1000001) Then
        ToRoundedScale = ToWords(num, mode)
        Exit Function
    End If
    
    Call InitWords
    
    words = ""
    If num < 0 Then
        words = words & "minus "
        num = -num
    End If

    ' Break up the number
    Dim groups() As String
    groups = Split(StrReverse(Format(num, "#,##0")), ",")
    If UBound(groups) > 6 Then
        ToRoundedScale = "A friggin huge number!"
        Exit Function
    End If
    Count = (UBound(groups)) * 3
    
    ' integer part
    words = words & ToWords(CInt(num / (10 ^ Count)), mode)

    ' fraction part
    fraction = StrReverse(groups(UBound(groups) - 1))
    If rounding <> FractionType.None Then
        words = words & AppendFraction(fraction, rounding)
    End If
    
    ' scale
    words = FixSpace(words) & GetScaleText(Count / 3, mode)
    
    ' rounded fraction?
    If rounding = FractionType.Rounded And Not fraction = "000" Then
        words = words & " plus"
    End If

   ToRoundedScale = words

End Function

'---------------------------------------
' SUPPORTING METHODS
'

Private Function TryParseNumber(ByRef num As LongLong)

    If Trim(Selection) = "" Or Selection = vbCr Then
        ' Check to see if we are just to the
        ' right of the number...
        Selection.MoveLeft unit:=wdCharacter, Count:=1
        If IsNumeric(Selection) Then
            ' Process the number
            TryParseNumber = TryParseNumber(num)
        Else
            ' Not a number, so put the cursor back
            ' where we found it... Move along, nothing to see...
            Selection.MoveRight unit:=wdCharacter, Count:=1
        End If
        
    ElseIf IsNumeric(Selection) Then
        ' We have a number to process...
        Application.Selection.words(1).Select
        num = CLngLng(Selection)
        Selection = ""
        ' check to see if the number is negative
        Selection.MoveLeft unit:=wdCharacter, Count:=1
        If Selection = "-" Then
            num = -num
            Application.Selection.words(1).Select
            Selection = ""
        Else
            ' Not negative, so move cursor back...
            Selection.MoveRight unit:=wdCharacter, Count:=1
        End If
        
        ' We have a valid number...
        TryParseNumber = True

    ElseIf Selection = "-" Then
        ' Do we have a negative number?
        Selection.MoveRight unit:=wdCharacter, Count:=1
        If IsNumeric(Selection) Then
            ' Process the negative number
            TryParseNumber = TryParseNumber(num)
        Else
            ' Not a number, so put the cursor back
            ' where we found it... Move along, nothing to see...
            Selection.MoveLeft unit:=wdCharacter, Count:=1
        End If
    End If

End Function

Private Sub InitWords()
    
    If zero = "" Then
        singleScale = Split("zero,one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thirteen,fourteen,fifteen,sixteen,seventeen,eighteen,nineteen", ",")
        tensScale = Split(",twenty,thirty,forty,fifty,sixty,seventy,eighty,ninety", ",")
        shortScale = Split("hundred,thousand,million,billion,trillion,quadrillion,quintillion", ",")
        longScale = Split("hundred,thousand,million,millard,billion,billard,tril


Рейтинг:
0

Patrice T

Цифры на французские буквы. Клипер (FoxPro) еще раз.

*   CCCP Code Challenge Code Project
* Chiffres en lettres
local scan
clear
test= {-1, 0, 1, 61, 71, 81, 91, 180, 200, 3000, 3000000, 1234, 12345, 1234567890123456}

for scan= 1 to len(test)
	? test[scan]
	? i2l(test[scan])
next
return

function i2l(nb)
	private rep, set
	rep=""
	sep=" "
	if nb < 0
		concat("moins")
		nb= abs(nb)
	endif
	if nb = 0
		concat("zéro")
	endif
	
	tranche= int(nb/1000000000000)
	nb= nb % 1000000000000
	if tranche != 0
		concat(i2lm(tranche))
		if tranche > 1 .and. nb=0
			concat("billions")
		else
			concat("billion")
		endif
	endif
	
	tranche= int(nb/1000000000)
	nb= nb % 1000000000
	if tranche != 0
		concat(i2lm(tranche))
		if tranche > 1 .and. nb=0
			concat("milliards")
		else
			concat("milliard")
		endif
	endif
	
	tranche= int(nb/1000000)
	nb= nb % 1000000
	if tranche != 0
		concat(i2lm(tranche))
		if tranche > 1 .and. nb=0
			concat("millions")
		else
			concat("million")
		endif
	endif
	
	tranche= int(nb/1000)
	nb= nb % 1000
	if tranche != 0
		if tranche != 1
			concat(i2lm(tranche))
		endif
		concat("mille")
	endif
	
	tranche= nb 
	if tranche != 0
		concat(i2lm(tranche))
		if tranche >= 200 .and. tranche % 100 = 0
			rep +="s"
		endif
		if tranche % 100 = 80
			rep +="s"
		endif
	endif
	return rep
	
function i2lm(nb)
	private rep, sep
	rep=""
	sep="-"
	du= nb % 100
	c= int(nb / 100)
	if c > 0
		if c > 1
			i2lv(c)
		endif
		concat("cent")
	endif
	do case
	case du >= 80
		concat("Quatre")
		concat("vingt")
		i2lv(du-80)
	case du >= 60
		concat("soixante")
		if du= 61 .or. du= 71
			concat("et")
		endif
		i2lv(du-60)
	case du >= 50
		concat("cinqante")
		if du= 51
			concat("et")
		endif
		i2lv(du-50)
	case du >= 40
		concat("quarante")
		if du= 41
			concat("et")
		endif
		i2lv(du-40)
	case du >= 30
		concat("trente")
		if du= 31
			concat("et")
		endif
		i2lv(du-30)
	case du >= 20
		concat("vingt")
		if du= 21
			concat("et")
		endif
		i2lv(du-20)
	otherwise
		i2lv(du)
	endcase
	return rep
	
procedure i2lv(nb)
	do case
	case nb= 0
	case nb= 1
		concat("un")
	case nb= 2
		concat("deux")
	case nb= 3
		concat("trois")
	case nb= 4
		concat("quatre")
	case nb= 5
		concat("cinq")
	case nb= 6
		concat("six")
	case nb= 7
		concat("sept")
	case nb= 8
		concat("huit")
	case nb= 9
		concat("neuf")
	case nb=10
		concat("dix")
	case nb=11
		concat("onze")
	case nb=12
		concat("douze")
	case nb=13
		concat("treize")
	case nb=14
		concat("quatorze")
	case nb=15
		concat("quinze")
	case nb=16
		concat("seize")
	otherwise
		i2lv(10)
		i2lv(nb-10)
	endcase
	return

procedure concat(st)
	if len(rep) != 0
		rep += sep
	endif
	rep += st
	return


-1
moins un
         0
zéro
         1
un
        61
soixante-et-un
        71
soixante-et-onze
        81
Quatre-vingt-un
        91
Quatre-vingt-onze
       180
cent-Quatre-vingts
       200
deux-cents
      3000
trois mille
   3000000
trois millions
      1234
mille deux-cent-trente-quatre
     12345
douze mille trois-cent-quarante-cinq
 1234567890123456
douze-cent-trente-quatre billion cinq-cent-soixante-sept milliard huit-cent-Quatre-vingt-dix million cent-vingt-trois mille quatre-cent-cinqante-six


Рейтинг:
0

Graeme_Grant

Поскольку ppolymorphe опубликовал версию на французском языке, я подумал, что могу попробовать себя в Японском.

Японский немного отличается от английского. Процитируем выдержку из wikipedia.org[^]: "Японские цифры в письменном виде полностью основаны на китайских цифрах, и группировка больших чисел следует китайской традиции группирования по 10 000."

Обновление : Добавлена поддержка свободно для ToPhonetic Метод расширения, чтобы сделать японские "символы" английскими фонетическими читабельными.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Num2Japanese
{
    static class Program
    {
        static void Main(string[] args)
        {
            int[] tests =
                {
                -1,
                0,
                17,
                1001,
                151,
                302,
                469,
                1234,
                10001,
                2025,
                10000,
                100001,
                1100101,
                -9836703,
                9836703,
                10110011,
                100011011,
                1001010101,
                2036521801,
                -1001010101
                };

            Int64 testMin = Int64.MinValue;
            Int64 testMax = Int64.MaxValue;

            Console.OutputEncoding = Encoding.Unicode;

            for (int i = 0; i < tests.Length; i++)
                ShowResult(tests[i]);

            ShowResult(testMin);
            ShowResult(testMax);

            Console.WriteLine("-- Press any key to exit --");
            Console.ReadKey();
        }

        private static void ShowResult(Int16 value)
        {
            ShowResult((Int64)value);
        }

        private static void ShowResult(UInt16 value)
        {
            ShowResult((Int64)value);
        }

        private static void ShowResult(Int32 value)
        {
            ShowResult((Int64)value);
        }

        private static void ShowResult(UInt32 value)
        {
            ShowResult((Int64)value);
        }

        private static void ShowResult(Int64 value)
        {
            var msg = value.ToJapanese();
            Console.WriteLine(seperatorLine);
            Console.WriteLine($"VALUE: {value:N0}{spacer}TEXT:  {msg}{spacer}Phonetic:  {msg.ToPhonetic()}{spacer}");
        }

        static string spacer = "\r\n";
        static string seperatorLine = "------------------------------------------------";
    }

    public static class NumberToWordsExtension
    {
        static List<string> singlesJScale = new List<string>() { "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九" };
        static List<string> tensJScale = new List<string>() { "", "二十", "三十", "四十", "五十", "六十", "七十", "八十", "九十" };
        static List<string> shortJScale = new List<string>() { "百", "千", "万", "億", "兆", "京" };

        static List<string> singlesPhonetic = new List<string>() { "rei", "ichi", "ni", "san", "yon", "go", "roku", "nana", "hachi", "kyū", "jū", "jū-ichi", "jū-ni", "jū-san", "jū-yon", "jū-go", "jū-roku", "jū-nana", "jū-hachi", "jū-kyū" };
        static List<string> scalePhonetic = new List<string>() { "hyaku", "sen", "man", "oku", "chō", "kei", "gai", "jo" };
        static Dictionary<string, string> specialPhonetic = new Dictionary<string, string>() { { "三百", "san-byaku" }, { "六百", "rop-pyaku" }, { "八百", "hap-pyaku" }, { "千", "is-sen" }, { "三千", "san-zen" }, { "八千", "hassen" }, { "兆", "it-chō" }, { "八兆", "hat-chō" }, { "京", "ik-kei" }, { "六京", "rok-kei" }, { "八京", "hak-kei" } };
        static string zeroJ = singlesJScale[0];

        public static JString ToJapanese(this Int32 num)
            => ((Int64)num).ToJapanese();

        public static JString ToJapanese(this Int64 num)
        {
            // safety check
            if (num == 0) return new JString(zeroJ);

            var words = new StringBuilder();
            if (num < 0)
            {
                words.Append("− ");
                num = -num;
            }

            //break up the number
            var s = string.Concat(num.ToString().Reverse());
            var groups = s.Select((x, i) => i)
                          .Where(i => i % 4 == 0)
                          .Select(i => s.Substring(i, s.Length - i >= 4 ? 4 : s.Length - i))
                          .ToArray();

            if (groups.Length > 5)
                return new JString("申し訳ありませんが、数字が大きすぎます。"); // sorry the number is too big.

            for (int i = groups.Length; i > 0; i--)
            {
                bool isPart = false;
                int[] digits = groups[i - 1].Select(o => Convert.ToInt32(o) - 48).ToArray();
                for (int j = digits.Length; j > 0; j--)
                {
                    var index = digits[j - 1];
                    if (index > 0)
                    {
                        if ((index != 1 && j > 2) || j == 1)  // singles
                        {
                            words.Append(singlesJScale[index]);
                        }

                        if (j == 2) // tens
                        {
                            if (index == 1)
                                words.Append(singlesJScale[10 + digits[j-- - 2]]);
                            else
                                words.Append(tensJScale[index - 1]);
                        }

                        if (j == 3) // hundreds
                        {
                            words.Append(shortJScale[0]);
                        }

                        if (j == 4) // thousands
                        {
                            words.Append(shortJScale[1]);
                        }

                        isPart = true;
                    }
                    isPart = isPart && i > 1;
                }

                if (isPart) // number scale
                {
                    words.Append(shortJScale[i]).Append("  ");
                }
            }
            return new JString(words);
        }

        public static JString ToPhonetic(this JString jText)
        {
            if (string.IsNullOrEmpty(jText?.Value)) return new JString();
            if (jText.Value == singlesJScale[0]) return new JString(singlesPhonetic[0]);

            var words = new StringBuilder();
            var specialSingles = singlesJScale.Skip(1).Take(9);
            var chars = jText.Value.ToCharArray();

            var ndx = chars[0].Equals('−') ? 1 : 0;
            if (ndx > 0) words.Append("Mainasu "); // マイナス

            for (int i = ndx; i < chars.Length; i++)
            {
                var key = chars[i].ToString();
                var isHyphen = !(i == 0 || words.Length == 0 || words[words.Length - 1] == ' ');
                var hyphenate = isHyphen ? "-" : "";

                if (!"-,. ".Contains(key))
                {
                    if (i < chars.Length - 1 && key.Equals(singlesJScale[10]) && specialSingles.Any(c => c.Equals(chars[i + 1])))
                    {
                        words.Append($"{singlesPhonetic[singlesJScale.IndexOf(chars[i + 1].ToString()) + 10]} ");
                    }
                    else
                    {
                        if (specialSingles.Any(c => c.Equals(key)))
                        {
                            if (i < chars.Length - 1)
                            {
                                var sKey = jText.Value.Substring(i, 2);
                                if (specialPhonetic.ContainsKey(sKey))
                                {
                                    words.Append($"{specialPhonetic[sKey]} ");
                                    i++;
                                }
                                else
                                    words.Append($"{singlesPhonetic[singlesJScale.IndexOf(key)]}");
                            }
                            else
                                words.Append($"{singlesPhonetic[singlesJScale.IndexOf(key)]} ");
                        }
                        else if (key.Equals(singlesJScale[10]))
                        {
                            var sKey = jText.Value.Substring(i, 2);
                            if (i < chars.Length - 1 && !isHyphen && singlesJScale.Any(t => t.Equals(sKey)))
                            {
                                words.Append($"{singlesPhonetic[singlesJScale.IndexOf(sKey)]} ");
                                i++;
                            }
                            else
                                words.Append($"{hyphenate}{singlesPhonetic[10]} ");

                        }
                        else if (shortJScale.Any(c => c.Equals(key)))
                        {
                            var isSingle = words.Length > 0 && words[i - 1] == singlesJScale[1][0];
                            if (((i == 0 || words.Length == 0) || (i > 0 && isSingle)) && specialPhonetic.ContainsKey(key))
                            {
                                if (isSingle) words.Remove(words.Length - 1, 1);
                                words.Append($"{specialPhonetic[key]} ");
                            }
                            else
                                words.Append($"{hyphenate}{scalePhonetic[shortJScale.IndexOf(key)]} ");
                        }
                    }
                }
            }
            return new JString(words);
        }
    }


Jon McKee

Йон (4) и Нана (7) также могут быть Ши (4) или шичи (7). Kyuu (9) также может быть ku (9), хотя я не думаю, что когда-либо слышал, чтобы кто-то использовал ku. Зависит от контекста.

Graeme_Grant

Да, конечно, могут. Во введении к решению есть ссылка на Википедию, которая содержит еще несколько фонетических вариаций... ;)

[редактировать:] Например, число 600. Вы не произносите его року-хяку, вместо этого "Рендаку" (морфофонология или последовательное озвучивание) - это РОП-Пяку. Код знает об этом и использует его правильно. :)

Примечание: Я не говорю по-японски и просто подумал, что было бы интересно написать код после комментариев из представления PIEBALDconsult &ppolymorphe...

Jon McKee

О да, я просто не видел Ши/шичи в вашем массиве и делал комментарий :) Я взял 4 года японского языка и могу говорить на нем... "хорошо", ха-ха. Есть много маленьких "Готч", как и в английском, но больше сосредоточенных на том, как сочетаются слова.

Graeme_Grant

Да, я изучал основы французского, немецкого и японского языков в начальной школе несколько десятилетий назад. Меня тоже учили Ши/шичи. Однако я основал свой выбор на ссылке выше - Йон и Нана перечислены как "предпочтительное чтение", ши и шичи-как"на чтении".

Кроме того, я знаю из ведения бизнеса с японскими бизнесменами, что Йон и Нана тогда были более распространены.

Jon McKee

Это потрясающе! Я скучаю по японской общине, где учился в колледже; Иида-сенсей был великим учителем. Мой японский за эти годы сильно заржавел из-за того, где я сейчас живу на Среднем Западе США.

Раньше я хорошо знал Тагальский (филиппинский) и немного французский, но в основном забыл и то, и другое :(

Graeme_Grant

Вы бывали в Японии? В течение нескольких лет я дважды в год ездил по делам. Всегда любил ходить пешком / ездить на работу по ночам и по выходным. :)

Jon McKee

Еще нет, но он есть в списке! Я бы тоже с удовольствием побывал в Южной Корее. Люблю этот язык, хотя мне очень трудно произносить некоторые слова как носителю английского языка, и я не знаю ни одного носителя языка.

Graeme_Grant

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

Jon McKee

Я фанат киберспорта, поэтому постараюсь съездить в Сеул как раз к чемпионату мира по LoL, SC или чему-то подобному ;)

EDIT: кроме того, вау, вы работали повсюду o_O

Graeme_Grant

Звучит весело, но жить из чемодана, путешествуя по делам, - это тяжелая работа, и большую часть времени вы видите только из окна автомобиля или, самое большее, 1/2 дня в заграничной поездке к себе.

Рейтинг:
0

Jon McKee

Запаздываю с этим делом. Был действительно болен на этой неделе : (просто, по существу, и в рамках спецификации с добавлением неподписанной поддержки! Может быть легко расширен для BigInteger поддержка, так как алгоритм разбивает число и перечисление тысяч может быть легко добавлено.

public static class Extensions
{
    public static string ToPhonetic(this long number)
    {
        ulong temp = (ulong)Math.Abs(number);
        if (number < 0)
            return "Negative " + temp.ToPhonetic();
        return temp.ToPhonetic();
    }

    public static string ToPhonetic(this ulong number)
    {
        if (number == 0) return "Zero";
        byte index = 0;
        Dictionary<byte, int> numberSets = new Dictionary<byte, int>();
        do
        {
            numberSets.Add(index++, (int)(number % 1000));
            number /= 1000;
        } while (number > 0);

        return numberSets.Keys.Aggregate(new StringBuilder(),
                (phoneticString, key) =>
                {
                    if (key > 0)
                        phoneticString.Insert(0, " " +
                            Enum.GetName(typeof(Thousands), key) + ", ");
                    GetHundredsPhonetic(phoneticString,
                        numberSets[key]);
                    return phoneticString;
                },
                phoneticString => phoneticString.ToString()
            );
    }

    private static void GetHundredsPhonetic(StringBuilder phonetic, int number)
    {
        byte hundreds = (byte)(number / 100);
        byte tens = (byte)(number % 100 / 10 * 10);
        byte ones = (byte)(number % 10);
        switch (tens)
        {
            case 0:
                phonetic.Insert(0, Enum.GetName(typeof(Hundreds), ones));
                break;
            case 10:
                phonetic.Insert(0, Enum.GetName(typeof(Hundreds), tens + ones));
                break;
            default:
                phonetic.Insert(0, Enum.GetName(typeof(Hundreds), tens) + " " +
                    Enum.GetName(typeof(Hundreds), ones));
                break;
        }
        if (hundreds > 0)
            phonetic.Insert(0, Enum.GetName(typeof(Hundreds), hundreds) + " Hundred ");
    }

    private enum Hundreds : short
    {
        One = 1,
        Two,
        Three,
        Four,
        Five,
        Six,
        Seven,
        Eight,
        Nine,
        Ten,
        Eleven,
        Twelve,
        Thirteen,
        Fourteen,
        Fifteen,
        Sixteen,
        Seventeen,
        Eighteen,
        Nineteen,
        Twenty = 20,
        Thirty = 30,
        Fourty = 40,
        Fifty = 50,
        Sixty = 60,
        Seventy = 70,
        Eighty = 80,
        Ninety = 90,
    }

    private enum Thousands : byte
    {
        None = 0,
        Thousand = 1,
        Million = 2,
        Billion = 3,
        Trillion = 4,
        Quadrillion = 5,
        Quintillion = 6
    }
}