Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

tabAlign() - function to tab align columnar data


  • Please log in to reply
3 replies to this topic
sinkfaze
  • Moderators
  • 6367 posts
  • Last active: Nov 30 2018 08:50 PM
  • Joined: 18 Mar 2008
On occassion I need to be able to convert data in text files from being tab delimited to a truly tab aligned format where each column of data is distinct, making the data easier to read with the naked eye. This function will take a set of data and convert it to such a tab aligned structure. The number used to calculate the tab alignment is 8, which is the maximum number of characters a tab can consume in Notepad. Theoretically that number could be changed to accomodate other programs but I have not delved into that.

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.

HansBKK
  • Members
  • 14 posts
  • Last active: Dec 22 2011 03:36 PM
  • Joined: 09 Dec 2011
The msgbox doesn't show the alignment, nor can I select the text it does display to copy it anywhere.

Isn't there a way to get msgbox to display with a monospace font?

sinkfaze
  • Moderators
  • 6367 posts
  • Last active: Nov 30 2018 08:50 PM
  • Joined: 18 Mar 2008

...nor can I select the text it does display to copy it anywhere.


A helpful reminder:

Tip: Pressing Control-C while a MsgBox window is active will copy its text to the clipboard. This applies to all MsgBoxes, not just those produced by AutoHotkey.



tfman
  • Guests
  • Last active:
  • Joined: --
Somewhat related, "experimental" function
_TF_ConvertToFixedColumn() a possible addition to the TF lib
http://www.autohotke...300.html#409300
(posted for reference, parses D/CSV data and you can choose an alignment left, center, right. Aligned using spaces, not tabs like sinkfazes' tabalign func.)