How can I convert an integer into its verbal representation?

后端 未结 14 2161
走了就别回头了
走了就别回头了 2020-11-22 15:23

Is there a library or a class/function that I can use to convert an integer to it\'s verbal representation?

Example input:

4,567,788`

相关标签:
14条回答
  • 2020-11-22 16:06

    Currently the best, most robust, library for this is definitely Humanizer. It's open sourced and available as a nuget:

    Console.WriteLine(4567788.ToWords()); // => four million five hundred and sixty-seven thousand seven hundred and eighty-eight
    

    It also has a wide range of tools solving the small problems every application has with strings, enums, DateTimes, TimeSpans and so forth, and supports many different languages.

    Console.WriteLine(4567788.ToOrdinalWords().Underscore().Hyphenate().ApplyCase(LetterCasing.AllCaps)); // => FOUR-MILLION-FIVE-HUNDRED-AND-SIXTY-SEVEN-THOUSAND-SEVEN-HUNDRED-AND-EIGHTY-EIGHTH
    
    0 讨论(0)
  • 2020-11-22 16:06

    Fully recursive version:

    private static string[] ones = {
        "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", 
        "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen",
    };
    
    private static string[] tens = { "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
    
    private static string[] thous = { "hundred", "thousand", "million", "billion", "trillion", "quadrillion" };
    
    private static string fmt_negative = "negative {0}";
    private static string fmt_dollars_and_cents = "{0} dollars and {1} cents";
    private static string fmt_tens_ones = "{0}-{1}"; // e.g. for twenty-one, thirty-two etc. You might want to use an en-dash or em-dash instead of a hyphen.
    private static string fmt_large_small = "{0} {1}"; // stitches together the large and small part of a number, like "{three thousand} {five hundred forty two}"
    private static string fmt_amount_scale = "{0} {1}"; // adds the scale to the number, e.g. "{three} {million}";
    
    public static string ToWords(decimal number) {
        if (number < 0)
            return string.format(fmt_negative, ToWords(Math.Abs(number)));
    
        int intPortion = (int)number;
        int decPortion = (int)((number - intPortion) * (decimal) 100);
    
        return string.Format(fmt_dollars_and_cents, ToWords(intPortion), ToWords(decPortion));
    }
    
    private static string ToWords(int number, string appendScale = "") {
        string numString = "";
        // if the number is less than one hundred, then we're mostly just pulling out constants from the ones and tens dictionaries
        if (number < 100) {
            if (number < 20)
                numString = ones[number];
            else {
                numString = tens[number / 10];
                if ((number % 10) > 0)
                    numString = string.Format(fmt_tens_ones, numString, ones[number % 10]);
            }
        } else {
            int pow = 0; // we'll divide the number by pow to figure out the next chunk
            string powStr = ""; // powStr will be the scale that we append to the string e.g. "hundred", "thousand", etc.
    
            if (number < 1000) { // number is between 100 and 1000
                pow = 100; // so we'll be dividing by one hundred
                powStr = thous[0]; // and appending the string "hundred"
            } else { // find the scale of the number
                // log will be 1, 2, 3 for 1_000, 1_000_000, 1_000_000_000, etc.
                int log = (int)Math.Log(number, 1000);
                // pow will be 1_000, 1_000_000, 1_000_000_000 etc.
                pow = (int)Math.Pow(1000, log);
                // powStr will be thousand, million, billion etc.
                powStr = thous[log];
            }
    
            // we take the quotient and the remainder after dividing by pow, and call ToWords on each to handle cases like "{five thousand} {thirty two}" (curly brackets added for emphasis)
            numString = string.Format(fmt_large_small, ToWords(number / pow, powStr), ToWords(number % pow)).Trim();
        }
    
        // and after all of this, if we were passed in a scale from above, we append it to the current number "{five} {thousand}"
        return string.Format(fmt_amount_scale, numString, appendScale).Trim();
    }
    

    Current works up to the (short scale) quadrillions. Additional support (for larger numbers, or for the long scale) can be added simply by changing the thous variable.

    0 讨论(0)
  • 2020-11-22 16:09

    In case anyone wants a JavaScript version

    Number.prototype.numberToWords = function () {
        var unitsMap = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"];
        var tensMap = ["zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"];
    
        var num = this.valueOf();
        if (Math.round(num == 0)) {
            return "zero";
        }
        if (num < 0) {
            var positivenum = Math.abs(num);
            return "minus " + Number(positivenum).numberToWords();
        }
        var words = "";
        if (Math.floor(num / 1000000) > 0) {
            words += Math.floor(num / 1000000).numberToWords() + " million ";
            num = Math.floor(num % 1000000);
        }
        if (Math.floor(num / 1000) > 0) {
            words += Math.floor(num / 1000).numberToWords() + " thousand ";
            num = Math.floor(num % 1000);
        }
        if (Math.floor(num / 100) > 0) {
            words += Math.floor(num / 100).numberToWords() + " hundred ";
            num = Math.floor(num % 100);
        }
        if (Math.floor(num > 0)) {
            if (words != "") {
                words += "and ";
            }
            if (num < 20) {
            words += unitsMap[num];
            }
            else {
                words += tensMap[Math.floor(num / 10)];
                if ((num % 10) > 0) {
                    words += "-" + unitsMap[Math.round(num % 10)];
                }
            }
        }
        return words.trim();
    }
    
    0 讨论(0)
  • 2020-11-22 16:11

    Solution that takes up less code.

    The most important part is only couple lines:

    static Func<long, string> remainder = t => t > 0 ? " " + ToEN(t) : "";
    
    public static string ToEN(this long val, double d = 20, long th = 20)
    {
        switch ((long)d)
        {
            case 20:   return val >= d ? ToEN(val, 1e2)             : en[val];
            case 100:  return val >= d ? ToEN(val, 1e3, 100)        : en[val / 10 * 10] + remainder(val % 10);
            default:   return val >= d ? ToEN(val, d * 1e3,(long)d) : ToEN(val / th) + " " + en[th] + remainder(val % th);
        }
    }
    

    Full code is available here https://dotnetfiddle.net/wjr4hF

    0 讨论(0)
  • 2020-11-22 16:14
    Imports System.Text
    
    Public Class NumberWriter
    
        Public Shared Function Parse(ByVal Number As String) As String
            If Not AreNumbers(Number) Then Return ""
            Dim TempQueue As New Queue(Of String)
            For Each ItemA As Char In Number.Replace(",", "").Reverse
                TempQueue.Enqueue(ItemA)
            Next
            Dim Blocks As New List(Of String)
            Dim BlockEmpty As New List(Of Boolean)
            Do
                Dim TempBlock As New StringBuilder(3)
                TempBlock.Append(TempQueue.Dequeue)
                If TempQueue.Count > 0 Then
                    TempBlock.Append(TempQueue.Dequeue)
                    If TempQueue.Count > 0 Then
                        TempBlock.Append(TempQueue.Dequeue)
                    End If
                End If
                Blocks.Add(StrReverse(TempBlock.ToString))
                BlockEmpty.Add(TempBlock.ToString = "000")
                If TempQueue.Count < 1 Then Exit Do
            Loop
            Dim ResultStack As New Stack(Of String)
            For int1 As Integer = 0 To Blocks.Count - 1
                ResultStack.Push(ReadBlock(Blocks(int1)) & If(Not int1 = 0, If(Not BlockEmpty(int1), " " & CapitalizeWord(GetPlaceValueSet(int1)) & If(BlockEmpty(int1 - 1), "", ", "), ""), ""))
            Next
            Dim Result1 As String = ""
            Do Until ResultStack.Count < 1
                Result1 &= ResultStack.Pop
            Loop
            Return RemoveGrammarErrors(Result1)
        End Function
    
        Private Shared Function RemoveGrammarErrors(ByVal Str As String) As String
            Dim tstr As String = Str
            tstr.Replace("  ", " ")
            tstr.Replace(" , ", ", ")
            Return tstr
        End Function
    
        Private Shared Function AreNumbers(ByVal Str1 As String) As Boolean
            Dim Numbers() As String = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ","}
            For Each ItemA As Char In Str1
                Dim IsN As Boolean = False
                For Each ItemB As String In Numbers
                    If ItemA = ItemB Then IsN = True
                Next
                If Not IsN Then
                    Return False
                End If
            Next
            Return True
        End Function
    
        Private Shared Function ReadBlock(ByVal Block As String)
            Select Case Block.Length
                Case 1
                    Return ReadSingleDigit(Block)
                Case 2
                    Return ReadTwoDigits(Block)
                Case 3
                    Return ReadThreeDigits(Block)
                Case Else
                    Throw New Exception
            End Select
        End Function
    
        Private Shared Function ReadThreeDigits(ByVal Digits As String)
            If Digits.Length > 3 Then Throw New ArgumentException("There are too many digits.")
            Dim Result As String = ""
            If Not Digits(0) = "0" Then
                Result &= ReadSingleDigit(Digits(0)) & " Hundred "
            End If
            Result &= ReadTwoDigits(Digits.Substring(1))
            Return Result
        End Function
    
        Private Shared Function ReadTwoDigits(ByVal Digits As String)
            If Digits.Length > 2 Then Throw New ArgumentException("There are too many digits.")
            Select Case Digits(0)
                Case "0"
                    Return ReadSingleDigit(Digits(1))
                Case "1"
                    Return ReadTeenNumber(Digits)
                Case Else
                    Return ReadFirstInNumberPair(Digits(0)) & If(Digits(1) = "0", "", "-" & ReadSingleDigit(Digits(1)))
            End Select
        End Function
    
        Private Shared Function ReadSingleDigit(ByVal Digit As String) As String
            If Not Digit.Length = 1 Then Throw New ArgumentException("There must be only one digit and it must be more than zero.")
            Select Case Digit
                Case "0"
                    Return ""
                Case "1"
                    Return "One"
                Case "2"
                    Return "Two"
                Case "3"
                    Return "Three"
                Case "4"
                    Return "Four"
                Case "5"
                    Return "Five"
                Case "6"
                    Return "Six"
                Case "7"
                    Return "Seven"
                Case "8"
                    Return "Eight"
                Case "9"
                    Return "Nine"
                Case Else
                    Throw New Exception()
            End Select
        End Function
    
        Private Shared Function ReadTeenNumber(ByVal Num As String) As String
            Select Case Num
                Case "11"
                    Return "Eleven"
                Case "12"
                    Return "Twelve"
                Case "13"
                    Return "Thirteen"
                Case "14"
                    Return "Fourteen"
                Case "15"
                    Return "Fifteen"
                Case "16"
                    Return "Sixteen"
                Case "17"
                    Return "Seventeen"
                Case "18"
                    Return "Eighteen"
                Case "19"
                    Return "Nineteen"
                Case Else
                    Throw New Exception()
            End Select
        End Function
    
        Private Shared Function ReadFirstInNumberPair(ByVal Num As String) As String
            If Not (Num > 1 OrElse Num < 10) Then Throw New ArgumentException("Number must be more than 1 and less than 10")
            Select Case Num
                Case "2"
                    Return "Twenty"
                Case "3"
                    Return "Thirty"
                Case "4"
                    Return "Fourty"
                Case "5"
                    Return "Fifty"
                Case "6"
                    Return "Sixty"
                Case "7"
                    Return "Seventy"
                Case "8"
                    Return "Eighty"
                Case "9"
                    Return "Ninety"
                Case Else
                    Throw New Exception()
            End Select
        End Function
    
        Private Shared Function CapitalizeWord(ByVal Word As String) As String
            Return Word.Substring(0, 1).ToUpper & Word.Substring(1)
        End Function
    
        Private Shared Function GetPlaceValueSet(ByVal Num As Byte) As String
            Select Case Num
                Case 0
                    Return "" 'Hundreds
                Case 1
                    Return "Thousand"
                Case 2
                    Return "Million"
                Case 3
                    Return "Billion"
                Case 4
                    Return "Trillion"
                Case 5
                    Return "Quadrillion"
                Case 6
                    Return "Quintillion"
                Case 7
                    Return "Sextillion"
                Case 8
                    Return "Septillion"
                Case 9
                    Return "Octillion"
                Case 10
                    Return "Nonillion"
                Case 11
                    Return "octillion"
                Case 12
                    Return "nonillion"
                Case 13
                    Return "decillion"
                Case 14
                    Return "undecillion"
                Case 15
                    Return "dodecillion,"
                Case 16
                    Return "tredecillion"
                Case 17
                    Return "quattuordecillion"
                Case 18
                    Return "quindecillion"
                Case 19
                    Return "sexdecillion"
                Case 20
                    Return "septendecillion"
                Case 21
                    Return "octodecillion"
                Case 22
                    Return "novemdecillion"
                Case 23
                    Return "vigintillion"
                Case 24
                    Return "unvigintillion"
                Case 25
                    Return "dovigintillion"
                Case 26
                    Return "trevigintillion"
                Case 27
                    Return "quattuorvigintillion"
                Case 28
                    Return "quinvigintillion"
                Case 29
                    Return "sexvigintillion"
                Case 30
                    Return "septenvigintillion"
                Case 31
                    Return "octovigintillion"
                Case 32
                    Return "novemvigintillion"
                Case 33
                    Return "trigintillion"
                Case 34
                    Return "untrigintillion"
                Case 35
                    Return "dotrigintillion"
                Case 36
                    Return "tretrigintillion"
                Case 37
                    Return "quattuortrigintillion"
                Case 38
                    Return "quintrigintillion"
                Case 39
                    Return "sextrigintillion"
                Case 40
                    Return "septentrigintillion"
                Case 41
                    Return "octotrigintillion"
                Case Else
                    Throw New Exception
            End Select
        End Function
    End Class
    

    Sorry it's in VB.NET, but it works completely. It is one way. Number to Verbal. Handles numbers up to 123 characters long I believe.

    0 讨论(0)
  • 2020-11-22 16:18

    The following C# console app code will give accepts a monetary value in numbers up to 2 decimals and prints it in English. You can use it as a reference to achieve your results.

       namespace ConsoleApplication2
    {
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text.RegularExpressions;
        class Program
        {
           static void Main(string[] args)
            {
                bool repeat = true;
                while (repeat)
                {
                    string inputMonetaryValueInNumberic = string.Empty;
                    string centPart = string.Empty;
                    string dollarPart = string.Empty;
                    Console.Write("\nEnter the monetary value : ");
                    inputMonetaryValueInNumberic = Console.ReadLine();
                    inputMonetaryValueInNumberic = inputMonetaryValueInNumberic.TrimStart('0');
    
                    if (ValidateInput(inputMonetaryValueInNumberic))
                    {
    
                        if (inputMonetaryValueInNumberic.Contains('.'))
                        {
                            centPart = ProcessCents(inputMonetaryValueInNumberic.Substring(inputMonetaryValueInNumberic.IndexOf(".") + 1));
                            dollarPart = ProcessDollar(inputMonetaryValueInNumberic.Substring(0, inputMonetaryValueInNumberic.IndexOf(".")));
                        }
                        else
                        {
                            dollarPart = ProcessDollar(inputMonetaryValueInNumberic);
                        }
                        centPart = string.IsNullOrWhiteSpace(centPart) ? string.Empty : " and " + centPart;
                        Console.WriteLine(string.Format("\n\n{0}{1}", dollarPart, centPart));
                    }
                    else
                    {
                        Console.WriteLine("Invalid Input..");
                    }
    
                    Console.WriteLine("\n\nPress any key to continue or Escape of close : ");
                    var loop = Console.ReadKey();
                    repeat = !loop.Key.ToString().Contains("Escape");
                    Console.Clear();
                }
    
            }
    
            private static string ProcessCents(string cents)
            {
                string english = string.Empty;
                string dig3 = Process3Digit(cents);
                if (!string.IsNullOrWhiteSpace(dig3))
                {
                    dig3 = string.Format("{0} {1}", dig3, GetSections(0));
                }
                english = dig3 + english;
                return english;
            }
            private static string ProcessDollar(string dollar)
            {
                string english = string.Empty;
                foreach (var item in Get3DigitList(dollar))
                {
                    string dig3 = Process3Digit(item.Value);
                    if (!string.IsNullOrWhiteSpace(dig3))
                    {
                        dig3 = string.Format("{0} {1}", dig3, GetSections(item.Key));
                    }
                    english = dig3 + english;
                }
                return english;
            }
            private static string Process3Digit(string digit3)
            {
                string result = string.Empty;
                if (Convert.ToInt32(digit3) != 0)
                {
                    int place = 0;
                    Stack<string> monetaryValue = new Stack<string>();
                    for (int i = digit3.Length - 1; i >= 0; i--)
                    {
                        place += 1;
                        string stringValue = string.Empty;
                        switch (place)
                        {
                            case 1:
                                stringValue = GetOnes(digit3[i].ToString());
                                break;
                            case 2:
                                int tens = Convert.ToInt32(digit3[i]);
                                if (tens == 1)
                                {
                                    if (monetaryValue.Count > 0)
                                    {
                                        monetaryValue.Pop();
                                    }
                                    stringValue = GetTens((digit3[i].ToString() + digit3[i + 1].ToString()));
                                }
                                else
                                {
                                    stringValue = GetTens(digit3[i].ToString());
                                }
                                break;
                            case 3:
                                stringValue = GetOnes(digit3[i].ToString());
                                if (!string.IsNullOrWhiteSpace(stringValue))
                                {
                                    string postFixWith = " Hundred";
                                    if (monetaryValue.Count > 0)
                                    {
                                        postFixWith = postFixWith + " And";
                                    }
                                    stringValue += postFixWith;
                                }
                                break;
                        }
                        if (!string.IsNullOrWhiteSpace(stringValue))
                            monetaryValue.Push(stringValue);
                    }
                    while (monetaryValue.Count > 0)
                    {
                        result += " " + monetaryValue.Pop().ToString().Trim();
                    }
                }
                return result;
            }
            private static Dictionary<int, string> Get3DigitList(string monetaryValueInNumberic)
            {
                Dictionary<int, string> hundredsStack = new Dictionary<int, string>();
                int counter = 0;
                while (monetaryValueInNumberic.Length >= 3)
                {
                    string digit3 = monetaryValueInNumberic.Substring(monetaryValueInNumberic.Length - 3, 3);
                    monetaryValueInNumberic = monetaryValueInNumberic.Substring(0, monetaryValueInNumberic.Length - 3);
                    hundredsStack.Add(++counter, digit3);
                }
                if (monetaryValueInNumberic.Length != 0)
                    hundredsStack.Add(++counter, monetaryValueInNumberic);
                return hundredsStack;
            }
            private static string GetTens(string tensPlaceValue)
            {
                string englishEquvalent = string.Empty;
                int value = Convert.ToInt32(tensPlaceValue);
                Dictionary<int, string> tens = new Dictionary<int, string>();
                tens.Add(2, "Twenty");
                tens.Add(3, "Thirty");
                tens.Add(4, "Forty");
                tens.Add(5, "Fifty");
                tens.Add(6, "Sixty");
                tens.Add(7, "Seventy");
                tens.Add(8, "Eighty");
                tens.Add(9, "Ninty");
                tens.Add(10, "Ten");
                tens.Add(11, "Eleven");
                tens.Add(12, "Twelve");
                tens.Add(13, "Thrteen");
                tens.Add(14, "Fourteen");
                tens.Add(15, "Fifteen");
                tens.Add(16, "Sixteen");
                tens.Add(17, "Seventeen");
                tens.Add(18, "Eighteen");
                tens.Add(19, "Ninteen");
                if (tens.ContainsKey(value))
                {
                    englishEquvalent = tens[value];
                }
    
                return englishEquvalent;
    
            }
            private static string GetOnes(string onesPlaceValue)
            {
                int value = Convert.ToInt32(onesPlaceValue);
                string englishEquvalent = string.Empty;
                Dictionary<int, string> ones = new Dictionary<int, string>();
                ones.Add(1, " One");
                ones.Add(2, " Two");
                ones.Add(3, " Three");
                ones.Add(4, " Four");
                ones.Add(5, " Five");
                ones.Add(6, " Six");
                ones.Add(7, " Seven");
                ones.Add(8, " Eight");
                ones.Add(9, " Nine");
    
                if (ones.ContainsKey(value))
                {
                    englishEquvalent = ones[value];
                }
    
                return englishEquvalent;
            }
            private static string GetSections(int section)
            {
                string sectionName = string.Empty;
                switch (section)
                {
                    case 0:
                        sectionName = "Cents";
                        break;
                    case 1:
                        sectionName = "Dollars";
                        break;
                    case 2:
                        sectionName = "Thousand";
                        break;
                    case 3:
                        sectionName = "Million";
                        break;
                    case 4:
                        sectionName = "Billion";
                        break;
                    case 5:
                        sectionName = "Trillion";
                        break;
                    case 6:
                        sectionName = "Zillion";
                        break;
                }
                return sectionName;
            }
            private static bool ValidateInput(string input)
            {
                return Regex.IsMatch(input, "[0-9]{1,18}(\\.[0-9]{1,2})?"))
            }
        }
    }
    

    0 讨论(0)
提交回复
热议问题