65.9K
CodeProject 正在变化。 阅读更多。
Home

将数字转换为英文和亚洲格式的单词

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (22投票s)

2011年12月26日

CPOL

4分钟阅读

viewsIcon

96426

downloadIcon

5806

将数字转换为可读的单词。

介绍 

我正在浏览文章,偶然看到一篇关于将数字转换为文字的文章,例如将12转换为Twelve。我想我可以用不同的方式尝试同样的事情。我不是程序员,但我喜欢摆弄代码。

我将/会添加我可能不懂的其他语言。例如,我最近添加的印尼语,我甚至无法发音转换后的单词;但我还是做了这个转换器。重点是,请验证并告知我是否需要任何改进。谢谢。

无论如何,Converter 类允许我们将数字转换为文字。让图说话吧!

 IntroImage.png

背景 

在深入研究代码之前,让我们看看数字是如何用文字表示的

英文风格 (美国): 

123,123,000 =  One hundred twenty three million one hundred twenty three thousand
123,000,000 =  One hundred twenty three million
      123,000 =                                                 One hundred twenty three thousand
english_us_and_uk_image.png 

正如我们所见,三位数字总是以相同的方式拼写,然后加上修饰词,如million。在英文风格中,数字以三位一组进行聚合。在亚洲风格中,情况稍有不同。最右边的三位数字被组合在一起,然后其余数字以两个单词进行聚合。

南亚风格: 

12,12,112 = Twelve lakh twelve thousand one hundred twelve
12,00,000 = Twelve lakh
      12,000 =                        twelve thousand
            112 =                                                          one hundred twelve
South_Asian_style_numbers_to_words.png

印尼语风格: 

123,123,100 = Seratus Dua Puluh Tiga Juta Seratus Dua Puluh Tiga Ribu
123,000,000 = Seratus Dua Puluh Tiga Juta
        123,000 =                                                    Seratus Dua Puluh Tiga Ribu
indonesian_style_numbers_to_words.png

代码流程 

这两种系统最普遍的共同点是数字本身。1就是one,9就是nine,20就是twenty,这两种语言都一样。 不同之处在于较高数字的组合和读法。为了方便实现,我创建了数组。这些数组是转换的核心。棘手的部分在于找到正确的索引,以便我们可以使用这些数组。

Private SingleDigitStringArray() As String = _
        {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"}
Private DoubleDigitsStringArray() As String = _
        {"", "Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"}
Private TenthDigitStringArray() As String = _
        {"Ten", "Eleven", "Tweleve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", _
         "Eighteen", "Nineteen"}

Private HigherDigitEnglishStringArray() As String = _
        {"", "", "Hundred", "Thousand", "Million", "Billion", "Trillion", "Quadrillion", "Quintillion"}
Private HigherDigitAsianStringArray() As String = _
        {"", "", "Hundred", "Thousand", "Lakh", "Karod", "Arab", "Kharab"}

Private EnglishCodeArray() As String = {"1", "22", "3"}
Private AsianCodeArray() As String = {"1", "22", "3", "4", "42", "5", "52", "6", "62", "7", "72", "8", "82"} 

Private IndonesianCodeArray() As String = {"1", "22", "3", "4", "42", "420"}
Private SingleDigitIndonesianArray() As String = {"", "Satu", "Dua", "Tiga", "Empat", "Lima", "Enam", _
                                                  "Tujuh", "Delapan", "Sembilan"}
Private DoubleDigitIndonesianArray() As String = {"Puluh", "Belas"}
Private HigherDigitIndonesianStringArray() As String = {"", "", "Ratus", "Ribu", "Juta", "Miliar", "Triliun"}

整个过程基本上是数组操作。主要目标是找到与数字及其位置相对应的正确索引,然后从上述数组中提取相应的单词。 

让我们开始吧。 在英文转换方法中,我们从右边开始一次处理3位数字,然后根据需要添加thousand/million,直到完成为止,如下所示:

Do
	concatHigherDigitString = False
	If i > 3 Then concatHigherDigitString = True 'to suffix the Thousand/Million/Billion type of Word


	If newAmount.Length >= 4 Then   'work with 3 right most digits at a time
		newAmount = amountString.Substring(amountString.Length - i, 3)
	End If


	'do the conversion and affix the Thousand/Million/Billion type of word at the end when needed
	If concatHigherDigitString AndAlso CInt(newAmount) <> 0 Then
		result = ThreeDigitsConverter(CInt(newAmount)) & " " & _
                          HigherDigitEnglishStringArray(i / 3 + 1) & " " & result
	Else
		result = ThreeDigitsConverter(CInt(newAmount))
	End If


	workedStringLength += newAmount.Length
	newAmount = amountString.Substring(0, amountString.Length - workedStringLength)
	i += 3
Loop Until amountString.Length <= workedStringLength


在这两种方法中,我们首先将给定的数字转换为字符串,然后转换为数组,例如,1234转换为“1234”,然后转换为{1, 2, 3, 4},使用以下简单代码。我相信一定有更好的方法来做到这一点…

'convert numbers to array of each digit
Dim amountArray(amountString.Length - 1) As Integer
For i As Integer = amountArray.Length To 1 Step -1
   amountArray(i - 1) = amountString.Substring(i - 1, 1)
Next

现在我们逐位处理,但要向后处理,因为个位数字始终保持在个位。 处理像12这样的数字时会变得有点复杂,因为它不读作onetwo,而是读作Twelve。同样,22不是twotwo,而是Twenty two。同样,10001不是Ten thousand zero hundred one,而是Ten thousand one。牢记所有这些,以下循环将找到正确的索引,然后从单词库(我们之前讨论过的fields数组)中,我们将数字转换为单词。

数字转英文单词的主要方法

与其它方法相比,转换为英文的方法比较直接。没有太多特殊情况,所以找到所需数组的正确索引并不难。

    For i As Integer = amountArray.Length To 1 Step -1
      j = amountArray.Length - i
      digit = amountArray(j)

      codeIndex = EnglishCodeArray(i - 1)
      higherDigitEnglishString = HigherDigitEnglishStringArray(CInt(codeIndex.Substring(0, 1)) - 1)


      If codeIndex = "1" Then 'Number [1 9]
        result = result & SingleDigitStringArray(digit)

      ElseIf codeIndex.Length = 2 And digit <> 0 Then 'Number in tenth place and skip if digit is 0

        If digit = 1 Then   'Number [Eleven, Twelve,...., Nineteen]
          Dim suffixDigit As Integer = amountArray(j + 1)
          result = result & separator & TenthDigitStringArray(suffixDigit) & " " & higherDigitEnglishString
          i -= 1  'Skip the next round as we already looked at it

        Else    'Number [tenth] and [20+] 

          If Me.Style = ConvertStyle.EnglishUK Then
            result = result & separator & DoubleDigitsStringArray(digit) & "-" & higherDigitEnglishString
          ElseIf Me.Style = ConvertStyle.EnglishUS Then
            result = result & separator & DoubleDigitsStringArray(digit) & " " & higherDigitEnglishString
          End If

        End If

      ElseIf digit <> 0 Then  'Standard Number like 100, 1000, 1000000 and skip if digit is 0

        If Me.Style = ConvertStyle.EnglishUK Then andSeparator = " and"
        result = result & separator & SingleDigitStringArray(digit) & " " & higherDigitEnglishString _ 
                                                                          & andSeparator

      End If

      separator = " "
    Next

数字转印尼语单词的主要方法

印尼语风格与英文风格有些相似,但有几个特殊情况使其变得困难。对我来说,最困难的部分是数字以“1”开头的情况。 当数字以1开头时,两个单词会合并成一个,但这不仅仅是简单的拼接。有趣的是,我甚至无法正确发音转换后的单词!

For i As Integer = amountArray.Length To 1 Step -1
      j = amountArray.Length - i
      digit = amountArray(j)

      codeIndex = IndonesianCodeArray(i - 1)
      higherDigitIndonesianString = HigherDigitIndonesianStringArray(CInt(codeIndex.Substring(0, 1)) - 1)


      If codeIndex = "1" Then 'Number [1, 9]
        result = result & separator & SingleDigitIndonesianArray(digit)

      ElseIf codeIndex.Length = 2 And digit <> 0 Then 'Number in tenth place and skip if digit is 0
        Dim suffixDigit As Integer = amountArray(j + 1)

        If digit = 1 And suffixDigit < 2 Then   'Number [Ten and Eleven] 'Sepuluh, Sebelas
          result = result & separator & "Se" & DoubleDigitIndonesianArray(suffixDigit).ToLower & " " & _
                                               higherDigitIndonesianString
          i -= 1

        ElseIf digit = 1 And suffixDigit >= 2 Then    'Number [12, 19]  
          result = result & separator & SingleDigitIndonesianArray(suffixDigit) & " " & _
                                        DoubleDigitIndonesianArray(1) & " " & higherDigitIndonesianString
          i -= 1

        ElseIf suffixDigit <> 0 Then 'Numbers like [21, 22,..29,31,32..39,41....99] ' except ?0s, ??0s
          result = result & separator & SingleDigitIndonesianArray(digit) & " " & _
                                        DoubleDigitIndonesianArray(0)

        Else 'Numbers like [20 30 40...90]
          result = result & separator & SingleDigitIndonesianArray(digit) & " " & _
                                        DoubleDigitIndonesianArray(0) & " " & higherDigitIndonesianString

        End If

      ElseIf digit <> 0 Then  'Standard Number like 100+, 1000+, 1000000+ and skip if digit is 0
        If digit = 1 Then   'exactly numbers like 100, 1000, 1000000
          result = result & separator & "Se" & higherDigitIndonesianString.ToLower
        Else
          result = result & separator & SingleDigitIndonesianArray(digit) & " " & higherDigitIndonesianString
        End If

      End If

      separator = " "
    Next


在此过程中,单词之间会附加一个或两个空格,因此为了清理,我使用RegEx如下:

Private Function RemoveSpaces(ByVal word As String) As String
  Dim regEx As New System.Text.RegularExpressions.Regex("  ")
  Return regEx.Replace(word, " ").Trim
End Function 

好了,这将把数字转换为文字!

数字格式化(或分组)

还有一个公共函数FormatNumber ,它基本上调用Converter 类中的私有函数FormatNumberPerLanguage 。这个FormatNumberPerLanguage 函数将根据提供的区域名称进行分组格式化。简单使用CultureInfo 类。

Private Function FormatNumberPerLanguage(ByVal culterInfoName As String)
    Dim ci As New System.Globalization.CultureInfo(culterInfoName)
    ci.NumberFormat.NumberDecimalDigits = 0
    Return Me.Amount.ToString("N", ci)
End Function 

使用代码 

只需创建一个转换器的新实例,然后传入您想转换的数字和转换风格,然后调用Convert方法。

代码块应设置为“格式化”样式,如下所示: 

Dim converter As New Converter(number, converter.ConvertStyle.EnglishUS)
Me.RichTextBox1.Text = converter.Convert

converter = New Converter(number, NumberToWords.Converter.ConvertStyle.Asian)
Me.RichTextBox2.Text = converter.Convert   

关注点

这两个数组值得一提

Private EnglishCodeArray() As String = {"1", "22", "3"}
Private AsianCodeArray() As String = {"1", "22", "3", "4", "42", "5", "52", "6", "62", "7", "72", "8", "82"}
Private IndonesianCodeArray() As String = {"1", "22", "3", "4", "42", "420"}

…这两个数组有助于确定一个数字是个位、十位还是其它位置…在上面的数组中,双位数“22”将始终代表10位。“4”代表千,“42”代表万。

我有一种感觉,我还没有进行足够的测试,所以我非常期待您的评论。谢谢! 

© . All rights reserved.