转换到/来自区域设置的行为不一致

时间:2013-09-12 15:55:59

标签: excel vba locale decimal-point

我注意到excel中的奇怪和恼人的行为可能是由于比利时的数字符号不同。 当我在即时窗口中输入此内容时,我会得到反直觉的结果:

 ?val("0,5")
 0
 ?val("0.5")
 0,5

所以我的解决方法就是像这样使用它(通常字符串“0,5” textbox.value 替换)

 val(replace("0,5",",","."))

同样,当使用numberformat()函数时,这会让我陷入这种麻烦。

起初,我在文本框中有一个受限制的KeyPresses:

Select Case KeyAscii
  Case vbKey0 To vbKey9, vbKeyBack, vbKeyClear, vbKeyDelete, vbKeyLeft, _
  vbKeyRight, vbKeyUp, vbKeyDown, vbKeyTab, vbDecimal
  Case Else
    KeyAscii = 0
    Beep
  End Select

但是vbDecimal只允许我输入'。'作为小数点,然后在运行时它将被解释为1000的值。

对此有何看法?

4 个答案:

答案 0 :(得分:2)

Val功能仅识别“。”作为小数分隔符(您可以在相应的MSDN article中阅读);与其他VBA功能相同的事情发生。因此,如果您修改由VBA / Excel计算的小数分隔符,相当多的函数将无关紧要(并且将继续使用“。”)。我通常做的是设置一个自定义函数来分析所有输入数据(它可以只包含你在问题中引用的基本Replace;但我也可以利用它来调整数字格式到一个我期待的,例如:最大小数位数),确保在计算过程中计算的所有小数分隔符都是“。”。完成所有计算后,我有另一个功能来使输出适应预期的格式(通过修改Excel单元格或数字变量本身)。如果你知道的话,这不是一个理想的情况,也不是一个难以解决的问题。

答案 1 :(得分:1)

修改 的 找到了覆盖“区域区域设置数字设置”

的良好示例here

您可以通过查看当地的环境变量来尝试容纳欧洲或美国的分离者。

'Locale support
Private Declare Function GetLocaleInfo Lib "kernel32" Alias "GetLocaleInfoA" (ByVal Locale As Long, ByVal LCType As Long, ByVal lpLCData As String, ByVal cchData As Long) As Long
Const LOCALE_ICOUNTRY = &H5         '  country code
Const LOCALE_SENGCOUNTRY = &H1002      '  English name of country
Const LOCALE_USER_DEFAULT = &H400

然后在你的代码中做这样的事情:

If getLocale <= 1 Then  'US
  'use commas
else 'UK
  'use period
End If

我确信有一种更有效的方法但是如果你加载一个dll,你现在可以根据你的支持有两个不同的dll负载。

答案 2 :(得分:1)

在巴西,我们使用相同的数字符号(“,”作为小数分隔符,“。”作为千位分隔符)。我通常使用CDbl()来转换数字,因为它会考虑区域语言环境设置。 正如您已经提出的那样,val()对于我来说对任何现实世界的使用都太不一致了。它很容易与逗号和点混淆。

这是我对每个功能的看法。请记住,该值在区域设置中返回(在本例中,逗号为小数点分隔符),但在内部它独立于表示法。

? val("2.500,50")
 2,5 
? cdbl("2.500,50")
 2500,5 

这里,val()停止读取逗号上的字符串 - 因此只读取“2.500”,并将点视为小数点分隔符。另一方面,CDbl()完全识别出这个数字。

? val("2,500.50")
 2     
? cdbl("2,500.50")
 2,5005 

在这里,一切都变得一团糟,你可以看到......再次val()停止阅读逗号(尽管数字是美国符号),CDbl()与之混淆在小数点分隔符后“错放”了千位分隔符并忽略它。

答案 3 :(得分:0)

            Public Function GetNumber(ByVal Subject As String, ByVal Default As Double) As Double
            GetNumber = Default
            On Error GoTo EndNow
            Subject = Replace(Subject, ",", ".")
            Subject = Trim(Subject)
            Dim SplitArray() As String
            SplitArray = Split(Subject, ".", 2)

            Dim FirstNumber As Double
            Dim SecondNumber As Double

            SecondNumber = 1

            Dim IndexOne As Long
            Dim IndexTwo As Long
            Dim PowerLength As Long

            IndexOne = LBound(SplitArray)
            IndexTwo = UBound(SplitArray)
            FirstNumber = CDbl(SplitArray(IndexOne))
            GetNumber = FirstNumber

            If (IndexTwo > IndexOne) Then
                SecondNumber = CDbl(SplitArray(IndexTwo))

                PowerLength = Len("" & CDbl("1" & SplitArray(IndexTwo)))
                PowerLength = PowerLength - 1

                If (FirstNumber < 0) Then
                    SecondNumber = SecondNumber * -1
                End If
                GetNumber = GetNumber + (SecondNumber / Application.WorksheetFunction.Power(10, PowerLength))
            End If



            EndNow:
            End Function