Concatenate or Combine Multiple Values and Retain Fonts and Colour - excel

I am trying to concatenate or combine a few cells together and keep their individual styles.
For instance:
A1: Mr (Arial, Red, size 10)
A2: Joseph (Courier, Blue, size 20)
A3: Lion (Arial, Green, size 15)
Using the function =A1&" "&A2&" "&A3
A5: Mr Joseph Lion (Default font, default colour, default Size)
In the Concatenated cell A5, all the fonts, sizes and colours go back to default.
Is there a way to combine the values and maintain the styles.
Thank you all in advance.

You can use this function (RICHTEXTCONCAT()) to concatenate rich text from your Sheets:
function isCell(obj) {
return (typeof obj == "object" && obj.toString() == "Range" && obj.getHeight() == 1 && obj.getWidth() == 1);
}
function RICHTEXTCONCAT() {
var nargs = arguments.length;
var resultText = "";
var styles = [];
for (var i=0; i<nargs; i++) {
var arg = arguments[i];
if (isCell(arg)) {
var startPos = resultText.length;
resultText += arg.getValue();
var rtv = arg.getRichTextValue();
if (rtv) {
var runs = rtv.getRuns();
for (var j=0; j<runs.length; j++) {
styles.push({startIndex: startPos + runs[j].getStartIndex(),
endIndex: startPos + runs[j].getEndIndex(),
textStyle: runs[j].getTextStyle().copy().build()});
}
}
} else if (typeof arg == "string") {
resultText += arg;
} else {
throw new Error("Unsupported type " + typeof arg + " for argument " + (i+1) + ". Must be a cell or a string.");
}
}
var result = SpreadsheetApp.newRichTextValue().setText(resultText);
for (var i=0; i<styles.length; i++) {
if (styles[i].startIndex === styles[i].endIndex) continue;
result.setTextStyle(styles[i].startIndex,
styles[i].endIndex,
styles[i].textStyle);
}
return result.build();
}
In theory, you could use the function as a custom function, so that it could be used in a cell such as:
=RICHTEXTCONCAT(A1, " ", A2, " ", A3)
However, Sheets does not interpret rich text return values from custom functions. That means that the only option you have is to manually call a Google Apps Script function that uses setRichTextValue() in order to execute it. An example:
function myConcat() {
var sheet = SpreadsheetApp.getActive();
var range1 = sheet.getRange("A1");
var range2 = sheet.getRange("A2");
var range3 = sheet.getRange("A3");
var result = RICHTEXTCONCAT(range1, " ", range2, " ", range3);
var destinationRange = sheet.getRange("A5");
destinationRange.setRichTextValue(result);
}
If you are interested in Rich Text Value being a possible return value from a custom function, please consider filing a Feature Request into Google's Public Issue Tracker (https://issuetracker.google.com).

Related

Check only a range of checkboxes

I have this code with works brilliantly for me. I just need a small alteration to be able to select a range of cells as well, meaning:
Either H15-H17 or H22 or H26 in the attached image.enter image description here
the code I have is the following:
var CHECKBOX_CELLS = ["H15", "H22", "H26"];
function onEdit(e) {
var range = e.range;
var checkboxIndex = CHECKBOX_CELLS.indexOf(range.getA1Notation());
if (checkboxIndex > -1 && range.getValue() == true) {
var sheet = range.getSheet();
for (var i=0; i<CHECKBOX_CELLS.length; i++) {
if (i==checkboxIndex) continue;
sheet.getRange(CHECKBOX_CELLS[i]).setValue(false);
}
}
}

Reading values from array with objects from a function in google sheets

I am very new to excel but I have been coding for a couple of years. Now I have created a function which returns an array of objects.
function sheetnames() {
var out = new Array()
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
for (var i=0 ; i<sheets.length ; i++){
let totalScore = sheets[i].getRange("C2").getValue();
if(i == 0 || i == 1){
continue;
}
console.log(sheets[i].getName(), totalScore);
out.push({name: sheets[i].getName(), score: totalScore});
}
return out.sort((a)=> a.totalScore);
}
I want to call this function and write Name in A1 and score in B1 and then next row Name in A2 and score in B2 and so on and so on.
I'm calling my function in excel using =sheetnames() which i got to work before when I only returned an array with strings.
Thanks!
I solved it by updating the excelsheet straigt from the code instead of calling the function from the acctual excel.
function sheetnames() {
resetStandingsSheet();
var out = new Array()
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
for (var i=0 ; i<sheets.length ; i++){
let totalScore = sheets[i].getRange("C2").getValue();
if(i == 0 || i == 1){
continue;
}
console.log(sheets[i].getName(), totalScore);
out.push({name: sheets[i].getName(), score: totalScore});
}
var scoresAndNames = out.sort((a)=> a.totalScore);
var standingSheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[1];
standingSheet.appendRow(["Name", "Score"]);
for(var i = 0; i < scoresAndNames.length; i++){
standingSheet.appendRow([scoresAndNames[i].name, scoresAndNames[i].score + 'p']);
}
}

Google Sheet custom function not returning string

I am new to Google Sheet scripting.
I am writing a code to strip the sixth components from a long text that is based on a naming convention. The text have 6 parts all separated by an underscore. However, my code is not returning anything
function RetailerStrip(account) {
var count = 0;
var retname = "";
var retcount = 0;
for(var i = 0, len = account.length; i < len; i++) {
if (account[i] =="_") {
++count;
}
if (count == 5) {
retname[retcount]= account[i];
++retcount;
}
}
return retname;
}
I then call this function from sheet as below
=RetailerStrip("abc_def_ghi_jkl_mno_pqr")
When I tried to declare 'retname' as an array the function did return the required text (fifth component) but the text was spread across multiple cells with on character in each cell, and not as a single string in one cell
var retname = [];
Please help
You could try this:
function RetailerStrip(str) { return str.split('_')[5]; }
The split() method creates an array.
But if you prefer to stick with the string-iteration method, you could use this:
function RetailerStrip(account) {
var count = 0;
var retname = []; // Array
var retcount = 0;
for (var i = 0, len = account.length; i < len; i++) {
if (account[i] =="_") {
++count;
}
if (count == 4) {
retname[retcount]= account[i];
++retcount;
}
}
retname.shift(); // To get rid of the underscore from the array
var retnameString = retname.join(''); // To convert the array to a string
return retnameString;
}

How to manipulate a string representing a raw number (e.g. 130000.1293) into a formatted string (e.g. 130,000.13)?

In apps script I want to obtain formatted 'number' strings. The input is an unformatted number. With an earlier answer posted by #slandau, I thought I had found a solution by modifying his code (see code snippet). It works in codepen, but not when I am using apps script.
1. Does anyone know what went wrong here?
2. I noticed this code works except when entering a number ending in .0, in that case the return value is also .0 but should be .00. I would like some help fixing that too.
Thanks!
I have tried to look for type coercion issues, but wasn't able to get it down. I am fairly new to coding.
function commaFormatted(amount)
{
var delimiter = ","; // replace comma if desired
var a = amount.split('.', 2);
var preD = a[1]/(Math.pow(10,a[1].length-2));
var d = Math.round(preD);
var i = parseInt(a[0]);
if(isNaN(i)) { return ''; }
var minus = '';
if(i < 0) { minus = '-'; }
i = Math.abs(i);
var n = new String(i);
var a = [];
while(n.length > 3)
{
var nn = n.substr(n.length-3);
a.unshift(nn);
n = n.substr(0,n.length-3);
}
if(n.length > 0) { a.unshift(n); }
n = a.join(delimiter);
if(d.length < 1) { amount = n; }
else { amount = n + '.' + d; }
amount = minus + amount;
return amount;
}
console.log(commaFormatted('100000.3532'))
The expected result would be 100,000.35.
I am getting this in the IDE of codepen, but in GAS IDE is stops at the .split() method => not a function. When converting var a to a string = I am not getting ["100000", "3532"] when logging var a. Instead I am getting 100000 and was expecting 3532.
Based on this answer, your function can be rewritten to
function commaFormatted(amount)
{
var inputAmount;
if (typeof(amount) == 'string') {
inputAmount = amount;
} else if (typeof(amount) == 'float') {
inputAmount = amount.toString();
}
//--- we expect the input amount is a String
// to make is easier, round the decimal part first
var roundedAmount = parseFloat(amount).toFixed(2);
//--- now split it and add the commas
var parts = roundedAmount.split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
}
console.log(commaFormatted(100000.3532));
console.log(commaFormatted('1234567.3532'));

Convert rows into columns with conditions

I've the following excel which needs to be transposed to columns. I have tried using the built-in formula and hte pivot table but that did not help me much since the data is in a single column and I am looking for transposing to multiple columns.
Excel: (all data in single column)
ABC1
F1
D1
Sym1
ABC2
See Link2
ABC3
F3
D3
Sym3
ABC4
See Link4
ABC5
See Link5
The output should be like:
ABC Functions Description Sym See Link
ABC1 F1 D1 Sym1
ABC2 See Link1
ABC3 F3 D3 Sym3
ABC4 See Link4
ABC5 See Link5
See that when 'See Link' is present for the row data, none of the functions, descriptions and syms are present and vice versa.
So I figured this out. Used G script in googlesheet to get this right. For anyone looking for code, here's it:
function run() {
var inputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var outputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Description");
var rows = new Array(new Array());
var values = inputSheet.getRange(1, 1, inputSheet.getLastRow()).getValues();
Logger.log(values.length);
var j = 0;
var endOfRow = false;
var singleRow = new Array();
for (var row in values) {
for (var col in values[row]) {
var value = values[row][col];
if(value.indexOf("F") != -1) {
singleRow[1] = value;
}
else if(value.indexOf("D") != -1) {
singleRow[2] = value;
}
else if(value.indexOf("See Link") != -1) {
singleRow[4] = value;
endOfRow = true;
}
else if(value.indexOf("Sym") != -1) {
singleRow[3] = value;
endOfRow = true;
}
else {
singleRow[0] = value;
}
}
if(endOfRow) {
rows[j] = singleRow;
j++;
endOfRow = false;
var singleRow = new Array();
}
}
for(var d=2; d < rows.length; d++) {
var singleRow = rows[d];
for(var f = 0; f < singleRow.length; f++) {
if(singleRow[f] == undefined) {
outputSheet.getRange(d, f+1).setValue("");
} else {
outputSheet.getRange(d, f+1).setValue(singleRow[f]);
}
}
}
}

Resources