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

问题描述 投票:4回答:4

我注意到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倍。

对此有何看法?

excel vba locale decimal-point
4个回答
2
投票

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


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负载,具体取决于你的支持。


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()与小数分隔符之后的“错位”数千分隔符混淆忽略它。


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
© www.soinside.com 2019 - 2024. All rights reserved.