Microsoft Excel Column Generator

Hi guys,

Anyone got a way to take a number and spit out the appropriate column name for excel?

Both of the examples below fail for number’s above 26 that are multiples of 26 ( (26 * x) mod 26 = 0, and there’s no zeroth index for lists in applescript, so you get an error). The funny thing is that if this were a lesser code, like C++, then there’d be no problem.

I’d like to see a working version of this code. It seems silly that having list indices from 1-number instead of from 0-(number - 1) shouldn’t keep this kind of base conversion from being possible.

I’d also be very happy with some sort of built in functionality for this sort of thing, like an excel command.

Thanks,

Tim

Anyways, here’s one I wrote (sloppy, I know):

on excelColumn(num)
	set columnNum to num
	set column_ to {}
	set alphabet to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
	set degree to 0
	set degreeTest to 0
	set answer to ((columnNum - 1) div (26 ^ degreeTest))
	repeat until answer = 0
		set answer to ((columnNum - 1) div (26 ^ degreeTest))
		if answer = 0 then
			set degree to degreeTest - 1
		end if
		set degreeTest to degreeTest + 1
	end repeat
	
	if degree > 0 then
		set end of column_ to item (columnNum div (26 ^ degree)) of alphabet
		set i_ to degree
		repeat until i_ < 2
			set end of column_ to item ((columnNum div (26 ^ i_)) mod 26) of alphabet
			set i_ to i_ - 1
		end repeat
		set end of column_ to item (columnNum mod (26)) of alphabet
	else
		set end of column_ to item (columnNum div (26 ^ degree)) of alphabet
	end if
	
	return column_ as text
end excelColumn

and here’s one from Trash Man (http://macscripter.net/profile.php?id=9395):

columnLetterBase26(26) --> "z"
columnLetterBase26(27) --> "aa"
columnLetterBase26(28) --> "ab"
columnLetterBase26(289) --> "kc"

on columnLetterBase26(aDecimal)
   try
       set aDecimal to aDecimal as integer
   on error
       error "The parameter given to convert decimals to base 26 wasn't a number." from aDecimal to integer
   end try
   
   if aDecimal < 1 then error "The parameter given is smaller than 1" from aDecimal to integer
   
   local Base26
   set Base26 to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   
   -- search for largest exponent
   set exponent to 0
   repeat while (26 * (26 ^ exponent)) < aDecimal
       set exponent to exponent + 1
   end repeat
   
   -- fill string
   set repr26 to {}
   repeat while exponent ≥ 0
       
       -- find biggest suitable
       set baseNumber to 26
       repeat while (baseNumber * (26 ^ exponent)) > aDecimal
           set baseNumber to baseNumber - 1
       end repeat
       
       -- add letter
       set end of repr26 to item baseNumber of Base26
       
       -- addapt values
       set aDecimal to aDecimal - (baseNumber * (26 ^ exponent))
       set exponent to exponent - 1
       
   end repeat
   exponent
   
   
   return (repr26 as string)
end columnLetterBase26

Thanks,
TIm

Hello!

Say your column number is number 28: 28 div 26 is 1, 28 mod 26 is 2 A would be the first char, b would would be the second and you would end up with AB which shoukld be correct

say your column number is 256:

your high value is 256 / 26 and is 9 this should be translated to an I, your low value is 256 mod 26 is 22 this would leave you with “v” as the last char.

The edge case is when your number mod 26 i zero, then you have to subtract one from the high number, and put a z in as the last character.


set a to columnName(256)
log a

to columnName(n)
	local a
	set a to (ASCII number ("A")) - 1
	
	set highch to n / 26 as integer
	set lowch to n mod 26 as integer
	
	if lowch = 0 and highch = 0 then
		return ""
	else if lowch = 0 then
		set highch to highch - 1
		set lowch to 26
	end if
	
	if highch > 0 then
		return ((ASCII character (highch + a)) & (ASCII character (lowch + a)) as text)
	else
		return ((ASCII character lowch) + a) as text
	end if
	
end columnName

Isn’t that already basically what I’m doing in the top script? In the case of 28 the degree would be one, so 28 div 26 would give me one, and 28 mod 26 gives too. Both of the above scripts would work with a number like 28, but for a number like 52, 52 mod 26 is zero, and there’s no zeroth item of a list in AppleScript.

I’m fairly new to AppleScript, however. And I’m not entirely sure what you mean by “internally”.

Can you elaborate?

Thanks,

Tim

Hello

Try the handler, it should work

In the case of 52 you take one like in school subtraction, that leaves you with 1 as the high char, and z as the lowchar
which is az and correct.

I need coffee . :slight_smile:

sorry I have changed it to work correctly, and have reposted it! :slight_smile:

When I try the handler copied from your post, I get an error saying ‘a’ isn’t defined (which it is in the first line it seems…). If I scratch the first two lines and try to simply return the handler as text with some integer argument, only a blank “” returns.

I assume that ASCII character/number returns the character for an ASCII value, or the number for an ASCII character, but I can’t follow what’s going on in your handler. I’m also new to the log command, and to calling a handler with to rather than on.

But I’d love to learn!

Hello!

It works now, but try this, it should be faster. You got the developer version first! :smiley:


property alphabet : {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}

set a to columnName(289)
log a

to columnName(n)	
	
	set highch to n / 26 as integer
	set lowch to n mod 26 as integer
	
	if lowch = 0 and highch = 0 then
		return ""
	else if lowch = 0 then
		set highch to highch - 1
		set lowch to 26
	end if
	
	if highch > 0 then
		return item highch of my alphabet & item lowch of my alphabet
	else
		return item lowch of my alphabet
	end if
	
end columnName




It is early for me, and I posted it first, as I had overseen that it worked in my debugger, not realizing it didn’t return the actual result!

to is the same as on, -totally!

I removed those functions, to avoid unnecessary arithmetic, and gave you a faster version

I like it, but two things:

This handler stops working at 690, then works again at 702 ( (26^2) + 26 ). Could you modify it to apply to any number? .xlsx files support a huge number of rows and columns, so can this be modified for numbers above 26^4?

Entering 675 returns ZY (incorrect), but 676 returns YZ (correct).

Though your’s is definitely the most eloquently written of the three!

Hello!

Could you please tell me what you do mean by stop working at 690?

From 690 to 701, there’s an error that item 27 of the property can be found, and again from 703 to infinity (or 26^3), the error changes to item (26^2, or so) not being found, but it works for 702!

I’m getting the above results by putting a “return a” at the bottom, then fooling with the handler argument.

Hello!

Hello, I have fixed it and made it faster, I see having columns exceeding 26^2 columns in excel as something purely theorethical.

For some reason a rounding error were introduced, I have just subtractet the modulus value, before performing the division, to bypass that problem, and that should work correctly, in any case! :slight_smile:


property alphabet : {"", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}

set a to columnName(675)
log a

to columnName(n)
	local highch, lowch

        set n to n as integer

	set lowch to n mod 26 
	set n to n - lowch 
	set highch to n / 26 
	
	if lowch = 0 then
	    set highch to highch - 1
            set lowch to 26
	end if
	return item (highch + 1) of my alphabet & item (lowch + 1) of my alphabet
end columnName

the problem is this line

set highch to n / 26 as integer

to get the proper result use this

set highch to n div 26

btw: the result of the mod operation is always an integer, the coercion is not needed

Looks good. But, if we’re talking theoretically :P, might you expand this to include a higher upper bound on the possible conversion?

For most this would be unnecessary, surely, but I’ve got some gruesome engineering projects coming my way, for which I’m told there will be spreadsheets to the AAAA range. “For the love of God!” I say, but to no avail…

I suppose just adding two more variables, higherCh and highestCh, as n div 26^2 and n div 26^3?

So I’m full of crap it seems, as the max number of columns is just under 26^3.

Anyways. I’ll try and add that much to the handler you wrote. Thanks again!

Hello!

Thanks Stefan! I’d be sure to remember that coercing a number to an integer performs a rounding!

And Guten Morgen Switzerland! It is good to see you back! :slight_smile:

Handles columnames greater than 676 but not larger than 17575.

Well, if excel can deliver it, somebody may need it!

The forms of structuring data are many! maybe somebody transposes a large table, in order to sum values in some odd way. So, here you are! :slight_smile:


property alphabet : {"", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}

set a to columnName(679)
log a

to columnName(n)
	local bigch, highch, lowch, m
        if (n > 17575) then error "you better go back and ask for more! [url=http://macscripter.net/edit.php?id=153614]http://macscripter.net/edit.php?id=153614"[/url]
	set n to n as integer
	set m to n mod 676
	set bigch to (n - m) / 676
	set lowch to m mod 26
	set m to m - lowch
	set highch to m / 26
	
	
	if highch = 0 then
		set bigch to bigch - 1
		set highch to 26
	end if
	
	if lowch = 0 then
		set highch to highch - 1
		set lowch to 26
	end if
	return (item (bigch + 1) of my alphabet) & (item (highch + 1) of my alphabet) & item (lowch + 1) of my alphabet
end columnName


Looks great.

Don’t suppose you know anything about scripting for Tex-Edit Plus or some other scripts me text editor so I can select text relative to a known location. For example, I know that the 11 characters I want to select is 7 lines down and 5 spaces over from the result of a search in a large text file. Word, pages, or TextEdit is good too, or some text editor I’ve never heard of!

I posted here:

http://macscripter.net/viewtopic.php?id=39178

Thanks, you’ve already been a great help.

Tim

I beat you to it! :slight_smile:

Learn TextWrangler, it is free and decent! with lots of scripting examples floating around, there you can find and mark all, and use the markers as relative references.

this should convert any number to the alphabetical equivalent

to excelColumnToLetters(column)
	set letters to ""
	repeat while column > 0
		set remainder to column mod 26
		if remainder = 0 then set remainder to 26
		set letters to character id (remainder + 64) & letters
		set column to (column - remainder) div 26
	end repeat
	return letters
end excelColumnToLetters