App Script Google Docs Replace Text in Body - google-apps-script

I'm having trouble, replacing text in a Google Doc, using App Script.
Inside the document I have certain tags/tokens like ${TOKEN.SUBTOKEN}. I get the document as text and extract all the TOKEN's as a list with a Regex without issue, but when I want to use the replaceText function, I have issues. When I execute the replaceText line, it doesn't change the value in the document, but returns an element from the document. I can't find a way to replace the text I'm targeting.
var doc = DocumentApp.openById(docId);
var docBody = doc.getBody();
// tokenValues is the Object that contains the values to replace.
var fields = docBody.getText().match(/\$\{[a-z0-9\.\_]+\}/gi);
for (var i = 0; i < fields.length; i++ ) {
fields[i] = fields[i].substring(2, fields[i].length-1);
}
for (var i; i < fields.length; i++) {
Logger.log(docBody.replaceText(new RegExp('\\${ *' + fields[i].replace('/\./g', '\.') + '\ *}', tokenValues[i]));
}
How should I approach this, I'm having trouble with It because the documentation is not that explicit, (or maybe I don't understand it)

I did something similar to your question.
Here's the text:
{{ClientName}} would like to have a {{Product}} {{done/created}}. The purpose of this {{Product}} is to {{ProductPurpose}}. We have experience with such testing and development, and will develop and test the {{Product}} for {{ClientName}}.
Here's the code:
function searchReplace(){
var regex1=new RegExp('{{([a-zA-Z/]+)}}','g');
var tA=[];
var srchA=[];
var fldA=[];
var s=DocumentApp.getActiveDocument().getBody().getText();
while((tA=regex1.exec(s))!==null){//get all fields
fldA.push(tA[1]);
}
for(var i=0;i<fldA.length;i++){//Get unique fields
if(srchA.indexOf(fldA[i])==-1){
srchA.push(fldA[i]);
}
}
var doc=DocumentApp.getActiveDocument();
var body=doc.getBody();
for(var i=0;i<srchA.length;i++){
var searchPattern=Utilities.formatString('\\{\\{(%s)\\}\\}', srchA[i]);//need double backslashes here.
var prompt=Utilities.formatString('Enter Replacement for %s',srchA[i]);
var resp=DocumentApp.getUi().prompt('Replacement Text',prompt , DocumentApp.getUi().ButtonSet.OK_CANCEL)
if(resp.getSelectedButton()==DocumentApp.getUi().Button.OK){
body.replaceText(searchPattern, resp.getResponseText());//replaces all instances of the field
}
}
}

Related

How to delete selected text in a Google doc using Google Apps Script

In a Google document is there a way to delete selected text with Google Apps Script? The find criterion for the text to delete is not a string, but instead is relative to a bookmark. This question is related to a workaround for my open question at https://webapps.stackexchange.com/questions/166391/how-to-move-cursor-to-a-named-bookmark-using-google-apps-script).
Here is code I wish worked.
function UpdateBookmarkedText() {
var doc = DocumentApp.getActiveDocument();
var bookmarks = doc.getBookmarks();
for (var i = 0; i < bookmarks.length; i++){
// Delete the old text, one step in a longer process.
var text = bookmarks[i].getPosition().getElement().asText().editAsText();
var range = doc.newRange().addElementsBetween(text, 5, text, 7).build(); // arbitrary offsets for testing
doc.setSelection(range); // The selected range is successfully highlighted in the document.
doc.deleteSelection(); // This command does not exist.
} }
This documentation seems relevant but is over my head: https://developers.google.com/docs/api/how-tos/move-text
Use deleteText()
You may use the following script as the basis for your script:
function deleteSelectedText() {
var selection = DocumentApp.getActiveDocument().getSelection();
if (selection) {
var elements = selection.getRangeElements();
if (elements[0].getElement().editAsText) {
var text = elements[0].getElement().editAsText();
if (elements[0].isPartial()) {
text.deleteText(elements[0].getStartOffset(), elements[0].getEndOffsetInclusive());
}
}
}
}
This is a modified version of the script featured in the Class Range guide. This modification works for selected sentences within a paragraph. Thus, the use of the for loop (in the sample script) is not anymore necessary since the script operates within a single element/paragraph.
Optimized Script:
function test() {
var selection = DocumentApp.getActiveDocument().getSelection();
var elements = selection.getRangeElements();
var text = elements[0].getElement().editAsText();
(selection && elements[0].getElement().editAsText && elements[0].isPartial()) ? text.deleteText(elements[0].getStartOffset(), elements[0].getEndOffsetInclusive()):null;
}
References:
Class Range
deleteText(startOffset, endOffsetInclusive)
I'm not sure what exactly you're trying to do, so here is a guess. If you able to select something you can remove the selected text about this way:
function UpdateBookmarkedText() {
var doc = DocumentApp.getActiveDocument();
var bookmarks = doc.getBookmarks();
for (var i = 0; i < bookmarks.length; i++){
// Delete the old text, one step in a longer process.
var text = bookmarks[i].getPosition().getElement().asText().editAsText();
var range = doc.newRange().addElementsBetween(text, 5, text, 7).build(); // arbitrary offsets for testing
doc.setSelection(range); // The selected range is successfully highlighted in the document.
// the way to handle a selection
// from the official documentation
// https://developers.google.com/apps-script/reference/document/range
var selection = DocumentApp.getActiveDocument().getSelection();
if (selection) {
var elements = selection.getRangeElements();
for (let element of elements) {
if (element.getElement().editAsText) {
var text = element.getElement().editAsText();
if (element.isPartial()) {
text.deleteText(element.getStartOffset(), element.getEndOffsetInclusive());
} else {
text.setText(''); // not sure about this line
}
}
}
}
}
}

Google Apps Script - How to get Text from Paragraph?

Trying to write a function that pulls text between <> brackets in a document, writes to html and allows the user to replace the bracketed text with a user input field (via the find and replace function). Having trouble getting the actual bracketed text from the google doc. The closest I have gotten is returning the paragraph the bracketed text is in, but that does not work because then the entire paragraph gets replaced instead of only the bracketed text.
This is the most recent error:
TypeError: Cannot find function getStartOffset in object Text. (line
11, file "Code", project "Find and Replace Script")
function doGet() {
var docURL = DocumentApp.openByUrl('XXXX')
var body = docURL.getBody();
var fel0 = body.findText('<*>')
var el0 = fel0.getElement();
var startOffset = el0.getStartOffset();
var endOffset = el0.getEndOffsetInclusive();
var text = el0.asText().getText()
if (elements[0].isPartial())
text = el0.substring(startOffset,endOffset+1);
var template = HtmlService.createTemplateFromFile('urlinput.html');
template.el0 = el0;
return template.evaluate();
}
function findreplace(form){
var docURL = DocumentApp.openByUrl('XXXX')
var body = docURL.getBody();
body.replaceText(body.findText('<*>',fel0).getElement().asText().getText())
}
How do I get the actual found text from that body.findText('<*>') object? A big part that makes this difficult is the * wildcard between the <> brackets.
Try this:
This is just a quick little example to help you to get past your current problem.
function findAndReplace(){
var doc=DocumentApp.getActiveDocument();
var body=doc.getBody();
var rel1=body.findText('<.*>');
var el1=rel1.getElement();
var t=el1.asText().getText();
var x=rel1.getStartOffset();
var y=rel1.getEndOffsetInclusive();
var p=rel1.isPartial();
el1.asText().replaceText('<.*>', 'You\'ve been replaced.');
//Logger.log('\nt:%s\nx:%s\ny:%s\np:%s',t,x,y,p?'true':'false');
//var end="is near";
}
This also works:
function findAndReplace(){
DocumentApp.getActiveDocument().getBody().replaceText('<.*>', 'You\'ve been replaced.');
}
This is what you actually asked for:
As usual, I read some of the problem and then went off an did what I wanted to do. I guess you wanted to get the text. So here's another short example.
function findMyText(){
var body=DocumentApp.getActiveDocument().getBody();
var rel=body.findText('<.*>');
var el=rel.getElement();
var eltxt=el.asText().getText();
var txt=eltxt.slice(rel.getStartOffset()+1,rel.getEndOffsetInclusive())
DocumentApp.getUi().alert(txt);
}
I think your only problem was that you needed the .* which means zero or more of any character. The search pattern is a regular expression enclosed in quotes. I hope this helps.

Remove line breaks using apps scripts in a Google Document

Trying to work out how to remove multiple line breaks from Google Documents (not spreadsheets).
I've tried this and many variations thereof:
function searchAndReplace() {
var bodyElement = DocumentApp.getActiveDocument().getBody();
bodyElement.replaceText("\r\r", '\r');
}
Any idea please?
Noob to all of this...
Purpose is to replicate the search and replace in MS Word for ^p
Here is a rather "radical" method if your document has only paragraphs with text (images or other elements will be lost). See doc about element types here
(comments in code)
function removeNewLines(){
var doc = DocumentApp.getActiveDocument();
var text = doc.getBody().getText();// get a string
var textMod=text.replace(/\n/g,'');// replace all \n with ''
Logger.log(textMod);//optional check in logger
doc.getBody().clear().appendParagraph(textMod);// empty the doc and apend new texr
doc.saveAndClose();// save the result
}
I wanted to do the same thing (replace two new lines with a single new line). Ended up with the following as replaceText() doesn't accept \n for some reason.
function myFunction() {
var body = DocumentApp.getActiveDocument().getBody();
var text = body.editAsText();
var text_content = text.getText();
for(var i = 0, offset_i = 0; i < (text_content.length); i++){
if((text_content.charCodeAt(i)==10) && (text_content.charCodeAt(i-1)==10)){
text.deleteText(i-1-offset_i, i-1-offset_i)
offset_i++;
}
}
}
This code helped me to remove doubled new lines in document:
function removeDoubleNewLines(){
var doc = DocumentApp.getActiveDocument();
var paragraphs = doc.getBody().getParagraphs();
var paragraph;
for (var i = 0; i < paragraphs.length-1; i++) {
paragraph = paragraphs[i];
if(paragraph.getText() === '' &&
paragraph.getNumChildren() === 0) {
paragraph.removeFromParent();
}
}
}

Set the Glyph Type to "Checkbox" in Google Apps Script

I'm adding list items to a Google Doc. I know GlyphType lets you set the bullet type:
var myArray = myObjects[i].myColumn.split(", ");
for (var i = 0; i < myArray.length; i++) {
body.appendListItem(myArray[i])
.setGlyphType(DocumentApp.GlyphType.BULLET)
.setLineSpacing(1.85)
.setIndentStart(40);
}
body.appendListItem("Text").setIndentStart(40);
But how can I set the bullet type to "checkbox"? It is one of the available options within GDocs:
http://www.ultraimg.com/images/ScreenShot.png
I suspect if I were editing an existing document with the glyph type already set, .appendListItem() wouldn't change the glyph type. But my project involves creating a GDoc from scratch and doesn't lend itself well to using a template (because the number of times the template text is used would need to be variable).
Unfortunately It seems to be not possible... below is a small test I tried on a doc with "square bullets" :
function myFunction() {
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var element = body.getChild(1).asListItem();
var attrs = element.getAttributes();
for (var att in attrs) {
Logger.log(att + " : " + attrs[att]);
}
}
And the result : they show up as "normal" bullets.

Need to edit gdoc using a googleappscript

Is it possible that I could add the body of a gdoc into an email? I kinda have an idea of how to do it but I am not completely sure. I have written this code below to kinda help me. I am new to this and I have managed to have a few scripts running, but I am completely lost on this one. I have watched several videos and this is what I was able to do. The code is below.
Basically what I want to do is to be able to have a user input his name and another variable and then go to the google doc file and change it to the value that was input and then put it back in an email and send it to an address... Any ideas of what I am doing wrong or where should I start?? Thanks in advance.
function gsnot() {
var emailaddress="albdominguez25#gmail.net";
var sub="Subject1";
var pattern = Browser.inputBox("Enter your name");
var pattern2 = Browser.inputBox("Enter the minutes:");
var templateDocID= ScriptProperties.getProperty("EmailTemplateDocId");
var doc = DocumentApp.openById(templateDocID);
var body = doc.getActiveSection()
var html = "";
var keys = {
name: pattern,
min: pattern2,
};
for ( var k in keys ) {
body.replaceText("%" + k + "%", keys[k]);
doc.saveAndClose();
html = getDocAsHtml(docId);
DocsList.getFileById(docId).setTrashed(true);
return html;
var emailaddress="albdominguez25#gmail.net";
var sub="Subject1";
MailApp.sendEmail(emailaddress,sub, {htmlBody: body});}}
You might want to change your code by reading the body from the document into a variable, doing the replace on the variable and inserting that into your email. For example:
function gsnot() {
var emailaddress = "albdominguez25#gmail.net";
var sub = "New Subject";
var pattern = Browser.inputBox("Enter your name:");
var pattern2 = Browser.inputBox("Enter the minutes:");
var templateDocID = ScriptProperties.getProperty("EmailTemplateDocId");
var doc = DocumentApp.openById(templateDocID);
var body = doc.getText();
var replacement;
var k;
var keys = {
name: pattern,
min: pattern2
};
for (k in keys) {
if (keys.hasOwnProperty(k)) {
replacement = new RegExp("%" + k + "%",'g');
body = body.replace(replacement, keys[k]);
}
}
MailApp.sendEmail(emailaddress,sub, '', {htmlBody: body});
}
A few notes:
It is good form to have all your var statements at the beginning of
the function
When you use for-in (eg. for (k in keys) ), it returns all properties of the object. You only want the ones you assigned. This is the reason for: for (k in keys)
You had the mail sending for each property, I believe you wanted it outside the for-in loop so it only sent after all the replacements were completed.
Using replace(), you need to create a regular expression object that is set to global
or it will only replace the first instance of the pattern (you have name twice).
In your parameters for sendEmail(), even if you are using the htmlBody option, you need to specify a plain text body. I used empty quotes ''.