Jump to content

How to get StringSplit to output columns instead of rows?


kor
 Share

Recommended Posts

The array just holds the data. It's up to you how you display it. If you need that layout with _arraydisplay you could build a new array with many dimensions each with the content in the first 'row'- array[0][1], array[0][2],array[0]3]... array[0][n] . But i think n cannot exceed 64 [or 63 if you have a zero start].

William

Link to comment
Share on other sites

Oops

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

  • Moderators

saywell,

But i think n cannot exceed 64

As I read the limitation, you cannot have more than 64 pairs of [] after the array name. :)

There is a difference between the number of dimensions and the value of each dimension:

The number of dimensions increases with each [] pair:

1D array - aArray[n1]

2D array - aArray[n1][n2]

3D array - aArray[n1][n2][n3]

...

64D array - aArray[n1][n2][n3].....[n63][n64]

The value of the dimension is the number in each [] pair.

This is a common misunderstanding that often raises its head when discussing ReDim. ReDim will retain the existing values of an array (as far as possible) if you change the values of the existing dimensions. If you alter the number of dimensions, it creates a new empty array. :)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

@M23

so what we need here, to get the display required with _arraydisplay, is a 2-D array, of which only one 'row' is used, with as many values as you like, in effect?

Ie I misunderstood the terminology of 'dimensions'.

I think a 64-D array would be incredibly difficult to keep a mental track of!

William

Link to comment
Share on other sites

  • Moderators

saywell,

so what we need here, to get the display required with _arraydisplay, is a 2-D array, of which only one 'row' is used, with as many values as you like, in effect?

Correct. :)

I think a 64-D array would be incredibly difficult to keep a mental track of!

I have used a 6D array once - 4 of these dimensions held only 1 or 0 - and I found that just about manageable. I had several parameters to keep track of and this seemed the easiest way at the time. Nowadays I would add 1-2-4-8-16-etc to a single parameter and use BitAND to determine if a particular value was set - that would reduce the array to 3D and keep my hair in place. :)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Eek, to use up to 64D you just need up to 64 neurons. I mean you don't need to master superstring theory to reach high dimensions.

Almost everyone uses objects having _much_ more than 3 or 4 dimensions:

country

region

zip code

city

street

street number

building

entrance

floor

appartment number

owner name

owner first name

destinee name

destinee first name

Of course all these 14 dimensions are not always needed for precise location of every destinee, but many of them are necessary for common shipments and all of them are eventually used.

Such a (theorical) array is extremely sparse due to lack of need for some components in most addresses, but that causes no problem for most people to understand the idea that all these dimensions are actually formally independant.

Nobody will object that for precise location of a part of an object placed in a given room of an address, one will clearly need more dimensions again. Like the ENTER key of the keyboard on the left bench in the second room at the first floor of my house...

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

  • Moderators

jchd,

I know what you mean, but surely one of your beloved databases is better to hold something akin to the structure you just suggested? :)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

What I need to do is take the following text

mark,jones,11033,business

david,smith,11022,manager

mike,johnson,10229,supervisor

And convert to an array that looks like

post-48155-0-81066400-1301593669_thumb.j

Edited by kor
Link to comment
Share on other sites

Tweak and enjoy :)

#include <Array.au3>

$DataString = "Name,Job,Salary|John Doe,Programmer,$50000.00|Mary Jane,Reporter,$20000.00|Cole Brown,Actor,$1000000.00"

$rows = StringSplit($DataString, "|")
$cols = StringSplit($rows[1], ",")

Dim $table[$rows[0]][$cols[0]]

For $i = 1 To $rows[0]
    $cols = StringSplit($rows[$i], ",")
    For $j = 1 To $cols[0]
        $table[$i - 1][$j - 1] = $cols[$j]
    Next
Next

_ArrayDisplay($table)
Link to comment
Share on other sites

Here my version:

#include <Array.au3>

$gs_dummydata = ""
$gs_dummydata &= "john,smith,12345" & @CRLF
$gs_dummydata &= "josh,jones,34556,supervisor" & @CRLF
$gs_dummydata &= "" & @CRLF ; empty line
$gs_dummydata &= "zach,marks,98222,worker,extra column not expected" & @CRLF
$gs_dummydata &= "jake,warren,10984,worker" & @CRLF ; (last line will actually be empty because of CRLF)

$aS = StringSplitW($gs_dummydata, ",")
_ArrayDisplay($aS)

; #FUNCTION# ======================================================================================
; Name ................:     StringSplitW()
; Version .............:    v0.80 build 2011-05-05 beta
; Description .......:    Splits  a string into columns instead of rows as it is done by SplitString(), like a csv file to a 2d array ;-)
; Syntax ..............:    StringSplitW($string, $delimiter, $max_width)
; Parameters ........:    $string - string to split
;                                  $delimiter - the delimter how to split the string
; Return values ....:     Success - 2d array
;                                  Failure 1 - either $string or $delimter is not set
;                                  Failure 2 - array width exceeded
;                                  Failure 3 - 2D array memory exceeded -> width + height > 0x5EFA
; Author ..............:    UEZ
; Modified ............:
; Remarks ............:
; Related ..............:    StringSplit()
; =================================================================================================
Func StringSplitW($string, $delimiter)
    If $string = "" Or $delimiter = "" Then Return SetError(1, 0, 0)
    Local $chk, $width, $i, $j, $k, $len, $max = 1, $max_width
    Local $aPos[1], $l = 0
    Local $aSplit =  StringSplit($string, @LF)
    $max_width = 0x5EFA - $aSplit[0]
    If $max_width < 1 Then Return SetError(3, 0, 0)
    Local $aVertical[$aSplit[0]][$max_width]
    For $k = 1 To $aSplit[0]
        $len = StringLen($aSplit[$k])
        If $len > 1 Then
            $chk = StringReplace($aSplit[$k], $delimiter, $delimiter)
            $width = @extended
            If $width > $max_width Then Return SetError(2, 0, 0)
            If $width > $max Then $max = $width + 1
            Switch $width
                Case 0
                    $aVertical[$l][0] = $aSplit[$k]
                Case Else
                    Dim $aPos[$width * 2 + 2]
                    $j = 1
                    $aPos[0] = 1
                    For $i = 0 To $width - 1
                        $aPos[$j] = StringInStr($aSplit[$k], $delimiter, 0, $i + 1) - 1
                        $aPos[$j + 1] = $aPos[$j] + 2
                        $j += 2
                    Next
                    $aPos[UBound($aPos) - 1] = StringLen($aSplit[$k])
                    $j = 0
                    For $i = 0 To UBound($aPos) - 1 Step 2
                        $aVertical[$l][$j] = StringMid($aSplit[$k], $aPos[$i], $aPos[$i + 1] - $aPos[$i] + 1)
                        $j += 1
                    Next
                EndSwitch
                $l += 1
        EndIf
    Next
    ReDim $aVertical[$l][$max]
    Return $aVertical
EndFunc

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

If you have a text file, you could do something like this:

#include <file.au3>
#include <array.au3>

Dim $a_contents, $a_temp

_FileReadToArray("inputfile", $a_contents)

$a_temp = StringSplit($a_contents[$a_contents[0]], ",")

Dim $a_display[$a_contents[0]][$a_temp[0]]

For $i = 1 To $a_contents[0]
    $a_temp = StringSplit($a_contents[$i], ",")
    For $j = 1 To $a_temp[0]
        $a_display[$i - 1][$j -1] = $a_temp[$j]
    Next
Next

_ArrayDisplay($a_display)

:)

Regards,Hannes[spoiler]If you can't convince them, confuse them![/spoiler]
Link to comment
Share on other sites

  • Moderators

Does the data come from an array you've created, or are you copying the data straight from a text/csv file?

If you're copying from a text/csv file, then there, each line break is a "row", and each comma is a "column".

For that you could pretty much use Hannes123 example.

If you're manually creating this data; from the example you provided, then each array index is a row, and instead of using Hannes123 exact example, you'd modify it something like:

#include <file.au3>
#include <array.au3>

Dim $a_contents, $a_temp

Dim $data[4]
$data[0] = "john,smith,12345,manager"
$data[1] = "josh,jones,34556,supervisor"
$data[2] = "zach,marks,98222,worker"
$data[3] = "jake,warren,10984,worker"

$a_temp = StringSplit($data[UBound($data) - 1], ",")

Dim $a_display[UBound($data)][$a_temp[0]]

For $i = 0 To UBound($data) - 1
    $a_temp = StringSplit($data[$i], ",")
    For $j = 1 To $a_temp[0]
        $a_display[$i][$j -1] = $a_temp[$j]
    Next
Next

_ArrayDisplay($a_display)

Keep in mind, this is not really a "true" fix, in csv data, often you have to contend with quoted strings that have commas in them that are not a delimiter. It also does not verify that all the columns are the same count so you could run into array subscript errors.

I haven't looked at UEZ's method, he may have a fix for all that in there.

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

It also does not verify that all the columns are the same count so you could run into array subscript errors.

Is there a way to check for this before proceeding? Something simple like just checking if any cell is blank, then throw an error.

I'm also having difficulty removing empty rows now that my array is a 4x4 or 5x5.

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#Include <GuiRichEdit.au3>
#include <Array.au3>

Example1()

Func Example1()
    Local $msg

    Global $maingui = GUICreate("My GUI", 200, 200) ; will create a dialog box that when displayed is centered
    
    $button = GUICtrlCreateButton("Bulk", 50, 50, 80, 30)
    GuiCtrlSetState($button, $GUI_FOCUS)

    GUISetState(@SW_SHOW) ; will display an empty dialog box

    ; Run the GUI until the dialog is closed
    While 1
        $msg = GUIGetMsg()
        Switch $msg
            Case $button
                _Create()
            Case $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch
    WEnd
    GUIDelete()
EndFunc   ;==>Example1

Func _Create()
    Global $header = "FirstName,LastName,StaffID,Location"
    Local $msg
    $creategui = GUICreate("bulk create", 250, 290)
    Global $edit = _GUICtrlRichEdit_Create($creategui, $header & @CR, 10, 10, 230, 230, BitOr($ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL))
    $button1 = GUICtrlCreateButton("Ready", 70, 250, 80, 30)
    GUISetState()
    
        While 1
        $msg = GUIGetMsg()
        Switch $msg
            Case $button1
                _stuff()
            Case $GUI_EVENT_CLOSE
                GUIDelete()
                Exit
        EndSwitch
    WEnd
EndFunc

Func _stuff()
    Local $sTmp = ''
    $result = _GuiCtrlRichEdit_GetText($edit)
    $result = StringRegExpReplace($result, @CR, "|")


$rows = StringSplit($result, "|")
$cols = StringSplit($rows[1], ",")

Dim $table[$rows[0]][$cols[0]]

For $i = 1 To $rows[0]
    $cols = StringSplit($rows[$i], ",")
    For $j = 1 To $cols[0]
        $table[$i - 1][$j - 1] = $cols[$j]
    Next
Next

_ArrayDisplay($table)

For $x = 1 to UBound($table) - 1 ;>>>>>>>>>>>>>>>>>>> problem
    If $table[$x] == "" then
        _ArrayDelete($table, $x)
    EndIf
Next
_ArrayDisplay($table)

    Exit
EndFunc

If you run the code and have a CRLF anywhere, or if a user presses enter after pasting all the data I want to delete any blank rows.

Edited by kor
Link to comment
Share on other sites

Well, I can get the array to delete blank rows, but not if the last row is blank.

Func _stuff()
    Local $sTmp = ''
    $result = _GuiCtrlRichEdit_GetText($edit)
    $result = StringRegExpReplace($result, @CR, "|")


$rows = StringSplit($result, "|")
$cols = StringSplit($rows[1], ",")

Dim $table[$rows[0]][$cols[0]]

For $i = 1 To $rows[0]
    $cols = StringSplit($rows[$i], ",")
    For $j = 1 To $cols[0]
        $table[$i - 1][$j - 1] = $cols[$j]
    Next
Next

_ArrayDisplay($table)

For $x = 1 To UBound($rows) - 1
    If $rows[$x] == "" Then
        _ArrayDelete($table, $table[$x][0])
    EndIf
Next

_ArrayDisplay($table)

    Exit
EndFunc

I'm sure my mistake is stupid. If there are blank rows anywhere, the second loop will delete them, unless the last row is blank. In that case, I get array subscript errors.

EDIT:

For $x = Ubound($rows) - 1 to 0 Step - 1
    If $rows[$x] == "" then
        _ArrayDelete($table, $table[$x][0])
    EndIf
Next

This code seems to work better to delete any and all blank rows between rows 0 through n-1. However is row n is blank Im still getting subscript errors.

EDIT2:

NEvermind, none of my loops are doing what they are supposed to do. I'm utterly lost on how to delete blank rows from a multidimensional array and also be able to delete row N if the last row in the array is blank too.

Edited by kor
Link to comment
Share on other sites

  • Moderators

Hmm, maybe if we broke it down into steps:

#include <Array.au3>

Global $gs_dummydata = ""
$gs_dummydata &= "john,smith,12345,manager" & @CRLF
$gs_dummydata &= "josh,jones,34556,supervisor" & @CRLF
$gs_dummydata &= "" & @CRLF ; empty line
$gs_dummydata &= "zach,marks,98222,worker,extra column not expected" & @CRLF
$gs_dummydata &= "jake,warren,10984,worker" & @CRLF ; (last line will actually be empty because of CRLF)

; Get the initial rows
Global $ga_Array = __myGetRows($gs_dummydata, 1)
_ArrayDisplay($ga_Array)

; Function I wrote the other day for someone to remove strings from a 1D array
;   in this case an empty one ( blank line )
;   just use it like this, don't deviate other than your array name you pass
Global $ga_NoEmptyLines = __ArrayExclude1D($ga_Array, "", 1, True)
_ArrayDisplay($ga_NoEmptyLines)

; Transfer your row array into rows and column array
Global $ga_RowsCols2D = __myGetRowsCols($ga_NoEmptyLines, 1, ",")
_ArrayDisplay($ga_RowsCols2D)

Func __myGetRowsCols($a_rows, $i_base = 0, $s_col_delim = ",")

    If Not IsArray($a_rows) Then Return SetError(1, 0, 0)

    If Int($i_base) < 1 Then $i_base = 0

    Local $i_row_max = UBound($a_rows) - 1
    Local $a_cols = StringSplit($a_rows[$i_row_max], $s_col_delim, 1)
    Local $i_col_max = $a_cols[0], $i_rownext = 1

    Local $a_rowcol[$i_row_max + 1][$i_col_max]

    For $irow = $i_base To $i_row_max
        $a_cols = StringSplit($a_rows[$irow], $s_col_delim, 1)

        ; protection in case one of the rows has more cols than the default
        If $a_cols[0] > $i_col_max Then
            $i_col_max = $a_cols[0]
            ReDim $a_rowcol[$i_row_max + 1][$i_col_max]
        EndIf

        For $icol = 1 To $a_cols[0]
            $a_rowcol[$i_rownext][$icol - 1] = $a_cols[$icol]
        Next

        $i_rownext += 1
    Next

    ReDim $a_rowcol[$i_rownext][$i_col_max]
    $a_rowcol[0][0] = $i_rownext - 1

    Return $a_rowcol
EndFunc

Func __myGetRows($s_data, $i_base = 1); $i_base if 1 then [0] holds row count

    If StringLen($s_data) = 0 Then Return SetError(1, 0, 0)

    If Int($i_base) <> 1 Then $i_base = 2

    ; Find row delimiter; assuming it's based on separate lines
    If StringInStr($s_data, @CRLF, 1) Then
        Return StringSplit(StringStripCR($s_data), @LF, $i_base)
    ElseIf StringInStr($s_data, @CR, 1) Then
        Return StringSplit($s_data, @CR, $i_base)
    ElseIf StringInStr($s_data, @LF, 1) Then
        Return StringSplit($s_data, @LF, $i_base)
    EndIf

    ; There are no line separators
    ;  Whole string is in array as a row
    Local $i_ub = 1
    If $i_base = 1 Then $i_ub = 2
    Local $a_lines[$i_ub]
    If $i_ub = 2 Then
        $a_lines[0] = 1
        $a_lines[1] = $s_data
    Else
        $a_lines[0] = $s_data
    EndIf

    Return $a_lines
EndFunc

; array to search ( mandatory param; must be an array )
; exclude value ( mandatory param )
; base to start ( if you use normal stringsplit to create the array, it will be 1 ) ( default is zero )
; if you want [0] index zero to contain the total indexes available ( default is no )
; the max bounds you want to search the array ( default is all of the indexes )
; case sensitive ( default is no )
Func __ArrayExclude1D(ByRef $a_arr, $s_excludeval, $i_base = 0, $f_zeroindextotal = False, $i_max = -1, $f_case = False)

    If Not IsArray($a_arr) Then Return SetError(1, 0, 0)

    If Int($i_max) < 1 Then $i_max = UBound($a_arr) - 1
    Local $a_ret[$i_max + 1], $i_add = 0
    If $f_zeroindextotal Then $i_add += 1

    If $f_case Then
        For $i = $i_base To $i_max
            If Not ($a_arr[$i] == $s_excludeval) Then
                $a_ret[$i_add] = $a_arr[$i]
                $i_add += 1
            EndIf
        Next
    Else
        For $i = $i_base To $i_max
            If $a_arr[$i] <> $s_excludeval Then
                $a_ret[$i_add] = $a_arr[$i]
                $i_add += 1
            EndIf
        Next
    EndIf

    If $i_add = 0 Or ($i_add = 1 And $f_zeroindextotal) Then
        Return SetError(2, 0, 0)
    EndIf

    ReDim $a_ret[$i_add]
    If $f_zeroindextotal Then $a_ret[0] = $i_add - 1

    Return $a_ret
EndFunc
Edited by SmOke_N
forgot closing tag

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

@SmOke_N: good hint with empty lines!

I modified my code a little bit to check also empty lines. Look to post#13.

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...