将Excel范围/工作表导出为格式化文本文件

时间:2009-01-23 16:46:15

标签: .net sql excel vba excel-vba

我的任务是为财务部创建一个可重复使用的流程,将我们的工资单上传到州(WI)进行报告。我需要创建一些在Excel中使用工作表或范围的东西,并创建一个特定格式的文本文件。

格式

  • 第1列 - 静态编号,永不更改,位置1-10
  • 第2列 - 在运行时为季度/年度填充的动态参数,位置11-13
  • 第3列 - SSN,没有连字符或空格, 从A栏填写,位置14-22
  • 第4栏 - 姓氏,填写自 B列,截断为10,左 证明和辩证填补空白,位置 23-32
  • 第5栏 - 名字,由C填写, 截断8,左对齐&填 与空白,位置33-40
  • 第6栏 - 总工资/季度, 从D填充,剥离所有格式, 右对齐零填充,位置 41-49
  • 第7列 - 静态代码,永远不会 变化,位置50-51
  • 第8栏 - BLANKS,填空, 位置52-80

我假设有3种选择:

  1. VBA
  2. .NET
  3. SQL
  4. 我首先探索了.NET方法,但我找不到合适的文档来让我继续。我仍然喜欢这个,但我离题了。

    接下来我有一些VBA将Sheet转储到固定宽度的Text。我目前正在追求这一点,最终导致我的实际问题。

    如何在Excel中转​​换文本范围?我是否需要将它哄到另一张纸上,然后使用neccesarry格式化函数将该数据传递给我的Dump to text routine?我目前计划为每一列提供一个功能,但我无法弄清楚如何采取下一步。我在Office编程和一般开发方面都相当新,所以任何见解都会受到高度赞赏。

    SQL选项将是我的后退,因为我过去曾从SQL做过类似的导出。我只是更喜欢其他两个,“我不想负责运行这个,”原则。

    在任何时间提前感谢。

5 个答案:

答案 0 :(得分:4)

使用VBA似乎是找我的方式。这使您可以编写一个宏来处理所有各种格式化选项,并且希望它足够简单,让您的财务人员自己运行。

你说你需要在Excel中使用工作表或范围的东西。第一列永远不会更改,因此我们可以将其存储在宏中,第3-7列来自电子表格,第8列只是空白。这使第2列(季度/年为QYY)成为一个问题。如果在工作簿中的某个位置指定了季度/年(例如存储在单元格中,作为工作表名称,作为工作簿标题的一部分),那么我们就可以读取它。否则,您需要找到一些方法来指定季度/年运行宏时(例如弹出一个对话框并要求用户输入)

一些简单的代码(我们会担心以后如何调用它):

Sub ProduceStatePayrollReportFile(rngPayrollData As Range, strCompanyNo As String, _
    strQuarterYear As String, strRecordCode As String, strOutputFile As String)

参数非常明显:保存数据的范围,第1列的公司编号,第2列的季度/年,第7列的固定代码以及我们要将结果输出到

' Store the file handle for the output file
Dim fnOutPayrollReport As Integer
' Store each line of the output file
Dim strPayrollReportLine As String
' Use to work through each row in the range
Dim indexRow As Integer

要输出到VBA中的文件,我们需要获取文件句柄,因此我们需要一个变量来存储它。我们将在报告行字符串中构建报告的每一行并使用行索引来完成范围

' Store the raw SSN, last name, first name and wages data
Dim strRawSSN As String
Dim strRawLastName As String
Dim strRawFirstName As String
Dim strRawWages As String
Dim currencyRawWages As Currency

' Store the corrected SSN, last name, first name and wages data
Dim strCleanSSN As String
Dim strCleanLastName As String
Dim strCleanFirstName As String
Dim strCleanWages As String

这些变量集分别存储工作表中的原始数据和要输出到文件的已清理数据。将它们命名为“原始”和“清理”可以更容易地发现错误地输出原始数据而不是清理数据的错误。我们需要将原始工资从字符串值更改为数值以帮助格式化

' Open up the output file
fnOutPayrollReport = FreeFile()
Open strOutputFile For Output As #fnOutPayrollReport

FreeFile()获取下一个可用的文件句柄,我们使用它来链接到文件

' Work through each row in the range
For indexRow = 1 To rngPayrollData.Rows.Count
    ' Reset the output report line to be empty
    strPayrollReportLine = ""
    ' Add the company number to the report line (assumption: already correctly formatted)
    strPayrollReportLine = strPayrollReportLine & strCompanyNo
    ' Add in the quarter/year (assumption: already correctly formatted)
    strPayrollReportLine = strPayrollReportLine & strQuarterYear

在我们遍历每一行的循环中,我们首先清除输出字符串,然后添加第1列和第2列的值

' Get the raw SSN data, clean it and append to the report line
strRawSSN = rngPayrollData.Cells(indexRow, 1)
strCleanSSN = cleanFromRawSSN(strRawSSN)
strPayrollReportLine = strPayrollReportLine & strCleanSSN

.Cells(indexRow, 1)部分仅表示indexRow指定的行范围的最左列。如果范围从A列开始(不一定是这种情况)那么这只是意味着A.我们以后需要自己编写cleanFromRawSSN函数

' Get the raw last and first names, clean them and append them
strRawLastName = rngPayrollData.Cells(indexRow, 2)
strCleanLastName = Format(Left$(strRawLastName, 10), "!@@@@@@@@@@")
strPayrollReportLine = strPayrollReportLine & strCleanLastName

strRawFirstName = rngPayrollData.Cells(indexRow, 3)
strCleanFirstName = Format(Left$(strRawFirstName, 8), "!@@@@@@@@")
strPayrollReportLine = strPayrollReportLine & strCleanFirstName

Left$(string, length)将字符串截断为给定长度。格式图片!@@@@@@@@@@将字符串格式化为十个字符长,左对齐(!表示左对齐)并用空格填充

' Read in the wages data, convert to numeric data, lose the decimal, clean it and append it
strRawWages = rngPayrollData.Cells(indexRow, 4)
currencyRawWages = CCur(strRawWages)
currencyRawWages = currencyRawWages * 100
strCleanWages = Format(currencyRawWages, "000000000")
strPayrollReportLine = strPayrollReportLine & strCleanWages

我们将其转换为货币,以便我们可以乘以100将美分值移动到小数点的左侧。这样可以更轻松地使用Format生成正确的值。这不会产生正确的工资输出> = 1000万美元,但这是用于报告的文件格式的限制。格式图片中的0足够令人惊讶地填充

' Append the fixed code for column 7 and the spaces for column 8
strPayrollReportLine = strPayrollReportLine & strRecordCode
strPayrollReportLine = strPayrollReportLine & CStr(String(29, " "))

' Output the line to the file
Print #fnOutPayrollReport, strPayrollReportLine

String(number, char)函数生成一个Variant,其序列为number指定的charCStr将Variant转换为字符串。 Print #语句输出到文件而没有任何其他格式

Next indexRow

' Close the file
Close #fnOutPayrollReport

End Sub

循环到范围中的下一行并重复。处理完所有行后,关闭文件并结束宏

我们仍然需要两件事:cleanFromRawSSN函数和使用相关数据调用宏的方法。

Function cleanFromRawSSN(strRawSSN As String) As String

' Used to index the raw SSN so we can process it one character at a time
Dim indexRawChar As Integer

' Set the return string to be empty
cleanFromRawSSN = ""

' Loop through the raw data and extract the correct characters
For indexRawChar = 1 To Len(strRawSSN)
    ' Check for hyphen
    If (Mid$(strRawSSN, indexRawChar, 1) = "-") Then
        ' do nothing
    ' Check for space
    ElseIf (Mid$(strRawSSN, indexRawChar, 1) = " ") Then
        ' do nothing
    Else
        ' Output character
        cleanFromRawSSN = cleanFromRawSSN & Mid$(strRawSSN, indexRawChar, 1)
    End If
Next indexRawChar

' Check for correct length and return empty string if incorrect
If (Len(cleanFromRawSSN) <> 9) Then
    cleanFromRawSSN = ""
End If

End Function

Len返回字符串的长度,Mid$(string, start, length)length开始string返回start个字符。此功能可以改进,因为它当前不检查非数字数据

要调用宏:

Sub CallPayrollReport()

ProduceStatePayrollReportFile Application.Selection, "1234560007", "109", "01", "C:\payroll109.txt"

End Sub

这是调用它的最简单方法。范围是用户在活动工作簿中的活动工作表上选择的任何内容,其他值是硬编码的。用户应该选择他们想要输出到文件的范围,然后去工具&gt;宏&gt;运行并选择CallPayrollReport。为此,宏需要成为包含数据的工作簿的一部分,或者是在用户调用宏之前加载的不同工作簿中。

在每个季度的报告生成之前,有人需要更改季度/年的硬编码值。如前所述,如果季度/年已经存储在工作簿的某个地方,那么最好先阅读它而不是硬编码

希望有意义且有一些用处

答案 1 :(得分:0)

从对您最简单的角度考虑这一点,如果您对SQL感到满意,在Access的上下文中,您可以使用Access作为外部数据源附加到电子表格。它看起来像Access中的一个表,并从那里开始工作。

答案 2 :(得分:0)

哇!

我不得不说,我被吹走了。到目前为止,你已经超出了我对答案的期望,我感到内疚,我只能投票给你一次,并标记为例外。我曾希望能够获得最佳路径和一些格式的指导。祝我生日快乐!

Format()和FreeFile()是特别新的有用信息。另外,为了表明我在尝试,我的尝试就在下面。我非常接近,因为我正在制作格式化细节,但我相信我会用你的输入重做它,因为它似乎是更优雅的方法。

作为最后的说明。我通过杰夫阿特伍德的博客找到了这个地方,我对这个想法感到非常兴奋。作为一个新的,没有经验的开发商在一个单独的商店,我一直希望有一个地方,我可以转向指导。书籍和文章让你达到了一个目的,但是没有什么能比得上那个或曾经去过的人的建议。到目前为止StackOverflow已经交付。

作为参考,我在另一个非常受欢迎的代码论坛上发布了这个完全相同的问题,并且还没有以任何方式收到单个回复。

现在我的尝试:

模块代码


    Sub StateANSIIExport()
    Dim Sizes As Variant
    Dim arr As Variant
    Dim aRow As Long, aCol As Long
    Dim rowLimit As Integer, colLimit As Integer
    Dim SpacesPerCell As Integer
    Dim fso As Object
    Dim ts As Object
    Dim TheLine As String
    Dim TestStr As String

    arr = ActiveSheet.UsedRange
    rowLimit = UBound(arr, 1)
    'colLimit = UBound(arr, 2)
    colLimit = 8
    SpacesPerCell = 20      'Set export text "column" width here

    Set fso = CreateObject("Scripting.FileSystemObject")
    Set ts = fso.CreateTextFile(GetDesktopPath() & "EXCELTEXT.txt", True)

    ' Loop thru the rows
    For aRow = 1 To rowLimit
        TheLine = Space(colLimit * SpacesPerCell)     ' your fixed-width output
        ' Loop thru the columns
        For aCol = 1 To colLimit
            Select Case aCol
                Case 1  ' Employer UI Account #
                    Mid(TheLine, aCol * SpacesPerCell - SpacesPerCell + 1, SpacesPerCell) = "6979430002"
                Case 2  ' Reporting Period (QYY)
                    Mid(TheLine, aCol * SpacesPerCell - SpacesPerCell + 1, SpacesPerCell) = "109"
                Case 3  ' SSN
                    Mid(TheLine, aCol * SpacesPerCell - SpacesPerCell + 1, SpacesPerCell) = Cells(aRow, "A")
                Case 4  ' Last Name
                    Mid(TheLine, aCol * SpacesPerCell - SpacesPerCell + 1, SpacesPerCell) = Cells(aRow, "B")
                Case 5  ' First Name
                    Mid(TheLine, aCol * SpacesPerCell - SpacesPerCell + 1, SpacesPerCell) = Cells(aRow, "C")
                Case 6  ' Employee Quartly Gross Wages
                    Mid(TheLine, aCol * SpacesPerCell - SpacesPerCell + 1, SpacesPerCell) = Cells(aRow, "D")
                Case 7   ' Record Code
                    Mid(TheLine, aCol * SpacesPerCell - SpacesPerCell + 1, SpacesPerCell) = "01"
                Case 8  ' BLANK
                    Mid(TheLine, aCol * SpacesPerCell - SpacesPerCell + 1, SpacesPerCell) = "                             "
            End Select
        Next aCol
        ' Write the line to the file
        ts.WriteLine TheLine
    Next aRow

    ts.Close

    Set ts = Nothing
    Set fso = Nothing

    MsgBox "Done"
End Sub

    Sub MacroToRunTwo()
    Dim S As String
    S = "Hello World From Two:" & vbCrLf & _
        "This Add-In File Name: " & ThisWorkbook.FullName
    MsgBox S
End Sub

Function GetDesktopPath() As String
'Return the current user's desktop path
GetDesktopPath = "C:\Users\patrick\Desktop\"
'GetDesktopPath = Environ("HOMEDRIVE") & Environ("HOMEPATH") & "\Desktop\"
End Function

和工作簿代码:


    Private Const C_TAG = "Refracted Solutions" ' C_TAG should be a string unique to this add-in.
Private Const C_TOOLS_MENU_ID As Long = 30007&

Private Sub Workbook_Open()
'''''''''''''''''''''''''''''''''''''''''''''''
' Workbook_Open
' Create a submenu on the Tools menu. The
' submenu has two controls on it.
'''''''''''''''''''''''''''''''''''''''''''''''
Dim ToolsMenu As Office.CommandBarControl
Dim ToolsMenuItem As Office.CommandBarControl
Dim ToolsMenuControl As Office.CommandBarControl

'''''''''''''''''''''''''''''''''''''''''''''''
' First delete any of our controls that
' may not have been properly deleted previously.
'''''''''''''''''''''''''''''''''''''''''''''''
DeleteControls

''''''''''''''''''''''''''''''''''''''''''''''
' Get a reference to the Tools menu.
''''''''''''''''''''''''''''''''''''''''''''''
Set ToolsMenu = Application.CommandBars.FindControl(ID:=C_TOOLS_MENU_ID)
If ToolsMenu Is Nothing Then
    MsgBox "Unable to access Tools menu.", vbOKOnly
    Exit Sub
End If

''''''''''''''''''''''''''''''''''''''''''''''
' Create a item on the Tools menu.
''''''''''''''''''''''''''''''''''''''''''''''
Set ToolsMenuItem = ToolsMenu.Controls.Add(Type:=msoControlPopup, temporary:=True)
If ToolsMenuItem Is Nothing Then
    MsgBox "Unable to add item to the Tools menu.", vbOKOnly
    Exit Sub
End If

With ToolsMenuItem
    .Caption = "&WWCares"
    .BeginGroup = True
    .Tag = C_TAG
End With

''''''''''''''''''''''''''''''''''''''''''''''
' Create the first control on the new item
' in the Tools menu.
''''''''''''''''''''''''''''''''''''''''''''''
Set ToolsMenuControl = ToolsMenuItem.Controls.Add(Type:=msoControlButton, temporary:=True)
If ToolsMenuControl Is Nothing Then
    MsgBox "Unable to add item to Tools menu item.", vbOKOnly
    Exit Sub
End If

With ToolsMenuControl
    ''''''''''''''''''''''''''''''''''''
    ' Set the display caption and the
    ' procedure to run when clicked.
    ''''''''''''''''''''''''''''''''''''
    .Caption = "State ANSII E&xport"
    .OnAction = "'" & ThisWorkbook.Name & "'!StateANSIIExport"
    .Tag = C_TAG
End With

''''''''''''''''''''''''''''''''''''''''''''''
' Create the second control on the new item
' in the Tools menu.
''''''''''''''''''''''''''''''''''''''''''''''
'Set ToolsMenuControl = ToolsMenuItem.Controls.Add(Type:=msoControlButton, temporary:=True)
'If ToolsMenuControl Is Nothing Then
'    MsgBox "Unable to add item to Tools menu item.", vbOKOnly
'    Exit Sub
'End If

'With ToolsMenuControl
    ''''''''''''''''''''''''''''''''''''
    ' Set the display caption and the
    ' procedure to run when clicked.
    ''''''''''''''''''''''''''''''''''''
'    .Caption = "Click Me &Two"
'    .OnAction = "'" & ThisWorkbook.Name & "'!MacroToRunTwo"
'    .Tag = C_TAG
'End With

End Sub


Private Sub Workbook_BeforeClose(Cancel As Boolean)
''''''''''''''''''''''''''''''''''''''''''''''''''''
' Workbook_BeforeClose
' Before closing the add-in, clean up our controls.
''''''''''''''''''''''''''''''''''''''''''''''''''''
    DeleteControls
End Sub


Private Sub DeleteControls()
''''''''''''''''''''''''''''''''''''
' Delete controls whose Tag is
' equal to C_TAG.
''''''''''''''''''''''''''''''''''''
Dim Ctrl As Office.CommandBarControl

On Error Resume Next
Set Ctrl = Application.CommandBars.FindControl(Tag:=C_TAG)

Do Until Ctrl Is Nothing
    Ctrl.Delete
    Set Ctrl = Application.CommandBars.FindControl(Tag:=C_TAG)
Loop

End Sub

答案 3 :(得分:0)

就像更新一样:我能够将它与我的相关,一切都很顺利。

我将其添加到工具栏菜单以便于调用,并将保存部分更改为自动查找桌面并保存文件附加通过过滤的输入框输入的Quarter YEar变量的值。

我想尝试远离他们必须选择活动区域,但根据所涉及的工作,可能不值得我投入时间。 (Solo商店和所有人)沿着这些相同的路线,有更多的错误捕获是很好的,因为它现在非常脆弱,但唉... ....

再次感谢!

答案 4 :(得分:-1)

根据文档的格式,我可能会建议导出到.csv并使用它。如果您需要的只是数字,这将是最简单的方法。