【问题标题】:Crazy issue with string formatting字符串格式的疯狂问题
【发布时间】:2015-10-27 22:47:34
【问题描述】:

我遇到了一个让我发疯的问题。我的宏中有两个 FOR 循环,每个循环都有一个计数器来跟踪某个进程执行了多少次。计数器工作得很好,并且在循环结束时包含正确的数字。接下来我要做的是将计数格式化为带有前导零的五位数字。我已经尝试过使用两种不同的方法(见下文)。

cCount = String(5 - Len(cTemp), "0") & cTemp
mCount = String(5 - Len(mTemp), "0") & mTemp

cCount = Format(cTemp, "00000")
mCount = Format(mTemp, "00000")

问题出在第二个计数器上。当我逐步完成时,第一个格式公式有效,但第二行无效,无论我使用哪个版本。现在事情是这样的,如果当我还在宏中时,我将 mCount 的名称更改为其他任何名称,例如 mCnt,然后将宏步骤向后移动以重新处理该行,它将正确格式化多变的。但它不是名字,因为如果我然后使用 mCnt 再次运行宏,它会做同样的事情。我可以将它改回 mCount 并且它会起作用。

所有变量都显示为整数。我正在寻找的一个示例是,如果 mTemp 为 15,则 mCount 将为 00015。但是,mCount 刚刚返回为 15。cCount 工作正常。

一切都是正确的,如果我暂停宏、更改变量名并重新处理该行,我就可以让它工作,这让我完全不知道问题出在哪里。

Sub MakePay()

Dim strFileToOpen As String
Dim payDate, payTab, payCheckTemp, payCheck, payAccTemp As String
Dim payAcc, payAmount, payTotalC, payTotalM As String
Dim savePath As String
Dim payFileNameCLP, payFileNameMF As String
Dim payString1, payString2, payString3, payString4, payString5, payString6 As String
Dim payString7, payString8, payString9 As String
Dim rCnt, i, j, cTemp, cCount, mTemp, mCount As Integer
Dim payTotalMTemp, payAmountTemp, payTotalCTemp As Double


' Set date
payDate = Format(Now(), "yyyymmddhhmmss")
' Ask for check number and format to field length
payCheckTemp = InputBox("Please enter the check number.")
payCheck = payCheckTemp & String(15 - Len(payCheckTemp), " ")
' Create file names and open text files for writing
payFileNameCLP = "CLP_" & payDate & "_01.txt"
payFileNameMF = "MDF_" & payDate & "_01.txt"
savePath = Environ("USERPROFILE") & "\Desktop\"
Open savePath & payFileNameCLP For Output As #1
Open savePath & payFileNameMF For Output As #2

' Build header rows and print them
payString1 = "100"
payString2 = "200          C"
Print #1, payString1
Print #1, payString2
Print #2, payString1
Print #2, payString2

' reset counters for number of claims and total dollar amounts in files
cTemp = 0
mTemp = 0
payTotalCTemp = 0
payTotalMTemp = 0

For i = 1 To Sheets.Count
    ' Process the Clearpoint tab
    If Left(Sheets(i).Name, 3) = "CLE" Then
        Sheets(i).Activate
        rCnt = Cells(Rows.Count, 1).End(xlUp).Row
        For j = 3 To (rCnt - 1)
            ' Read accession # and format it for field length
            payAccTemp = Cells(j, 3).Value
            payAcc = payAccTemp & String(17 - Len(payAccTemp), " ")
            ' Read payment amount, if $0, skip
            payAmountTemp = Format(Cells(j, 5).Value2, "#,###.00")
            If payAmountTemp = "" Then
                GoTo SkipCDL
            End If
            ' Add payment to total Clearpoint payments
            payTotalCTemp = payTotalCTemp + payAmountTemp
            ' Format payment by deleting decimal and then format to field length
            payAmount = Format(payAmountTemp * 100, "0000000;-000000")

            ' Build payment strings and print them
            payString3 = "400" & String(10, " ") & payAcc & payCheck
            payString4 = "450" & String(10, " ") & payAcc & String(150, " ") & payAmount
            payString5 = "500" & String(10, " ") & payAcc & String(73, " ") & payAmount
            Print #1, payString3
            Print #1, payString4
            Print #1, payString5
            ' Increase Clearpoint patient count
            cTemp = cTemp + 1
SkipCDL:
        Next j
    ' Process Medfusion tab
    ElseIf Left(Sheets(i).Name, 3) = "MED" Then
        Sheets(i).Activate
        rCnt = Cells(Rows.Count, 1).End(xlUp).Row
        For j = 3 To (rCnt - 1)
            ' Read accession # and format it for field length
            payAccTemp = Cells(j, 3).Value
            payAcc = payAccTemp & String(17 - Len(payAccTemp), " ")
            ' Read payment amount, if $0, skip
            payAmountTemp = Format(Cells(j, 5).Value2, "#,###.00")
            If payAmountTemp = "" Then
                GoTo SkipMDF
            End If
            ' Add payment to total Medfusion payments
            payTotalMTemp = payTotalMTemp + payAmountTemp
            ' Format payment by deleting decimal and then format to field length
            payAmount = Format(payAmountTemp * 100, "0000000;-000000")

            ' Build payment strings and print them
            payString3 = "400" & String(10, " ") & payAcc & payCheck
            payString4 = "450" & String(10, " ") & payAcc & String(150, " ") & payAmount
            payString5 = "500" & String(10, " ") & payAcc & String(73, " ") & payAmount
            Print #2, payString3
            Print #2, payString4
            Print #2, payString5
            ' Increase Medfusion count
            mTemp = mTemp + 1
SkipMDF:
        Next j
    End If
Next i

' Format patient counter and total payment to field length

cCount = Format(cTemp, "00000")
mCount = Format(mTemp, "00000")
payTotalC = Format(payTotalCTemp * 100, "000000000;-00000000")
payTotalM = Format(payTotalMTemp * 100, "000000000;-00000000")


' Build footer strings and print them
payString6 = "800" & String(26, " ") & "9999" & cCount & String(131, " ") & payTotalC
payString7 = "800" & String(26, " ") & "9999" & mCount & String(131, " ") & payTotalM
payString8 = "900" & String(57, " ") & "099990" & cCount & String(154, " ") & String(2, "0") & payTotalC
payString9 = "900" & String(57, " ") & "099990" & mCount & String(154, " ") & String(2, "0") & payTotalM
Print #1, payString6
Print #2, payString7
Print #1, payString8
Print #2, payString9
' Close all files
Application.DisplayAlerts = False

    Close #1
    Close #2
Application.DisplayAlerts = True

End Sub

【问题讨论】:

  • cCount、cTemp、mCount、mTemp有哪些类型?什么是 mCount 的错误输出?
  • 我编辑了问题以包含此内容。谢谢。
  • 也许我误解了这个问题。 “整数”不是那个问题的答案吗?
  • 它们是整数,而不是字符串,因此您应该将字符串格式应用回整数。如果要显示字符串值,请创建一个字符串变量并使用它。
  • Len(ctemp) 看起来有点奇怪?得到一个整数的长度?例如,以下从单个数字整数 Dim a As Integer a = 1 Debug.Print Len(a) 返回长度为 2 而 Debug.Print Len(CStr(a)) 返回预期结果。

标签: string vba


【解决方案1】:

问题在于如何声明变量。

在 VBA/经典 vb 中,所有声明都应该在自己的行上,或者指定正确的数据类型,否则您可能会意外创建 Variant 数据类型,它可以伪装成 VB 引擎有规则的任何其他数据类型用于确定类型。

https://msdn.microsoft.com/en-us/library/56ht941f(v=vs.90).aspx

此外,每当在 VBA 中编码时,请确保在任何新代码模块的顶部声明 Option Explicit。它会在未来为您省去很多痛苦。

另外,您正在尝试将字符串格式推送到整数中,这是不可能的。

所以...

   Option  Explicit
    .....

    'Dim i, j as Integer 'BAD i is a variant, j is an integer
    Dim i As Integer
    Dim j As Integer 'GOOD both are Integers
    'OR
    Dim x As Integer, y as Integer 'I believe this will work too

    dim displayI as String
    i = 23
    displayI = Format(i, "00000")

在你的代码中为什么不直接格式化?

payString6 = "800" & String(26, " ") & "9999" & Format(cCount,"00000") & String(131, " ") & payTotalC

【讨论】:

  • 现在测试这个。只是好奇。对所有变量进行 DIM 处理有多重要,您何时知道哪些变量需要它?我知道没有它大多数代码都可以正常工作,并且每个小计数器都有自己的 DIM 行,代码会变得很长。只是好奇,因为我正在学习这个问题的新知识。
  • 在遇到像这样的细微错误之前并不重要:)...最佳实践是始终将所有变量和数据类型声明为您期望的样子。还更新了答案,包括如何在一行上正确声明多个。
  • 好的。现在一切都表现得像我预期的那样。我不得不处理一堆其他变量,因为一旦我给它们所有正确的声明,我就会遇到各种类型不匹配。然而,我现在把这一切都理顺了。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2014-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-24
相关资源
最近更新 更多