Aside of the set of data, there are three optional parameters for the function:
[*:u84tv5c2]delim - intended to be an end of line (EOL) character(s) to delimit each line (the default is a single newline)
[*:u84tv5c2]lineDelim - a character(s) that will delimit within each line where tab spacing will be placed (the default is a single tab character)
[*:u84tv5c2]omit - intended to be a character(s) that can be omitted from the beginning or end of each line; this parameter is associated exclusively with the delim parameter (the default is a carriage return)
Here's an example usage:
chars=0123456789 Loop, 30 ; loop that will build a 30-line dataset with three columns of data, where each data chunk can contain between 1 and 10 characters { var .= !var ? "" : "`n" Loop, 3 { Random, n, 1, 10 Loop % n { Random, c, 1, % StrLen(chars) var .= SubStr(chars,c,1) } var .= A_Index=3 ? "" : "`t" } } MsgBox, , Unaligned, % var MsgBox, , Aligned, % tabAlign(var) tabAlign(var,delim="`n",lineDelim="`t",omit="") { Loop, parse, var, %delim%, % (delim="`n") ? "`r" : omit ; extracts a line from var to determine the number of fields { n := A_LoopField break } StringReplace, n, n, %lineDelim%, %lineDelim%, UseErrorLevel ; finds the number of fields based on lineDelim Loop % (c := ErrorLevel) ; loop to parse each column and find the longest string in each { i := A_Index Loop, parse, var, %delim%, % (delim="`n") ? "`r" : omit { Loop, parse, A_LoopField, %lineDelim% if (A_Index = i) max%i% := StrLen(A_LoopField) > max%i% ? StrLen(A_LoopField) : max%i% } max%i% += 8 - Mod(max%i%,8) ; takes the longest string for that column and rounds it to the nearest multiple of 8 } Loop, parse, var, %delim%, % (delim="`n") ? "`r" : omit ; parses var by line { StringSplit, p, A_LoopField, %lineDelim% ; splits line by lineDelim out .= (!out ? "" : delim) Loop % c ; loops through all columns fields but the last columns since it will not have tabs after it { i := A_Index, t := StrLen(p%i%) + (8 - Mod(StrLen(p%i%),8)), p%i% .= "`t" if m := (max%i% - t) / 8 ; if tab padding is required Loop % m p%i% .= "`t" ; pad it with the appropriate number of tabs } Loop % p0 out .= p%A_Index% ; write to new var } return out }
In the above example MsgBox should display the tab alignment properly, but this is not a typical case. Most times MsgBox will not present the tab alignment properly, but if you instead copy that data to the Clipboard and paste it to Notepad, the tab alignment will display correctly.
And for the sake of redundancy, the function:
tabAlign(var,delim="`n",lineDelim="`t",omit="") { Loop, parse, var, %delim%, % (delim="`n") ? "`r" : omit { n := A_LoopField break } StringReplace, n, n, %lineDelim%, %lineDelim%, UseErrorLevel Loop % (c := ErrorLevel) { i := A_Index Loop, parse, var, %delim%, % (delim="`n") ? "`r" : omit { Loop, parse, A_LoopField, %lineDelim% if (A_Index = i) max%i% := StrLen(A_LoopField) > max%i% ? StrLen(A_LoopField) : max%i% } max%i% += 8 - Mod(max%i%,8) } Loop, parse, var, %delim%, % (delim="`n") ? "`r" : omit { StringSplit, p, A_LoopField, %lineDelim% out .= (!out ? "" : delim) Loop % c { i := A_Index, t := StrLen(p%i%) + (8 - Mod(StrLen(p%i%),8)), p%i% .= "`t" if m := (max%i% - t) / 8 Loop % m p%i% .= "`t" } Loop % p0 out .= p%A_Index% } return out }
Any questions or comments are welcome.