2 Stimmen

Excel-Bereich/Blatt in eine formatierte Textdatei exportieren

Ich wurde damit beauftragt, einen wiederverwendbaren Prozess für unsere Finanzabteilung zu erstellen, um unsere Gehaltsabrechnung für die Berichterstattung an den Staat (WI) hochzuladen. Ich muss etwas erstellen, das ein Blatt oder einen Bereich in Excel übernimmt und eine speziell formatierte Textdatei erstellt.

DAS FORMAT

  • Spalte 1 - Eine statische Nummer, ändert sich nie, Position 1-10
  • Spalte 2 - Eine dynamische Param, die zur Laufzeit für Quartal/Jahr gefüllt wird, Position 11-13
  • Spalte 3 - SSN, keine Bindestriche oder Leerzeichen, ausgefüllt aus Spalte A, Position 14-22
  • Spalte 4 - Nachname, ausgefüllt von Spalte B, Abgeschnitten bei 10, Links Ausrichten & mit Leerzeichen füllen, Position 23-32
  • Spalte 5 - Vorname, ausgefüllt ab C, Bei 8 abschneiden, linksbündig ausrichten & ausfüllen mit Leerzeichen, Position 33-40
  • Spalte 6 - Gesamtbruttolohn/Quartal, gefüllt von D, alle Formatierungen entfernen, Rechtsbündig Null ausfüllen, Position 41-49
  • Spalte 7 - Ein statischer Code, niemals ändert sich, Position 50-51
  • Spalte 8 - BLANKS, Mit Leerzeichen ausfüllen, Position 52-80

Ich habe, wie ich annehme, 3 Möglichkeiten:

  1. VBA
  2. .NET
  3. SQL

Ich hatte mich zuerst mit der .NET-Methode beschäftigt, aber ich konnte einfach keine anständige Dokumentation finden, die mich weitergebracht hätte. Ich mag diese Methode immer noch, aber ich schweife ab.

Als Nächstes habe ich einige VBA, die ein Blatt in einen Text mit fester Breite umwandeln wird. Ich bin gerade dabei, dies zu verfolgen, was schließlich zu meiner eigentlichen Frage führt.

Wie kann ich einen Textbereich in Excel umwandeln? Muss ich ihn in ein anderes Blatt übertragen und dann die Daten mit den erforderlichen Formatierungsfunktionen übergeben, die meine Dump-to-Text-Routine ausführen? Ich hatte eigentlich geplant, für jede Spalte eine Funktion zu haben, aber ich habe Schwierigkeiten herauszufinden, wie ich den nächsten Schritt machen soll. Ich bin ziemlich neu in der Office-Programmierung und Entwicklung im Allgemeinen, so dass jeder Einblick wird sehr geschätzt werden.

Die SQL-Option wäre meine Alternative, da ich in der Vergangenheit ähnliche Exporte aus SQL durchgeführt habe. Ich bevorzuge einfach die beiden anderen Optionen, "Ich möchte nicht für die Leitung verantwortlich sein". Prinzip.

Vielen Dank im Voraus für die Zeit, die Sie sich genommen haben.

0 Stimmen

Ausgezeichnete Frage und Antwort.

4voto

barrowc Punkte 10041

Die Verwendung von VBA scheint mir die beste Lösung zu sein. Damit können Sie ein Makro schreiben, das sich um alle Formatierungsoptionen kümmert und hoffentlich so einfach ist, dass Ihre Finanzleute es selbst ausführen können.

Sie sagten, Sie brauchen etwas, das ein Blatt oder einen Bereich in Excel übernimmt. Die erste Spalte ändert sich nie, also können wir sie im Makro speichern, die Spalten 3-7 stammen aus dem Arbeitsblatt und Spalte 8 ist einfach leer. Bleibt noch Spalte 2 (das Quartal/Jahr als QYY) als Problem. Wenn das Quartal/Jahr irgendwo in der Arbeitsmappe angegeben ist (z. B. in einer Zelle, als Arbeitsblattname, als Teil des Arbeitsmappentitels), können wir es einfach einlesen. Andernfalls müssen Sie eine Methode finden, um das Quartal/Jahr anzugeben, wenn das Makro ausgeführt wird (z. B. ein Dialogfeld öffnen und den Benutzer auffordern, es einzugeben).

Ein einfacher Code (wir werden uns später Gedanken darüber machen, wie man ihn aufruft):

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

Die Parameter sind ziemlich offensichtlich: der Bereich, der die Daten enthält, die Unternehmensnummer für Spalte 1, das Quartal/Jahr für Spalte 2, der feste Code für Spalte 7 und die Datei, in die wir die Ergebnisse ausgeben wollen

' 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

Für die Ausgabe in eine Datei in VBA benötigen wir ein Dateihandle, also eine Variable, in der wir es speichern können. Wir bauen jede Zeile des Berichts in der Berichtszeilenzeichenfolge auf und verwenden den Zeilenindex, um den Bereich zu durchlaufen

' 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

Diese Variablensätze speichern die Rohdaten aus dem Arbeitsblatt bzw. die bereinigten Daten, die in die Datei ausgegeben werden sollen. Die Benennung in "raw" und "clean" erleichtert die Fehlersuche, wenn Sie versehentlich Rohdaten statt bereinigter Daten ausgeben. Um die Formatierung zu erleichtern, müssen wir den Rohlohn von einem String-Wert in einen numerischen Wert ändern

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

FreeFile() holt sich das nächste verfügbare Dateihandle und verwendet dieses, um auf die Datei zu verweisen

' 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

In unserer Schleife, in der wir jede Zeile abarbeiten, löschen wir zunächst die Ausgabezeichenfolge und fügen dann die Werte für die Spalten 1 und 2 ein

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

El .Cells(indexRow, 1) Teil bedeutet einfach die Spalte ganz links im Bereich bei der durch indexRow angegebenen Zeile. Wenn der Bereich in Spalte A beginnt (was nicht der Fall sein muss), dann bedeutet dies einfach A. Wir müssen die cleanFromRawSSN Funktion selbst später

' 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) schneidet die Zeichenkette auf die angegebene Länge ab. Das Format Bild !@@@@@@@@@@ formatiert eine Zeichenkette als genau zehn Zeichen lang, linksbündig (das ! steht für linksbündig) und mit Leerzeichen aufgefüllt

' 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

Wir wandeln ihn in eine Währung um, damit wir ihn mit 100 multiplizieren können, um den Cent-Wert nach links vom Dezimalpunkt zu verschieben. Das macht es viel einfacher zu verwenden Format um den richtigen Wert zu erzeugen. Dies führt zu keiner korrekten Ausgabe für Löhne >= 10 Millionen Dollar, aber das ist eine Einschränkung des für die Berichterstattung verwendeten Dateiformats. Die Website 0 im Format Bildpads mit 0s überraschenderweise

' 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

El String(number, char) Funktion erzeugt eine Variante mit einer Folge von number des angegebenen char . CStr verwandelt die Variante in eine Zeichenkette. Die Print # Anweisung wird ohne zusätzliche Formatierung in die Datei ausgegeben

Next indexRow

' Close the file
Close #fnOutPayrollReport

End Sub

Schleife bis zur nächsten Reihe im Bereich und wiederholen. Wenn wir alle Zeilen verarbeitet haben, schließen wir die Datei und beenden das Makro

Wir brauchen noch zwei Dinge: eine cleanFromRawSSN-Funktion und eine Möglichkeit, das Makro mit den relevanten Daten aufzurufen.

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 gibt die Länge einer Zeichenkette zurück und Mid$(string, start, length) gibt zurück. length Zeichen aus string beginnend bei start . Diese Funktion könnte verbessert werden, da sie derzeit nicht auf nichtnumerische Daten prüft

Zum Aufrufen des Makros:

Sub CallPayrollReport()

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

End Sub

Dies ist die einfachste Art, sie aufzurufen. Der Bereich ist das, was der Benutzer auf dem aktiven Arbeitsblatt in der aktiven Arbeitsmappe ausgewählt hat, und die anderen Werte sind fest kodiert. Der Benutzer sollte den Bereich auswählen, den er in die Datei ausgeben möchte, und dann auf Extras > Makro > Ausführen gehen und CallPayrollReport . Damit dies funktioniert, müsste das Makro entweder Teil der Arbeitsmappe sein, die die Daten enthält, oder in einer anderen Arbeitsmappe liegen, die geladen wurde, bevor der Benutzer das Makro aufruft.

Jemand müsste den fest kodierten Wert des Quartals/Jahres ändern, bevor der Bericht für jedes Quartal erstellt wird. Wie bereits erwähnt, ist es besser, wenn das Quartal/Jahr bereits irgendwo in der Arbeitsmappe gespeichert ist, als es hart zu kodieren und einzulesen.

Ich hoffe, das macht Sinn und ist von Nutzen

0voto

dkretz Punkte 36862

Wenn Sie das Ganze unter dem Gesichtspunkt betrachten, was für Sie am einfachsten ist, und wenn Sie mit SQL vertraut sind, könnten Sie Access verwenden, um die Kalkulationstabelle als externe Datenquelle anzuhängen. Es würde wie eine Tabelle in Access aussehen, und Sie könnten von dort aus arbeiten.

0voto

Refracted Paladin Punkte 11836

Wow!

Ich muss sagen, ich bin überwältigt. Sie haben meine Erwartungen an eine Antwort so weit übertroffen, dass ich mich schuldig fühle, dass ich Sie NUR einmal bewerten und als angenommen markieren kann. Ich hatte so gehofft, dass Sie mir einen Hinweis geben würden, welcher Weg der beste ist und eine Formatierung. Alles Gute zum Geburtstag für mich!

Vor allem die Format()- und FreeFile()-Anweisungen waren neu und nützlich. Und um zu zeigen, dass ich es versucht habe, ist mein Versuch unten zu sehen. Ich war ziemlich nah dran, da ich gerade die Formatierungsdetails ausarbeitete, aber ich glaube, ich werde es mit Ihrem Beitrag überarbeiten, da es der elegantere Ansatz zu sein scheint.

Ein letzter Hinweis. Ich habe diesen Ort durch den Blog von Jeff Atwood gefunden und war von der Idee wirklich begeistert. Als neuer, unerfahrener Entwickler in einem Einzelunternehmen habe ich mir immer gewünscht, dass es einen Ort gibt, an den ich mich wenden kann, um Unterstützung zu erhalten. Bücher und Artikel bringen einen auf den Punkt, aber nichts kommt an den Rat von jemandem heran, der es geschafft hat oder es selbst erlebt hat. Bis jetzt hat StackOverflow das geschafft.

Zum Vergleich: Ich habe genau dieselbe Frage in einem anderen sehr beliebten Code-Forum gestellt und noch keine einzige Antwort erhalten.

Nun zu meinem Versuch:

Der Modulcode

    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

Und der WorkBook-Code:

    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

-1voto

Andy Mikula Punkte 16650

Je nach dem Format Ihres Dokuments würde ich wahrscheinlich empfehlen, in eine .csv-Datei zu exportieren und damit zu arbeiten. Wenn Sie nur die Zahlen benötigen, wäre dies der einfachste Weg.

0 Stimmen

Danke für die Antwort. Ich glaube, ich bin etwas verwirrt. Auf welches Dokument beziehen Sie sich in Bezug auf das "Format"? Ich habe versucht, das in meinem Beitrag zu erläutern. Zweitens: Was bringt es mir, meine xls-Datei in eine csv-Datei umzuwandeln? Nochmals vielen Dank!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X