Unlink all hyperlinks from a sheet - google-apps-script

I'm trying to Unlink all hyperlinks in a Google Spreadsheet, so far I'm trying to do a search and replace which is the code below, but wondering if there is a specific function to do the unlink?
function replacelinks(){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Links");
var values = sheet.getDataRange().getValues();
replaceInSheet(values, '.com', '');
replaceInSheet(values, '.net', '');

I believe your goal as follows.
You want to remove all hyperlinks on a sheet in a Google Spreadsheet using Google Apps Script.
For this, how about this answer?
Modification points:
Unfortunately, in the current stage, it seems that there are no methods for directly removing the hyperlinks of the cells and texts. So in order to achieve your goal, I would like to propose a workaround. The flow of this workaround is as follows.
Copy the sheet you want to remove the hyperlinks in the Google Spreadsheet as a temporal sheet.
Retrieve the richTextValues from the data range of the source sheet.
Retrieve the cell coordinates, which have the hyperlinks, and create an object for using the method of batchUpdate in Sheets API.
Request to the batchUpdate method using the created object.
The cells with the hyperlinks on the source sheet are cleared, and the values of the same coordinates are copied from the temporal sheet to the source sheet. By this, the hyperlinks are removed.
Sample script:
Please copy and paste the following script to the script editor. And, please enable Sheets API at Advanced Google services. And please set the sheet name you want to remove the hyperlinks.
function myFunction() {
const sheetName = "Sheet1"; // Please set the sheet name.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(sheetName);
const sheetId = sheet.getSheetId();
const range = sheet.getDataRange();
const temp = ss.insertSheet();
const tempId = temp.getSheetId();
range.copyTo(temp.getRange("A1"), {contentsOnly: true});
const requests = range.getRichTextValues().reduce((ar, row, i) => {
row.forEach((col, j) => {
const runs = col.getRuns();
if (col.getLinkUrl() || (runs && runs.some(e => e.getLinkUrl()))) {
const req1 = {updateCells:{range:{sheetId:sheetId,startRowIndex:i,endRowIndex:i + 1,startColumnIndex:j,endColumnIndex:j + 1},fields:"userEnteredValue"}};
const req2 = {copyPaste:{
source:{sheetId:tempId,startRowIndex:i,endRowIndex:i + 1,startColumnIndex:j,endColumnIndex:j + 1},
destination:{sheetId:sheetId,startRowIndex:i,endRowIndex:i + 1,startColumnIndex:j,endColumnIndex:j + 1},
pasteType:"PASTE_NORMAL"
}};
ar = ar.concat(req1, req2);
}
});
return ar;
}, []);
Sheets.Spreadsheets.batchUpdate({requests: requests}, ss.getId());
ss.deleteSheet(temp);
}
In this script, the hyperlinks of both with and without HYPERLINK() can be removed.
Note:
In the current stage, it seems that getRichTextValues() cannot retrieve the number values. By this, when the number values has the hyperlinks, these hyperlinks cannot be removed. About this issue, I have already reported to the issue tracker. Ref So when this issue was removed, I think that using above script, all hyperlinks might be be able to be removed. Or, in the current stage, the method of getLinkUrl() used in above script is not included in the official document. So I also think that the method for directly removing the hyperlinks might be added in the future update.
References:
getRichTextValues()
Advanced Google services
Method: spreadsheets.batchUpdate
UpdateCellsRequest
CopyPasteRequest

What helped for me was to setShowHyperlink to false for the range.
Example:
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getActiveSheet();
const range = ws.getRange(lastRow, 1)
range.setValue('https://example.com');
range.setShowHyperlink(false);
But as soon as you double click such a cell, Google will re-apply the hyperlink.

Related

How to automatically change links?

The table (master) has links that point to cells within the table.
When creating a copy of this table (master copy), these links lead to the original table (master).
How can I automatically change the links so that they in the copy (master copy) refer to cells inside the copy (master copy)?
I'll link the script to the "fix links" button.
Link to table - https://docs.google.com/spreadsheets/d/1Jrpjm7Yjwp-3WTFKyBz87laPeq6ksjwPaaiWWNcIoow/edit?usp=sharing
I think it can be done by replacing #gid (sheetID) in the links. I found information how to get #gid (sheetID) - Google Apps Script, Google Sheets - Getting Spreadsheet ID and Sheet ID programmatically
But I don't know how to automatically find and replace all #gid (sheetID) in the current table in the links.
You can do it manually using Find and Replace. But it needs to be automated.
I believe your goal is as follows.
From your provided sample Spreadsheet, you want to change the hyperlinks in the range of "I6:I10" with the active sheet instead of the original sheet.
In this case, how about the following sample script?
Sample script 1:
Please copy and paste the following script to the script editor of Spreadsheet and save the script. And, as a test, please copy master, and please open the copied sheet. And then, please run this script. By this, the hyperlinks in the range of "I6:I10" are changed from the original sheet to the currently active sheet.
function myFunction() {
const checkRange = "I6:I10"; // This is from yoru sample Spreadsheet.
const sheet = SpreadsheetApp.getActiveSheet();
const sheetId = sheet.getSheetId();
const range = sheet.getRange(checkRange);
const richTextValues = range.getRichTextValues().map(r => r.map(c => {
const link = c.getLinkUrl();
return link ? c.copy().setLinkUrl(link.replace(/#gid\=.*&/, `#gid=${sheetId}`)).build() : c;
}));
range.setRichTextValues(richTextValues);
}
Sample script 2:
In this sample script, "master" sheet is copied to the same Spreadsheet with the specific sheet name, and the hyperlinks in the range of "I6:I10" are changed from the original sheet to the currently active sheet.
function myFunction2() {
const newSheetName = "sample"; // Please set the new sheet name by copying "master" sheet.
const checkRange = "I6:I10"; // This is from yoru sample Spreadsheet.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sourceSheet = ss.getSheetByName("master");
const newSheet = sourceSheet.copyTo(ss).setName(newSheetName);
const sheetId = newSheet.getSheetId();
const range = newSheet.getRange(checkRange);
const richTextValues = range.getRichTextValues().map(r => r.map(c => {
const link = c.getLinkUrl();
return link ? c.copy().setLinkUrl(link.replace(/#gid\=.*&/, `#gid=${sheetId}`)).build() : c;
}));
range.setRichTextValues(richTextValues);
}
References:
getRichTextValues()
setRichTextValues(values)

Is it possible to get a google doc modified date within a google sheets or apps script?

I have a google doc urls column within a google sheets
https://docs.google.com/spreadsheets/d/id
I want to display another column next to that to display google docs latest modified date? Is it possible to achieve that using google sheets formulas or apps script?
About Is it possible to achieve that using google sheets formulas or apps script?, in this case, the custom function cannot be used. But, when the Google Apps Script is run with the script editor, custom menu, button and so on, your goal can be achieved. In your situation, how about the following sample script?
Sample script:
Please copy and paste the following script to the script editor of Spreadsheet and run the function with the script editor. By this, the script is run.
function myFunction() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); // Please set your sheet name.
const range = sheet.getRange("A2:A" + sheet.getLastRow());
const values = range.getValues()
.map(([a]) => {
if (a.toString() == "") return [null];
const id = a.split("/")[5];
return [id ? DriveApp.getFileById(id).getLastUpdated() : null];
});
range.offset(0, 1).setValues(values);
}
In this sample script, first, the URLs are retrieved from the column "A" and the last updated date is retrieved using the file ID retrieved from URL. And, the retrieved values are put to the column "B".
Note:
In this sample, it supposes that the format of your URL is like https://docs.google.com/spreadsheets/d/id. Please be careful about this.
At the above sample script, it supposes that the URLs like https://docs.google.com/spreadsheets/d/id are directly put into the column "A". But, if the URLs are put to the column "A" as the hyperlink of a text like "DOC", please test the following script.
function myFunction() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); // Please set your sheet name.
const range = sheet.getRange("A2:A" + sheet.getLastRow());
const values = range.getRichTextValues()
.map(([a]) => {
const link = a.getLinkUrl();
if (!link) return [null];
const id = link.split("/")[5];
return [id ? DriveApp.getFileById(id).getLastUpdated() : null];
});
range.offset(0, 1).setValues(values);
}
As another approach, for example, if the number of URLs is large, I thought that the following sample script might be useful as the low process cost. This script retrieves the last updated date using Drive API with batch requests. When you use this script, please install a Google Apps Script library and please enable Drive API at Advanced Google services, and test it.
function myFunction() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); // Please set your sheet name.
const range = sheet.getRange("A2:A" + sheet.getLastRow());
const requests = {
batchPath: "batch/drive/v3",
requests: range.getValues().map(([a]) => ({ method: "GET", endpoint: `https://www.googleapis.com/drive/v3/files/${a.split("/")[5]}?fields=modifiedTime` })),
};
const values = BatchRequest.EDo(requests).map(({ modifiedTime }) => [modifiedTime ? new Date(modifiedTime) : null]);
range.offset(0, 1).setValues(values);
}
In this script, as a sample, it supposes that the column "A" has the URLs like https://docs.google.com/spreadsheets/d/id. Please be careful about this.
References:
getLastUpdated()
map()

How to clear same multiple columns on different sheets in worksheet in google sheets

I created a Google sheet workbook with 4 sheets. Each sheet will need the following columns to be cleared each Friday (columns C3:S40 and column U3:U40). Here is what I came up with but it doesn't work all the way through. So I was wondering if anyone can help me to simplify the script. Thank you in advance!
function ClearCells()
var sheet = SpreadsheetApp.getActive().getSheetbyName ();
sheet.getRange(C3:S40).clearContent();
sheet.getRange(U3:U40).clearContent();}
Try this:
function ClearRangesofSelectedSheets() {
const shts = ["Sheet1","Sheet2","Sheet3"];
const ss = SpreadsheetApp.getActive();
shts.forEach(name => {
const sheet = ss.getSheetByName(name);
sheet.getRange("C3:S40").clearContent();
sheet.getRange("U3:U40").clearContent();
});
}
I believe your goal is as follows.
You want to simplify your showing script.
As the additional function, you want to use your script for the specific 4 sheets in a Google Spreadsheet.
Modification points:
It seems that your function of function ClearCells() is not enclosed by {}.
getSheetbyName () of SpreadsheetApp.getActive().getSheetbyName () is required to be getSheetByName("Sheet name").
When getRange method of Class Sheet is used, C3:S40 and U3:U40 of sheet.getRange(C3:S40).clearContent() and sheet.getRange(U3:U40).clearContent() are required to be given as the string value as follows.
sheet.getRange("C3:S40").clearContent();
sheet.getRange("U3:U40").clearContent();
In your script, sheet.getRange("C3:S40").clearContent() and sheet.getRange("U3:U40").clearContent() can be modified by one call as follows.
sheet.getRangeList(["C3:S40", "U3:U40"]).clearContent();
In order to use your script to the specific 4 sheets, it is required to give the sheets.
When these points are reflected in your script, how about the following modification?
Modified script:
function ClearCells() {
var sheetNames = ["Sheet1", "Sheet2",,,]; // Please set the sheet names you want to use.
var sheet = SpreadsheetApp.getActive();
sheetNames.forEach(sheetName =>
sheet.getSheetByName(sheetName).getRangeList(["C3:S40", "U3:U40"]).clearContent()
);
}
Or, in order to simplify the script, you can also use the following script. When you use this script, please enable Sheets API at Advanced Google services.
function ClearCells() {
var sheetNames = ["Sheet1", "Sheet2",,,]; // Please set the sheet names you want to use.
var ss = SpreadsheetApp.getActive();
Sheets.Spreadsheets.Values.batchClear({ ranges: sheetNames.flatMap(s => ["C3:S40", "U3:U40"].map(r => `'${s}'!${r}`)) }, ss.getId());
}
I think that when Sheets API is used, the process cost might be able to be reduced a little. Ref
References:
getRangeList(a1Notations) of Class Sheet
Method: spreadsheets.values.batchClear
forEach()
map()

Is there a way to import cells in a certain range for a large number of sheets

I have 25 tabs in a Google Spreadsheet, but this number slowly grows as more data is added. The importrange function that we are provided by default requires the specification of which sheets to import data from using something like what was outlined here: Combining multiple spreadsheets in one using IMPORTRANGE. However, is there a way (using a default function or the Apps Script) to do this for all tabs in the Google Spreadsheet, without specifying each one individually?
I believe your goal is as follows.
You want to retrieve the values from all sheets in a Google Spreadsheet and want to put the values to a sheet of the destination Spreadsheet. In this case, you want to set a range you want to retrieve.
You want to achieve this using Google Apps Script.
Sample script:
Please copy and paste the following script to the script editor of Google Apps Script, and set the variables. And, run the function.
function myFunction() {
const range = "A1:E3"; // Please set the range you want to retrieve.
const srcSpreadsheetId = "###"; // Please set source Spreadsheet ID.
const dstSpreadsheetId = "###"; // Please set destination Spreadsheet ID.
const dstSheetName = "Sheet1"; // Please set destination sheet name.
const values = SpreadsheetApp.openById(srcSpreadsheetId).getSheets().flatMap(s => s.getRange(range).getValues());
const dstSheet = SpreadsheetApp.openById(dstSpreadsheetId).getSheetByName(dstSheetName);
dstSheet.clearContents().getRange(1, 1, values.length, values[0].length).setValues(values);
}
When this script is run, the values are retrieved from the specific range of all sheets from the source Spreadsheet, and the values are put to the destination sheet.
In the above script, the retrieved values to "A1" of the destination sheet. If you want to append the values, please modify as follows.
From
dstSheet.clearContents().getRange(1, 1, values.length, values[0].length).setValues(values);
To
dstSheet.getRange(dstSheet.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
Unfortunately, I'm not sure whether I could correctly understand your question. So, for example, if you want to retrieve the values from all sheets except for multiple sheets, and you want to put the retrieved values to the specification sheet in the same Spreadsheet, how about the following sample script? In this case, you can use this script as a custom function. So, when you use this script, please put a custom function of =SAMPLE("A1:E3", "Sheet2,Sheet3") to a cell. In this sample arguments, the values are retrieved from the range of "A1:E3" of all sheets except for "Sheet2" and "Sheet3".
function SAMPLE(range, exclude) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const excludeSheets = [ss.getActiveSheet().getSheetName(), ...exclude.split(",").map(e => e.trim())];
return ss.getSheets().flatMap(s => {
if (!excludeSheets.includes(s.getSheetName())) {
return s.getRange(range).getValues();
}
return [];
});
}
As another pattern, if you want to retrieve the values from all sheets in a source Spreadsheet to a sheet of destination Spreadsheet, how about the following sample script? In this sample, please copy and paste the following script to the script editor of the destination Spreadsheet. And, please set the variables of source Spreadsheet ID and range you want. When this script is run, a formula is put to the cell "A1" of the destination sheet. The formula is from this thread. By this, you can see the values from all sheets in the source Spreadsheet at the destination sheet.
function myFunction2() {
const range = "A1:E3"; // Please set the range you want to retrieve.
const srcSpreadsheetId = "###"; // Please set source Spreadsheet ID.
const srcSs = SpreadsheetApp.openById(srcSpreadsheetId);
const url = srcSs.getUrl();
const values = srcSs.getSheets().map(s => `IMPORTRANGE("${url}","'${s.getSheetName()}'!${range}")`);
const formula = `={${values.join(";")}}`;
const dstSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); // Please set the destination sheet name.
dstSheet.clearContents().getRange(1, 1).setFormula(formula);
}
References:
getSheets()
getValues()
setValues(values)
Added:
About your following reply,
I'm using the first block of code that you sent, and it works. However, I want to copy the entire cell so that it also transfers the cell color, in addition to the text content of the cell. How would I modify the first block of code you sent to do that?
Unfortunately, from your question, I couldn't notice that you wanted to copy both the values and the background color of the cells. To achieve this request, the modified script of my 1st script is as follows.
Sample script:
function myFunction() {
const range = "A1:E3"; // Please set the range you want to retrieve.
const srcSpreadsheetId = "###"; // Please set source Spreadsheet ID.
const dstSpreadsheetId = "###"; // Please set destination Spreadsheet ID.
const dstSheetName = "Sheet1"; // Please set destination sheet name.
const { values, backgroundColors } = SpreadsheetApp.openById(srcSpreadsheetId).getSheets().reduce((o, s) => {
const r = s.getRange(range);
o.values = [...o.values, ...r.getValues()];
o.backgroundColors = [...o.backgroundColors, ...r.getBackgrounds()];
return o;
}, { values: [], backgroundColors: [] });
const dstSheet = SpreadsheetApp.openById(dstSpreadsheetId).getSheetByName(dstSheetName);
dstSheet.clearContents().clearFormats().getRange(1, 1, values.length, values[0].length).setValues(values).setBackgrounds(backgroundColors);
}

Google Sheets – Find and Replace multiple Code

Maybe someone can help me with my Problem.
First some background: I have copied some WhatsApp chats to Google Sheets. I use Latex to generate a book containing the chats. Google Sheet is able to display all Emojis from WhatsApp, Latex, of course, isn't. So I downloaded the Emojis as png files and defined Latex commands to include those emojis as graphic.
For Example: Too display the regular smiling emoji I type \grin. I have a list with hundreds of emojis in one row and the corresponding command in the next row.
Until now I used search and replace -> replace all in the same sheet for every single type of emoji. But as this takes hours I wondered if there is any way to make this more effective.
Here is a spreadsheet with a small example: Google Sheet
Thanks in advance!
You want to replace the Emojis to the defined Latex commands.
For example, you want to replace as follows.
From 03.01.19, 00:29 - me: Hi 😊 to 03.01.19, 00:29 - me: Hi \nettnett.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Flow:
The flow of this sample script is as follows. This sample script uses your shared Spreadsheet.
Retrieve data from the sheet of Codes for Smileys.
Create the request body for the findReplace request of batchUpdate method of Sheets API.
Run the method of batchUpdate.
Sample script:
This script used Sheets API. So, before you run the script, please enable Sheets API at Advanced Google services.
function myFunction() {
var dataSheet = "Codes for Smileys";
var sourceSheet = "unedited Chats with Smileys";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var data = ss.getSheetByName(dataSheet).getDataRange().getValues();
data.shift();
var sheetId = ss.getSheetByName(sourceSheet).getSheetId();
var requests = data.map(function(row) {return {findReplace: {sheetId: sheetId, find: row[0], replacement: row[1]}}});
Sheets.Spreadsheets.batchUpdate({requests: requests}, ss.getId());
}
This sample script uses your shared Spreadsheet. So in this case, the data sheet is Codes for Smileys. And the source sheet for converting is unedited Chats with Smileys.
Note:
If you change the sheet name, also please modify above script. Please be careful this.
When you run the script for the first time, the authorization screen is opened. So please authorize the scopes for using the script.
References:
Advanced Google services
spreadsheets.batchUpdate
FindReplaceRequest
Added:
You want to put the converted values to the sheet of Chat with Latex Code.
The sample script for achieving above is as follows.
Sample script:
function myFunction2() {
var dataSheet = "Codes for Smileys";
var sourceSheet = "unedited Chats with Smileys";
var destinationSheet = "Chats with LaTeX Codes";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(dataSheet);
var data = ss.getSheetByName(dataSheet).getDataRange().getValues();
data.shift();
var srcSheet = ss.getSheetByName(sourceSheet);
var tempSheet = srcSheet.copyTo(ss);
var sheetId = tempSheet.getSheetId();
var requests = data.map(function(row) {return {findReplace: {sheetId: sheetId, find: row[0], replacement: row[1]}}});
Sheets.Spreadsheets.batchUpdate({requests: requests}, ss.getId());
var tempValues = tempSheet.getDataRange().getValues();
var destSheet = ss.getSheetByName(destinationSheet);
destSheet.getRange(destSheet.getLastRow() + 1, 1, tempValues.length, tempValues[0].length).setValues(tempValues);
ss.deleteSheet(tempSheet);
}
In this sample script, the following flow is run.
Copy the source sheet unedited Chats with Smileys as a temporal sheet.
Create request body for the batchUpdate method to the temporal sheet.
Run the batchUpdate.
Copy the converted values from the temporal sheet to the destination sheet Chats with LaTeX Codes.
In this case, the converted values are put to the last row of the sheet.
Delete the temporal sheet.