|
Vielleicht benötigen Sie gelegentlich die Umsetzung eines zweidimensionalen Arrays in einen String aus Zeilen und Spalten, etwa für eine CVS-Datei oder zum Einfügen in ein Grid-Steuerelement oder eine Excel-Tabelle. Ebenso können Sie vielleicht die Umsetzung in der Gegenrichtung brauchen, von einem derartigen String in ein zweidimensionales Array.
Auf den ersten Blick mag Umsetzung vom Array zum String mittels zweier verschachtelter Schleifen und fortwährendem Anhängen an einen wachsenden String recht trivial erscheinen. Bei kleinen Arrays mit nur wenigen "Zeilen" und "Spalten" ist das auch praktikabel. Bei umfangreicheren Arrays dagegen kostet das ständige Anhängen neuer Spalten und Zeilen an den String ziemlich viel Zeit, da bei jedem Anhängen der String einmal im Speicher umkopiert wird. Selbst eine erste Optimierung, bei der jeweils eine ganze Zeile aus den "Spalten" zusammengesetzt und erst dann an den Gesamt-String angehängt wird, bringt keinen deutlichen Vorteil.
Erheblich günstiger ist es, wenn Sie gleich zu Beginn einen (noch leeren) String bereit stellen, der in den Schleifen nach und nach vom Anfang mit den Inhalten der Array-Elemente mittels der überschrieben wird (siehe auch "Mid-Wirkungen"). Auf jedes Element folgt natürlich noch der jeweilige Spalten-Trenner - etwa ein Tabulator-Zeichen oder ein Listentrennzeichen (Semikolon o.ä.) - oder der Zeilen-Trenner (vbNewLine).
Wenn Sie bereits vorab wissen, wie lang das längste Array-Element ist, können Sie die erforderliche Länge des bereitzustellenden Leer-Strings anhand der beiden Dimensionen des Arrays leicht ermitteln, unter Berücksichtigung der Längen der zusätzlich einzufügenden Trenner. Da wohl die meisten Elemente nicht die Maximal-Länge erreichen, wird der leere String voraussichtlich nicht komplett gefüllt werden - das abschließende Kürzen auf die tatsächliche Füll-Länge ist aber kein Problem.
Kennen Sie die Länge des längsten Array-Elements nicht im Voraus, müssen Sie diese zuvor noch in einem separaten Schleifendurchlauf ermitteln. Das ist jedoch hinsichtlich der Performance immer noch günstiger, als das eingangs erwähnte Anhängeverfahren.
Der folgenden Funktion MultiDimArrayToString übergeben Sie mindestens das umzusetzende Array. Wenn die größte "Spalten"-Länge bekannt ist, können Sie diese im zweiten, optionalen Parameter MaxColSize übergeben. In den beiden darauf folgenden optionalen Parametern RowSeparator und ColSeparator können Sie andere als die voreingestellten Trenner übergeben - als Spaltentrenner sind ein Tabulatorzeichen (vbTab) und der übliche Zeilentrenner (vbNewLine) vorgesehen. Standardmäßig vorgegeben ist auch, dass die erste Dimension die "Zeilen" und die zweite Dimension die "Spalten" repräsentiert - sollten Sie es umgekehrt benötigen, setzen Sie den letzten optionalen Parameter FirstDimensionIsRow auf False.
Public Function MultiDimArrayToString(Arr() As String, _
Optional ByVal MaxColSize As Long, _
Optional RowSeparator As String = vbNewLine, _
Optional ColSeparator As String = vbTab, _
Optional ByVal FirstDimensionIsRow As Boolean = True) As String
Dim r As Long
Dim c As Long
Dim nRows As Long
Dim nCols As Long
Dim nLenRowSeparator As Long
Dim nLenColSeparator As Long
Dim nLen As Long
Dim nString As String
Dim nPos As Long
Dim nLenItem As Long
nLenRowSeparator = Len(RowSeparator)
nLenColSeparator = Len(ColSeparator)
nPos = 1
If FirstDimensionIsRow Then
If MaxColSize = 0 Then
For r = LBound(Arr, 1) To UBound(Arr, 1)
For c = LBound(Arr, 2) To UBound(Arr, 2)
nLenItem = Len(Arr(r, c))
If nLenItem > MaxColSize Then
MaxColSize = nLenItem
End If
Next 'c
Next 'r
End If
nRows = (UBound(Arr, 1) - LBound(Arr, 1)) + 1
nCols = (UBound(Arr, 2) - LBound(Arr, 2)) + 1
nLen = nRows * nCols * MaxColSize
nLen = _
nLen + (nRows * ((nCols * nLenColSeparator) + nLenRowSeparator))
nString = Space(nLen)
For r = LBound(Arr, 1) To UBound(Arr, 1)
For c = LBound(Arr, 2) To UBound(Arr, 2)
Mid$(nString, nPos) = Arr(r, c) & ColSeparator
nPos = nPos + Len(Arr(r, c)) + nLenColSeparator
Next 'c
nPos = nPos - nLenColSeparator
Mid$(nString, nPos, nLenRowSeparator) = RowSeparator
nPos = nPos + nLenRowSeparator
Next 'r
Else
If MaxColSize = 0 Then
For r = LBound(Arr, 2) To UBound(Arr, 2)
For c = LBound(Arr, 1) To UBound(Arr, 1)
nLenItem = Len(Arr(c, r))
If nLenItem > MaxColSize Then
MaxColSize = nLenItem
End If
Next 'c
Next 'r
End If
nRows = (UBound(Arr, 2) - LBound(Arr, 2)) + 1
nCols = (UBound(Arr, 1) - LBound(Arr, 1)) + 1
nLen = nRows * nCols * MaxColSize
nLen = _
nLen + (nRows * ((nCols * nLenColSeparator) + nLenRowSeparator))
nString = Space(nLen)
For r = LBound(Arr, 2) To UBound(Arr, 2)
For c = LBound(Arr, 1) To UBound(Arr, 1)
Mid$(nString, nPos) = Arr(c, r) & ColSeparator
nPos = nPos + Len(Arr(c, r)) + nLenColSeparator
Next 'c
nPos = nPos - nLenColSeparator
Mid$(nString, nPos, nLenRowSeparator) = RowSeparator
nPos = nPos + nLenRowSeparator
Next 'r
End If
MultiDimArrayToString = Left$(nString, nPos - 1)
End Function
Die Umkehrung bietet die Funktion StringToMultiDimArr. Im Gegensatz zur vorhergehenden Funktion wird hier die maximale Anzahl der Spalten benötigt, damit das zurückzugebende Array dimensioniert werden kann. Sie können diese Anzahl im zweiten Parameter MaxCols nach der natürlich obligatorischen Angabe des umzusetzenden Strings optional angeben. Kennen Sie die Anzahl nicht im Voraus, wird sie automatisch ermittelt. Die übrigen Parameter entsprechen denen der oben stehenden Funktion.
Public Function StringToMultiDimArr(Text As String, _
Optional ByVal MaxCols As Long, _
Optional RowSeparator As String = vbNewLine, _
Optional ColSeparator As String = vbTab, _
Optional ByVal FirstDimensionIsRow As Boolean = True) As String()
Dim nRows() As String
Dim nCols() As String
Dim nRowsCount As Long
Dim nRows2 As Variant
Dim nRowCols As Long
Dim r As Long
Dim c As Long
Dim nArr() As String
Dim nMaxCols As Long
nRows = Split(Text, RowSeparator)
If Len(nRows(UBound(nRows))) Then
nRowsCount = UBound(nRows)
Else
nRowsCount = UBound(nRows) - 1
End If
ReDim nRows2(0 To nRowsCount)
If MaxCols = 0 Then
For r = 0 To nRowsCount
nRows2(r) = Split(nRows(r), ColSeparator)
nRowCols = UBound(nRows2(r))
If nRowCols > MaxCols Then
MaxCols = nRowCols
End If
Next 'r
End If
If FirstDimensionIsRow Then
ReDim nArr(0 To UBound(nRows2), 0 To MaxCols)
For r = 0 To UBound(nRows2)
nRowCols = UBound(nRows2(r))
For c = 0 To nRowCols
nArr(r, c) = nRows2(r)(c)
Next 'c
Next 'r
Else
ReDim nArr(0 To MaxCols, 0 To UBound(nRows2))
For r = 0 To UBound(nRows2)
nRowCols = UBound(nRows2(r))
For c = 0 To nRowCols
nArr(c, r) = nRows2(r)(c)
Next 'c
Next 'r
End If
StringToMultiDimArr = nArr
End Function
Die in dieser Funktion verwendete Split-Funktion steht allerdings erst ab Visual Basic 6 zur Verfügung. Um die Funktion in Visual Basic 5 verwenden zu können, können Sie beispielsweise die in "Teile-Haberschaft" vorgestellte Ersatz-Funktion verwenden.
|