【问题标题】:Convert numbers to words with VBA使用 VBA 将数字转换为单词
【发布时间】:2018-07-06 06:10:13
【问题描述】:

我有一列数字。在下一列中,我想要数字的文本/单词转换。

示例123.561 将转换为 One hundred twenty three point five six one

我不想转换为货币,只是将数字转换为文本,小数位数不限。

我该怎么做?

【问题讨论】:

  • 最大的数字有多大?数千?百万?万亿?
  • 如果您在 google 上搜索过,您会发现 Microsoft 提供了解决方案:How to convert a numeric value into English words in Excel
  • @Pᴇʜ 我搜索了这个伙伴,但这只适用于小数点后 2 位。我想要超过 2 个。此外,如何通过单击功能区中的按钮将其作为宏工作。?
  • @aman - 查看修改后的程序。它不再列出美元或美分,并且包含无限的小数位。

标签: vba excel numbers text-manipulation


【解决方案1】:

编辑:我已将以下程序调整为非货币、无限制的小数位。

Edit 2 通过 (1) Function SpellNumber(2) @ 中的两个变化来考虑 国际化 987654326@ 使代码与其他小数分隔符一起工作(例如,中欧的冒号) ' - see comment


示例:

MsgBox SpellNumber(2123.4575)

...返回:

Two Thousand One Hundred Twenty Three point Four Five Seven Five


将以下代码粘贴到新模块中:

Option Explicit

Function SpellNumber(ByVal numIn)
    Dim LSide, RSide, Temp, DecPlace, Count, oNum
    oNum = numIn
    ReDim Place(9) As String
    Place(2) = " Thousand "
    Place(3) = " Million "
    Place(4) = " Billion "
    Place(5) = " Trillion "
    numIn = Trim(Str(numIn)) 'String representation of amount
    ' Edit 2.(0)/Internationalisation
    ' Don't change point sign here as the above assignment preserves the point!
    DecPlace = InStr(numIn, ".") 'Pos of dec place 0 if none 
    If DecPlace > 0 Then 'Convert Right & set numIn
        RSide = GetTens(Left(Mid(numIn, DecPlace + 1) & "00", 2))
        numIn = Trim(Left(numIn, DecPlace - 1))
    End If
    RSide = numIn
    Count = 1
    Do While numIn <> ""
        Temp = GetHundreds(Right(numIn, 3))
        If Temp <> "" Then LSide = Temp & Place(Count) & LSide
        If Len(numIn) > 3 Then
            numIn = Left(numIn, Len(numIn) - 3)
        Else
            numIn = ""
        End If
        Count = Count + 1
    Loop

    SpellNumber = LSide
    If InStr(oNum, Application.DecimalSeparator) > 0 Then    ' << Edit 2.(1) 
        SpellNumber = SpellNumber & " point " & fractionWords(oNum)
    End If

End Function

Function GetHundreds(ByVal numIn) 'Converts a number from 100-999 into text
    Dim w As String
    If Val(numIn) = 0 Then Exit Function
    numIn = Right("000" & numIn, 3)
    If Mid(numIn, 1, 1) <> "0" Then 'Convert hundreds place
        w = GetDigit(Mid(numIn, 1, 1)) & " Hundred "
    End If
    If Mid(numIn, 2, 1) <> "0" Then 'Convert tens and ones place
        w = w & GetTens(Mid(numIn, 2))
    Else
        w = w & GetDigit(Mid(numIn, 3))
    End If
    GetHundreds = w
End Function

Function GetTens(TensText)  'Converts a number from 10 to 99 into text
    Dim w As String
    w = ""           'Null out the temporary function value
    If Val(Left(TensText, 1)) = 1 Then   'If value between 10-19
        Select Case Val(TensText)
            Case 10: w = "Ten"
            Case 11: w = "Eleven"
            Case 12: w = "Twelve"
            Case 13: w = "Thirteen"
            Case 14: w = "Fourteen"
            Case 15: w = "Fifteen"
            Case 16: w = "Sixteen"
            Case 17: w = "Seventeen"
            Case 18: w = "Eighteen"
            Case 19: w = "Nineteen"
            Case Else
        End Select
    Else      'If value between 20-99..
        Select Case Val(Left(TensText, 1))
            Case 2: w = "Twenty "
            Case 3: w = "Thirty "
            Case 4: w = "Forty "
            Case 5: w = "Fifty "
            Case 6: w = "Sixty "
            Case 7: w = "Seventy "
            Case 8: w = "Eighty "
            Case 9: w = "Ninety "
            Case Else
        End Select
        w = w & GetDigit _
            (Right(TensText, 1))  'Retrieve ones place
    End If
    GetTens = w
End Function

Function GetDigit(Digit) 'Converts a number from 1 to 9 into text
    Select Case Val(Digit)
        Case 1: GetDigit = "One"
        Case 2: GetDigit = "Two"
        Case 3: GetDigit = "Three"
        Case 4: GetDigit = "Four"
        Case 5: GetDigit = "Five"
        Case 6: GetDigit = "Six"
        Case 7: GetDigit = "Seven"
        Case 8: GetDigit = "Eight"
        Case 9: GetDigit = "Nine"
        Case Else: GetDigit = ""
    End Select
End Function

Function fractionWords(n) As String
    Dim fraction As String, x As Long
    fraction = Split(n, Application.DecimalSeparator)(1)   ' << Edit 2.(2)
    For x = 1 To Len(fraction)
        If fractionWords <> "" Then fractionWords = fractionWords & " "
        fractionWords = fractionWords & GetDigit(Mid(fraction, x, 1))
    Next x
End Function

(改编自Source: Microsoft


网上还有其他几个例子。如果您正在搜索“将数字转换为文本”,您可能已经找到了他们,因为这意味着更改数据类型。 "vba convert numbers to words" 是更好的搜索词。

【讨论】:

  • 通过使用String 返回函数Left$Right$Mid$Trim$,您将获得更好的性能。应避免使用 Val 函数,因为它不支持区域设置,并且会在某些区域返回错误值 - 最好酌情使用 CDblCLng。此外,将SpellNumber 的返回类型设为显式String,并强类型化所有变量和辅助函数。最后,使用vbNullString 比使用"" 更好。
  • @ashleedawg 好吧,存储很便宜,内存很贵。此外,在大多数情况下,您拥有的存储空间比可用内存多得多。所以我总是更喜欢内存和速度的优化而不是存储的优化。代码长度不应该是一个问题(如果它的长度优化了内存或速度)。我从来没有听说过有人因为 VBA 代码而耗尽存储空间,但我听说过很多内存不足的情况! (但现在已经离题了)
  • @ashleedawg 明文代码的长度无关紧要。代码文本被转换为 p 代码,然后被解释,然后作为 exe 代码运行。重要的是执行期间使用的字节。 vbNullString 是 0 字节,不需要每次遇到像 "" 这样的字符串文字时都创建、填充和销毁内存地址,因此它在运行时使用更少的内存,并且运行得更快。 Rubberduck VBA 插件(我是其中的贡献者)将识别并修复这些性能改进机会。
  • @ashleedawg Left 函数实际上是隐藏函数 _B_var_Left 的别名,旨在接受和返回 Variant,而 Left$ 函数实际上是_B_str_Left 函数,旨在接受和返回String。如果您的代码正在传入和/或期望返回 String,那么您的代码将更有效地运行,因为您不会遇到从 StringVariant 的隐式转换,然后将 Variant 返回到String每次调用LeftRightMidTrim 等函数时。
  • @ashleedawg Rubberduck's home。关于""vbNullString 的辩论:另一个要考虑的问题是程序员的intent(/代码清晰度)-vbNullString 在传达意图方面要好得多:是的,我真的很想这里有一个零长度的字符串 - 我没有不小心忘记在引号之间放置有意义的字符。它基本上消除了误解/错误的一个来源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-27
相关资源
最近更新 更多