Es gibt zwar schon ein paar Funktionen zum Einlesen von CSV aber manche kommen mit Feinheiten wie escaped quotes oder Zeilenumbrüche in einem Value nicht klar.
Außerdem habe ich mir eine Funktion gewünscht, welche gleich das benutzerdefinierte Parsing der Werte übernimmt (z. B. "deutsche" Zahlen mit "," als Dezimaltrennzeichen sollen gleich als AutoIt-Zahlentyp eingelesen werden oder sowas).
Des Weiteren hätte ich gerne (wie z.B. bei Python) die Werte nicht nur als 2D-Array sondern die einzelnen Datensätze gleich als Objekte vorliegen. (macht es bei der Verarbeitung hinterher einfacher wenn man einfach den Attributnamen des Objektes angeben kann anstatt dass man mit Indizes arbeiten muss).
Daher habe ich halt selbst eine entsprechende Funktion geschrieben und könnte mir vorstellen, dass noch jemand Verwendung für diese finden könnte.
Die _parseCSV ist für das Einlesen und konvertieren in ein Array zuständig und kann folgendes:
- Einlesen von CSV-Dateien oder Strings
- kommt mit escaped Quotes und Zeilenumbrüchen in Values klar
- Beliebiges Austauschen der Trennzeichen und Quote-Zeichen
- Headerzeile ignorieren ist möglich
- Für jede Spalte kann eine Funktion angegeben werden mit der die jeweiligen Werte konvertiert / geparsed werden sollen
#include "parseCSV.au3"
; CSV-Daten besorgen:
Global $s_CSV = BinaryToString(InetRead('https://pastebin.com/raw/3N1xVAN0'), 4)
; simples direktes Einlesen in ein Array ohne Behandlung der Werte:
Global $aData = _parseCSV($s_CSV)
_ArrayDisplay($aData, 'Großstädte Deutschlands', '1:', 64, Default, _ArrayToString($aData, '|', 0, 0))
; konvertiere in deutsch formatierte Zahlenwerte in AutoIt-Zahlentypen
$aData = _parseCSV($s_CSV, True, False, ';', '"', ';__PunktWeg;__ZahlDeutsch;__PunktWeg;Number')
_ArrayDisplay($aData, 'Großstädte Deutschlands - als Zahlen geparsed', '1:', 64, Default, _ArrayToString($aData, '|', 0, 0))
; deutsch formatierte zahlen in Zahlentyp konvertieren
Func __ZahlDeutsch($sZahl)
Return Number(StringReplace(StringReplace($sZahl, '.', ''), ',', '.'))
EndFunc ;==>__ZahlDeutsch
; entfernt Punkt aus String und wandelt in Zahlentyp
Func __PunktWeg($sZahl)
Return Number(StringReplace($sZahl, '.', ''))
EndFunc ;==>__PunktWeg
Alles anzeigen
Die _Array2Dics konvertiert ein 2D-Array (wie z. B. von der _parseCSV zurückgegeben) in ein Array mit Objekten.
Die Attributnamen kommen entweder aus der ersten Zeile (Headerzeile) oder können benutzerdefiniert übergeben werden:
#include "parseCSV.au3"
; Input-Array für _Array2Dics erzeugen:
Global $s_CSV = BinaryToString(InetRead('https://pastebin.com/raw/3N1xVAN0'), 4)
Global $aData = _parseCSV($s_CSV)
; 2D-Array in Array of Objects konvertieren (mit eigenem Header):
Global $aDics = _Array2Dics($aData, 'Name;EW;km²;EW/km²;Seit;Land')
; alle Objekte ausgeben
For $oObject In $aDics
ConsoleWrite("================================================" & @CRLF)
For $Attribute In $oObject.keys
ConsoleWrite(StringFormat("% 20s: %s\n", $Attribute, $oObject($Attribute)))
Next
ConsoleWrite("------------------------------------------------" & @CRLF & @CRLF)
Next
Alles anzeigen
Zu guter letzt macht es in dem Zusammenhang noch Sinn eine Funktion zu haben, welche aus einem 2D-Array eine CSV bastelt:
#include "parseCSV.au3"
; 2D-Array erzeugen:
Global $s_CSV = BinaryToString(InetRead('https://pastebin.com/raw/3N1xVAN0'), 4)
Global $aData = _parseCSV($s_CSV, True, False, ';', '"', ';__PunktWeg;__ZahlDeutsch;__PunktWeg;Number')
; schreibe csv-Datei
FileWrite("out.csv", _Array2CSV($aData, Default, ','))
Und ebenfalls liegt noch die Funktion _StringHandleTable() dabei.
Die ist ähnlich wie die parseCSV - jedoch für Tabellen wo die Spalten jeweils eine feste Breite haben (wie z.B. bei Ausgaben von printf) und eben nicht über ein Spaltentrennzeichen abgetrennt werden.
Das Parsing von Konsolenausgaben dürfte sicher der häufigste Anwendungsfall für diese Funktion sein:
#include "parseCSV.au3"
$s_String = RunCmd("netsh", "interface show interface")
; Erste zwei Zeilen entfernen:
$s_String = StringRegExpReplace($s_String, '\A(?>.*\R){3}', '')
; Tabellenformatierten String mit festen Spaltenbreiten in Array parsen:
$a_Data = _StringHandleTable($s_String, "__active 15; __connected 15; void 17; leftstring")
_ArrayDisplay($a_Data, "netsh interfaces", "", 64, Default, "Aktiviert?|Verbunden?|Device")
; user-defined functions zum speziellen Parsen einzelner Spalten:
Func __active(Const $S)
Return StringRegExp($S, "^Aktiviert") = 1
EndFunc
Func __connected(Const $S)
Return StringRegExp($S, "^Verbunden") = 1
EndFunc
; #FUNCTION# ======================================================================================
; Name ..........: RunCmd()
; Description ...: runs commandline programs or cmd-command and return their output
; Syntax ........: RunCmd($s_Cmd, [$sParameter = '', [$b_CmdSpec = False, [$WorkDir = @WorkingDir]]])
; Parameters ....: $s_Cmd - the command which should be executed (can be full command or without parameters)
; $sParameter - additional parameters for the command (also array of parameters)
; $b_CmdSpec - If true the command is interpreted as a command for cmd.exe
; $WorkDir - the working directory
; Return values .: Success: returns a string with the output
; Failure: set @error and returns a debug-string
; Author ........: AspirinJunkie
; =================================================================================================
Func RunCmd($s_Cmd, $sParameter = '', $b_CmdSpec = False, $WorkDir = @WorkingDir)
Local Static $h_User32DLL = DllOpen('user32.dll')
If @error Then Return SetError(1, @error, "")
If $b_CmdSpec Then $s_Cmd = @ComSpec & " /c " & $s_Cmd
Local $s_Ret, $s_Line, $s_Err
If $sParameter <> '' Then
If IsArray($sParameter) Then
Local $s_Par = ""
For $j In $sParameter
$s_Par &= " " & _QiN($j)
Next
$sParameter = $s_Par
Else
$sParameter = ' ' & $sParameter
EndIf
EndIf
Local $iPID = Run($s_Cmd & $sParameter, $WorkDir, @SW_HIDE, 0x2 + 0x4)
If @error Then Return SetError(2, @error, "")
Do
$s_Line = StdoutRead($iPID)
If @extended > 0 Then $s_Ret &= $s_Line
If @error Then ExitLoop
Sleep(10)
Until 0
Do
$s_Line = StderrRead($iPID)
If @extended > 0 Then $s_Err &= $s_Line
If @error Then ExitLoop
Sleep(10)
Until @error
$s_Ret = DllCall($h_User32DLL, 'BOOL', 'OemToChar', 'str', $s_Ret, 'str', '')[2]
If $s_Err <> "" Then
If $s_Ret <> "" Then Return SetError(3, 0, "------- StdOut -----------" & @CRLF & $s_Ret & @CRLF & @CRLF & "------- StdErr -----------" & @CRLF & $s_Err)
Return SetError(3, 0, $s_Err)
EndIf
Return $s_Ret
EndFunc ;==>RunCmd
; adds quotes if white spaces and escapes tabs and vertical space
Func _QiN($s_String, Const $s_Quote = '"', Const $s_QEscape = '""', Const $s_TabEscape = Default, Const $s_LineEscape = Default)
; escape line breaks
If $s_LineEscape <> Default Then $s_String = StringRegExpReplace($s_String, '(\v)+', $s_LineEscape)
; escape tabs
If $s_TabEscape <> Default Then $s_String = StringRegExpReplace($s_String, '(\t)+', $s_TabEscape)
; quotes around if necessary
If StringInStr($s_String, ' ', 1) Then Return $s_Quote & StringReplace($s_String, $s_Quote, $s_QEscape, 0, 1) & $s_Quote
Return $s_String
EndFunc ;==>_QiN
Alles anzeigen
Changelog:
2021/02/10 |
|
2020/07/22 |
|
2020/07/21 |
|
2020/06/16 |
|