Using JS to format a dynamic number - javascript

I have an ad I'm working on that displays user inputs from another page but since these inputs can be large numbers, I need to apply JS to format them to be $1K instead of $1000, $1M instead of $1,000,000 and so on. I've tried a few scripts that work in the console but aren't connecting with the HTML that has a value (that I input just to test the JS). I need to make sure this will work on whatever's inside the span tag since on the actual ad there will be a dynamic value that is pulling in whatever the user's input was. I'm pretty sure the issue is in regards to how I'm calling the value inside the first span with the #old id/ .current class, but I've tried several iterations of how to target that value and am getting further from the fix.
I have two JS scripts that are commented out currently, Attempt 1 and Attempt 2 and I'm wondering if it is in relation to the variable that is being defined before the function in Attempt 2 or if there's something missing at the end of either to have the script applied to the value I'm targeting.
Here's the codepen I have so far: http://codepen.io/linzgroves/pen/KgGPGX
If anyone has suggestions on what to adjust here, that'd be super helpful. Thank you!
P.S. I have looked at (and tried) several of the similar questions that have been asked about JS number formatting (such as this) but my issue seems to be more a matter of me incorrectly targeting the value within the span tag and not with the JS itself. However, if there is a similar question related to targeting elements correctly, I'd be happy to pointed towards that as well!
Also, let me know if there's additional information I need to provide.
Thanks!
<div id="container">
<div id="inner">
<div id="message_container">
<div id="roi-headline">
<h2>Cool Header</h2>
<h1>An even cooler headline</h1>
</div>
<div id="roi-values">
<div id="roi-value-1">
<div id="roi-value-1-graph" style="width:75%;">
<em>from</em> <sup>$</sup>
<span id="old" class="current">
100000
</span>
</div>
</div>
<div id="roi-value-2">
<div id="roi-value-2-graph" style="width:100%;">
<em>to</em>
<span><sup>$</sup>15<sup>K</sup></span>
</div>
</div>
</div>
<div id="button">Learn More</div>
</div>
</div>
</div>
Edit: Updated the following var to include .innerText
/* Attempt 1 */
var num = document.getElementById("old").innerText;
function nFormatter(num) {
if (num >= 1000000000) {
return (num / 1000000000).toFixed(1).replace(/\.0$/, '') + 'G';
}
if (num >= 1000000) {
return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
}
if (num >= 1000) {
return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
}
return num;
};
/* Attempt 2 */
var value = "span.current";
function prettifyNumber(value) {
var thousand = 1000;
var million = 1000000;
var billion = 1000000000;
var trillion = 1000000000000;
if (value < thousand) {
return String(value);
}
if (value >= thousand && value <= 1000000) {
return Math.round(value/thousand) + 'k';
}
if (value >= million && value <= billion) {
return Math.round(value/million) + 'M';
}
if (value >= billion && value <= trillion) {
return Math.round(value/billion) + 'B';
}
else {
return Math.round(value/trillion) + 'T';
}
};

Your functions work just fine - if you want the changes reflected in the DOM, you will have to set the innerText or innerHTML of your #old element.
You can accomplish this by changing your nFormatter() function like so:
var num = document.getElementById("old");
function nFormatter(num) {
var oldNumber = num.innerText;
var newNumber = oldNumber;
if (oldNumber >= 1000000000) {
newNumber = (oldNumber / 1000000000).toFixed(1).replace(/\.0$/, '') + 'G';
}
if (oldNumber >= 1000000) {
newNumber = (oldNumber / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
}
if (oldNumber >= 1000) {
newNumber = (oldNumber / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
}
num.innerText = newNumber;
}
OR you can pass it just the number and use the returned result to set the innerText or innerHTML
var num = document.getElementById("old");
function nFormatter(num) {
if (num >= 1000000000) {
return (num / 1000000000).toFixed(1).replace(/\.0$/, '') + 'G';
}
if (num >= 1000000) {
return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
}
if (num >= 1000) {
return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
}
return num;
}
num.innerText = nFormatter(num.innerText);

Here is an updated codepen. You were doing <= the upper bound and >= the lower bound on each if statement. This would cause multiple if's to be true. Also, have to make sure you call your function after you create it and I would advise not using the same name for a global variable and a parameter to a function. It can cause some confusing behavior.
var value1 = document.getElementById("old");
function prettifyNumber(value) {
var thousand = 1000;
var million = 1000000;
var billion = 1000000000;
var trillion = 1000000000000;
value = parseInt(value);
var retVal = "";
if (value < thousand) {
retVal = String(value);
}
if (value >= thousand && value < million) {
retVal = Math.round(value/thousand) + 'k';
}
if (value >= million && value < billion) {
retVal = Math.round(value/million) + 'M';
}
if (value >= billion && value < trillion) {
retVal = Math.round(value/billion) + 'B';
}
if(value > trillion) {
retVal = Math.round(value/trillion) + 'T';
}
value1.innerHTML = retVal;
};
prettifyNumber(value1.innerText);

In both attempts you are missing a basic step, that is: you are not invoking the function.
The fact that you are calling the function argument with the same name of the variable is not enough. On the contrary, the function argument hides the external variable, that therefore won't be accessible by name inside the function. Anyway, this is just an additional consideration, not the real problem.
Consider attempt 1. After the function definition, you should add the actual invocation, something like
document.getElementById("old").innerText = nFormatter(num);
Attempt 2 has basically the same issue (i.e. no function call), but also you must obtain the desired element (with document.querySelectorAll for instance) before handing in to the prettifyNumber function.
Summarizing, the first attempt is the most correct one among the two, keeping in mind that both functions work fine.

Related

Why does the variable always outputs 1, even though it's incremented in Javascript

I tried solving a Problem I found online. I successfully solved the problem, but there's one small error that I couldn't solve.
The Problem
Write a guessing game where the user has to guess a secret number.
After every guess the program tells the user whether their number was
too large or too small. At the end the number of tries needed should
be printed.
Here's my code:
// Generate a random number between 1 and 100
var num = Math.floor(Math.random() * (100)) + 1;
var running = true;
while(running) {
var tries = 1;
var input = prompt("Take a guess");
if (input == num) {
console.log("Correct!");
console.log("Number of tries: " + tries);
running = false;
}else if (input > num) {
console.log("Too big");
}else if (input < num) {
console.log("Too small");
}
tries++;
}
Bug
Even if the user takes more than 1 try, the program still says,
Number of tries: 1
Please explain what am I doing wrong.
Thank You.
You reinitialize tires on each iteration of your while loop:
while(running) {
var tries = 1;
...
}
Try initializing outside of your loop.
var num = Math.floor(Math.random() * (100)) + 1;
var running = true;
var tries = 1;
while(running) {
var input = prompt("Take a guess");
if (input == num) {
console.log("Correct!");
console.log("Number of tries: " + tries);
running = false;
}else if (input > num) {
console.log("Too big");
}else if (input < num) {
console.log("Too small");
}
tries++;
}
Your variable tries decalres inside the while body. So, any loop iteration, this variable gets the value 1. To solve this issue, you should declare & initialize the variable outside to the loop:
// Generate a random number between 1 and 100
var num = Math.floor(Math.random() * 100) + 1;
var running = true;
var tries = 1;
while (running) {
var input = prompt("Take a guess");
if (input == num) {
console.log("Correct!");
console.log("Number of tries: " + tries);
running = false;
} else if (input > num) {
console.log("Too big");
} else if (input < num) {
console.log("Too small");
}
tries++;
}
Note: Do not use console.log(), use alert() instead. The console is for debugging, not for notify user messages.
I can see your problem. If you put a variable inside while function it will be reset each time meaning that it will be 1 each time.
If you put it outside it run just fine. Also, I believe that promt returns a string not a number that is why I would recommend you either to convert a number to string or a promt to number.
Here is the working code:
var num = Math.floor(Math.random() * (100)) + 1;
var running = true;
var tries = 1;
while(running) {
var input = parseFloat(prompt("Take a guess"));
if (input == num) {
console.log("Correct!");
console.log("Number of tries: " + tries);
running = false;
}else if (input > num) {
console.log("Too big");
}else if (input < num) {
console.log("Too small");
}
tries++;
}

Highest power of two - javascript

I'm using google apps scripts, that works with javascript and I'm writing a piece of code that returns the highest power of two that divides a number, but it doesn't work. Why??
function HP2(input) {
var i = 1;
while(input % 2^i = 0){
i++;
};
return 2^i;
}
Thanks!!
You need to use == in the while condition and the Math.pow function instead of the xor operator ^. Also the return should be i-1.
function HP2(input) {
var i = 1;
while(input % Math.pow(2, i) == 0) {
i++;
};
return Math.pow(2, i-1);
}
if you stay in the 32-bit range (at least for the divisor) this would be way more performant way:
function HP2(input){
for(var i=0; i<31 && !(input & (1<<i)); ++i);
return (1<<i)>>>0;
}

how to count up to a specific number in javascript, fizzbuzz

I'm trying to solve a problem similar to the popular fizzbuzz or pingpong question. I already figured out how to write this portion of the code, however I also need to make a counter in which the user inputs their number and the page gives back 1 to the number they input, as well as the fizzbuzz/popcorn numbers. I think the code is something along the lines of
for (i = 1; i <= 20; i++) {...}
But I don't know how to combine this with my other code
var pingpong = function(number) {
if (number % 15 === 0) {
return 'pingpong';
} else if (number % 5 === 0) {
return 'pong';
} else if (number % 3 === 0) {
return 'ping';
} else {
return false;
}
};
Sorry, I know this is a super beginner question, but I'm just starting out and am having a hard time figuring out how everything works together.
You are close. To read more about JavaScripts loops.
var pingpong = function(number) {
if (number % 15 === 0) {
return 'pingpong';
} else if (number % 5 === 0) {
return 'pong';
} else if (number % 3 === 0) {
return 'ping';
} else {
return false;
}
};
for (var i = 1; i <= 20; i++) {
var num = pingpong(i);
// Just show it on the screen
document.body.innerHTML += i + ': ' + num + '<br />';
}

Inserting into a number string

Have the function DashInsert(num) insert dashes ('-') between each two odd numbers in num. For example: if num is 454793 the output should be 4547-9-3. Don't count zero as an odd number.
Here is my code (not working). When I run it, I get the same response as an infinite loop where I have to kill the page but I can't see why. I know there are ways to do this by keeping it as a string but now I'm wondering why my way isn't working. Thanks...
function DashInsert(num) {
num = num.split("");
for (i = 1; i < num.length; i++) {
if (num[i - 1] % 2 != 0 && num[i] % 2 != 0) {
num.splice(i, 0, "-");
}
}
num = num.join("");
return num;
}
Using num.splice you are inserting new entries into the array, therefor increasing its length – and that makes the value of i “running behind” the increasing length of the array, so the break condition is never met.
And apart from that, on the next iteration after inserting a -, num[i-1] will be that - character, and therefor you are practically trying to check if '-' % 2 != 0 … that makes little sense as well.
So, when you insert a - into the array, you have to increase i by one as well – that will a) account for the length of the array having increased by one, and also it will check the next digit after the - on the next iteration:
function DashInsert(num) {
num = num.split("");
for (i = 1; i < num.length; i++) {
if (num[i - 1] % 2 != 0 && num[i] % 2 != 0) {
num.splice(i, 0, "-");
i++; // <- this is the IMPORTANT part!
}
}
num = num.join("");
return num;
}
alert(DashInsert("454793"));
http://jsfiddle.net/37wA9/
Once you insert a dash -, the if statement is checking this '-'%2 != 0 which is always true and thus inserts another dash, ad infinitum.
Here's one way to do it with replace using a regex and function:
function DashInsert(n) {
var f = function(m,i,s) { return m&s[i+1]&1 ? m+'-' : m; };
return String(n).replace(/\d/g,f);
}
DashInsert(454793) // "4547-9-3"
When you are adding a dash, this dash will be processed as a number on the next iteration. You need to forward one step.
function DashInsert(num) {
var num = num.split("");
for (var i = 1; i < num.length; i++) {
if ((num[i - 1] % 2 != 0) && (num[i] % 2 != 0)) {
num.splice(i, 0, "-");
i++; // This is the only thing that needs changing
}
}
num = num.join("");
return num;
}
It's because there are cases when you use the % operator on dash '-' itself, e.g. right after you splice a dash into the array.
You can correct this behavior by using a clone array.
function DashInsert(num) {
num = num.split("");
var clone = num.slice(0);
var offset = 0;
for (i = 1; i < num.length; i++) {
if (num[i - 1] % 2 != 0 && num[i] % 2 != 0) {
clone.splice(i + offset, 0, "-");
offset++;
}
}
return clone.join("");
}
alert(DashInsert("45739"));
Output: 45-7-3-9
Demo: http://jsfiddle.net/262Bf/
To complement the great answers already given, I would like to share an alternative implementation, that doesn't modify arrays in-place:
function DashInsert(num) {
var characters = num.split("");
var numbers = characters.map(function(chr) {
return parseInt(chr, 10);
});
var withDashes = numbers.reduce(function(result, current) {
var lastNumber = result[result.length - 1];
if(lastNumber == null || current % 2 === 0 || lastNumber % 2 === 0) {
return result.concat(current);
} else {
return result.concat("-", current);
}
}, []);
return withDashes.join("");
}
It's longer, but IMHO reveals the intention better, and avoids the original issue.

Convert column index into corresponding column letter

I need to convert a Google Spreadsheet column index into its corresponding letter value, for example, given a spreadsheet:
I need to do this (this function obviously does not exist, it's an example):
getColumnLetterByIndex(4); // this should return "D"
getColumnLetterByIndex(1); // this should return "A"
getColumnLetterByIndex(6); // this should return "F"
Now, I don't recall exactly if the index starts from 0 or from 1, anyway the concept should be clear.
I didn't find anything about this on gas documentation.. am I blind? Any idea?
Thank you
I wrote these a while back for various purposes (will return the double-letter column names for column numbers > 26):
function columnToLetter(column)
{
var temp, letter = '';
while (column > 0)
{
temp = (column - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
column = (column - temp - 1) / 26;
}
return letter;
}
function letterToColumn(letter)
{
var column = 0, length = letter.length;
for (var i = 0; i < length; i++)
{
column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
}
return column;
}
This works good
=REGEXEXTRACT(ADDRESS(ROW(); COLUMN()); "[A-Z]+")
even for columns beyond Z.
Simply replace COLUMN() with your column number. The value of ROW() doesn't matter.
No need to reinvent the wheel here, use the GAS range instead:
var column_index = 1; // your column to resolve
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange(1, column_index, 1, 1);
Logger.log(range.getA1Notation().match(/([A-Z]+)/)[0]); // Logs "A"
=SUBSTITUTE(ADDRESS(1,COLUMN(),4), "1", "")
This takes your cell, gets it's address as e.g. C1, and removes the "1".
How it works
COLUMN() gives the number of the column of the cell.
ADDRESS(1, ..., <format>) gives an address of a cell, in format speficied by <format> parameter. 4 means the address you know - e.g. C1.
The row doesn't matter here, so we use 1.
See ADDRESS docs
Finally, SUBSTITUTE(..., "1", "") replaces the 1 in the address C1, so you're left with the column letter.
This works on ranges A-Z
formula =char(64+column())
js String.fromCharCode(64+colno)
an google spreadsheet appscript code, based on #Gardener would be:
function columnName(index) {
var cname = String.fromCharCode(65 + ((index - 1) % 26));
if (index > 26)
cname = String.fromCharCode(64 + (index - 1) / 26) + cname;
return cname;
}
In javascript:
X = (n) => (a=Math.floor(n/26)) >= 0 ? X(a-1) + String.fromCharCode(65+(n%26)) : '';
console.assert (X(0) == 'A')
console.assert (X(25) == 'Z')
console.assert (X(26) == 'AA')
console.assert (X(51) == 'AZ')
console.assert (X(52) == 'BA')
Adding to #SauloAlessandre's answer, this will work for columns up from A-ZZ.
=if(column() >26,char(64+(column()-1)/26),) & char(65 + mod(column()-1,26))
I like the answers by #wronex and #Ondra Žižka. However, I really like the simplicity of #SauloAlessandre's answer.
So, I just added the obvious code to allow #SauloAlessandre's answer to work for wider spreadsheets.
As #Dave mentioned in his comment, it does help to have a programming background, particularly one in C where we added the hex value of 'A' to a number to get the nth letter of the alphabet as a standard pattern.
Answer updated to catch the error pointed out by #Sangbok Lee. Thank you!
I was looking for a solution in PHP. Maybe this will help someone.
<?php
$numberToLetter = function(int $number)
{
if ($number <= 0) return null;
$temp; $letter = '';
while ($number > 0) {
$temp = ($number - 1) % 26;
$letter = chr($temp + 65) . $letter;
$number = ($number - $temp - 1) / 26;
}
return $letter;
};
$letterToNumber = function(string $letters) {
$letters = strtoupper($letters);
$letters = preg_replace("/[^A-Z]/", '', $letters);
$column = 0;
$length = strlen($letters);
for ($i = 0; $i < $length; $i++) {
$column += (ord($letters[$i]) - 64) * pow(26, $length - $i - 1);
}
return $column;
};
var_dump($numberToLetter(-1));
var_dump($numberToLetter(26));
var_dump($numberToLetter(27));
var_dump($numberToLetter(30));
var_dump($letterToNumber('-1A!'));
var_dump($letterToNumber('A'));
var_dump($letterToNumber('B'));
var_dump($letterToNumber('Y'));
var_dump($letterToNumber('Z'));
var_dump($letterToNumber('AA'));
var_dump($letterToNumber('AB'));
Output:
NULL
string(1) "Z"
string(2) "AA"
string(2) "AD"
int(1)
int(1)
int(2)
int(25)
int(26)
int(27)
int(28)
Simple way through Google Sheet functions, A to Z.
=column(B2) : value is 2
=address(1, column(B2)) : value is $B$1
=mid(address(1, column(B2)),2,1) : value is B
It's a complicated way through Google Sheet functions, but it's also more than AA.
=mid(address(1, column(AB3)),2,len(address(1, column(AB3)))-3) : value is AB
I also was looking for a Python version here is mine which was tested on Python 3.6
def columnToLetter(column):
character = chr(ord('A') + column % 26)
remainder = column // 26
if column >= 26:
return columnToLetter(remainder-1) + character
else:
return character
A comment on my answer says you wanted a script function for it. All right, here we go:
function excelize(colNum) {
var order = 1, sub = 0, divTmp = colNum;
do {
divTmp -= order; sub += order; order *= 26;
divTmp = (divTmp - (divTmp % 26)) / 26;
} while(divTmp > 0);
var symbols = "0123456789abcdefghijklmnopqrstuvwxyz";
var tr = c => symbols[symbols.indexOf(c)+10];
return Number(colNum-sub).toString(26).split('').map(c=>tr(c)).join('');
}
This can handle any number JS can handle, I think.
Explanation:
Since this is not base26, we need to substract the base times order for each additional symbol ("digit"). So first we count the order of the resulting number, and at the same time count the number to substract. And then we convert it to base 26 and substract that, and then shift the symbols to A-Z instead of 0-P.
Anyway, this question is turning into a code golf :)
Java Apache POI
String columnLetter = CellReference.convertNumToColString(columnNumber);
This will cover you out as far as column AZ:
=iferror(if(match(A2,$A$1:$AZ$1,0)<27,char(64+(match(A2,$A$1:$AZ$1,0))),concatenate("A",char(38+(match(A2,$A$1:$AZ$1,0))))),"No match")
A function to convert a column index to letter combinations, recursively:
function lettersFromIndex(index, curResult, i) {
if (i == undefined) i = 11; //enough for Number.MAX_SAFE_INTEGER
if (curResult == undefined) curResult = "";
var factor = Math.floor(index / Math.pow(26, i)); //for the order of magnitude 26^i
if (factor > 0 && i > 0) {
curResult += String.fromCharCode(64 + factor);
curResult = lettersFromIndex(index - Math.pow(26, i) * factor, curResult, i - 1);
} else if (factor == 0 && i > 0) {
curResult = lettersFromIndex(index, curResult, i - 1);
} else {
curResult += String.fromCharCode(64 + index % 26);
}
return curResult;
}
function lettersFromIndex(index, curResult, i) {
if (i == undefined) i = 11; //enough for Number.MAX_SAFE_INTEGER
if (curResult == undefined) curResult = "";
var factor = Math.floor(index / Math.pow(26, i));
if (factor > 0 && i > 0) {
curResult += String.fromCharCode(64 + factor);
curResult = lettersFromIndex(index - Math.pow(26, i) * factor, curResult, i - 1);
} else if (factor == 0 && i > 0) {
curResult = lettersFromIndex(index, curResult, i - 1);
} else {
curResult += String.fromCharCode(64 + index % 26);
}
return curResult;
}
document.getElementById("result1").innerHTML = lettersFromIndex(32);
document.getElementById("result2").innerHTML = lettersFromIndex(6800);
document.getElementById("result3").innerHTML = lettersFromIndex(9007199254740991);
32 --> <span id="result1"></span><br> 6800 --> <span id="result2"></span><br> 9007199254740991 --> <span id="result3"></span>
In python, there is the gspread library
import gspread
column_letter = gspread.utils.rowcol_to_a1(1, <put your col number here>)[:-1]
If you cannot use python, I suggest looking the source code of rowcol_to_a1() in https://github.com/burnash/gspread/blob/master/gspread/utils.py
Here's a two liner which works beyond ZZ using recursion:
Python
def col_to_letter(n):
l = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
return col_to_letter((n-1)//26) + col_to_letter(n%26) if n > 26 else l[n-1]
Javascript
function colToLetter(n) {
l = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
return n > 26 ? colToLetter(Math.floor((n-1)/26)) + colToLetter(n%26) : l[n-1]
}
If you need a version directly in the sheet, here a solution:
For the colonne 4, we can use :
=Address(1,4)
I keep the row number to 1 for simplicty.
The above formula returns $D$1 which is not what you want.
By modifying the formula a little bit we can remove the dollar signs in the cell reference.
=Address(1,4,4)
Adding four as the third argument tells the formula that we are not looking for absolute cell reference.
Now the returns is : D1
So you only need to remove the 1 to get the colonne lettre if you need, for example with :
=Substitute(Address(1,4,4),"1","")
That returns D.
This is a way to convert column letters to column numbers.
=mmult(ArrayFormula(ifna(vlookup(substitute(mid(rept(" ",3-len(filter(A:A,A:A<>"")))&filter(A:A,A:A<>""),sequence(1,3),1)," ",""),{char(64+sequence(26)),sequence(26)},2,0),0)*{676,26,1}),sequence(3,1,1,0))
Screenshot of the Google Sheet
Don't use 26 radix. Like below.
const n2c = n => {
if (!n) return '';
// Column number to 26 radix. From 0 to p.
// Column number starts from 1. Subtract 1.
return [...(n-1).toString(26)]
// to ascii number
.map(c=>c.charCodeAt())
.map((c,i,arr)=> {
// last digit
if (i===arr.length-1) return c;
// 10 -> p
else if (arr.length - i > 2 && arr[i+1]===48) return c===49 ? null : c-2;
// 0 -> p
else if (c===48) return 112;
// a-1 -> 9
else if (c===97) return 57;
// Subtract 1 except last digit.
// Look at 10. This should be AA not BA.
else return c-1;
})
.filter(c=>c!==null)
// Convert with the ascii table. [0-9]->[A-J] and [a-p]->[K-Z]
.map(a=>a>96?a-22:a+17)
// to char
.map(a=>String.fromCharCode(a))
.join('');
};
const table = document.createElement('table');
table.border = 1;
table.cellPadding = 3;
for(let i=0, row; i<1380; i++) {
if (i%5===0) row = table.insertRow();
row.insertCell().textContent = i;
row.insertCell().textContent = n2c(i);
}
document.body.append(table);
td:nth-child(odd) { background: gray; color: white; }
td:nth-child(even) { background: silver; }
Simple typescript functional approach
const integerToColumn = (integer: number): string => {
const base26 = (x: number): string =>
x < 26
? String.fromCharCode(65 + x)
: base26((x / 26) - 1) + String.fromCharCode(65 + x % 26)
return base26(integer)
}
console.log(integerToColumn(0)) // "A"
console.log(integerToColumn(1)) // "B"
console.log(integerToColumn(2)) // "C"
Here is a general version written in Scala. It's for a column index start at 0 (it's simple to modify for an index start at 1):
def indexToColumnBase(n: Int, base: Int): String = {
require(n >= 0, s"Index is non-negative, n = $n")
require(2 <= base && base <= 26, s"Base in range 2...26, base = $base")
def digitFromZeroToLetter(n: BigInt): String =
('A' + n.toInt).toChar.toString
def digitFromOneToLetter(n: BigInt): String =
('A' - 1 + n.toInt).toChar.toString
def lhsConvert(n: Int): String = {
val q0: Int = n / base
val r0: Int = n % base
val q1 = if (r0 == 0) (n - base) / base else q0
val r1 = if (r0 == 0) base else r0
if (q1 == 0)
digitFromOneToLetter(r1)
else
lhsConvert(q1) + digitFromOneToLetter(r1)
}
val q: Int = n / base
val r: Int = n % base
if (q == 0)
digitFromZeroToLetter(r)
else
lhsConvert(q) + digitFromZeroToLetter(r)
}
def indexToColumnAtoZ(n: Int): String = {
val AtoZBase = 26
indexToColumnBase(n, AtoZBase)
}
In PowerShell:
function convert-IndexToColumn
{
Param
(
[Parameter(Mandatory)]
[int]$col
)
"$(if($col -gt 26){[char][int][math]::Floor(64+($col-1)/26)})$([char](65 + (($col-1) % 26)))"
}
Here is a 0-indexed JavaScript function without a maximum value, as it uses a while-loop:
function indexesToA1Notation(row, col) {
const letterCount = 'Z'.charCodeAt() - 'A'.charCodeAt() + 1;
row += 1
let colName = ''
while (col >= 0) {
let rem = col % letterCount
colName = String.fromCharCode('A'.charCodeAt() + rem)
col -= rem
col /= letterCount
}
return `${colName}${row}`
}
//Test runs:
console.log(indexesToA1Notation(0,0)) //A1
console.log(indexesToA1Notation(37,9)) //J38
console.log(indexesToA1Notation(5,747)) //ABT6
I wrote it for a web-app, so I'm not 100% sure it works in Google Apps Script, but it is normal JavaScript, so I assume it will.
For some reason I cant get the snippet to show its output, but you can copy the code to some online playground if you like
Here's a zero-indexed version (in Python):
letters = []
while column >= 0:
letters.append(string.ascii_uppercase[column % 26])
column = column // 26 - 1
return ''.join(reversed(letters))

Categories