Remove line breaks using apps scripts in a Google Document - google-apps-script

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();
}
}
}

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
}
}
}
}
}
}

Get correct user-selected text in Google Docs Apps Script

I need the full text of a user-made selection in Google Docs which may stretch over multiple lines.
This is different from this question: Get user-selected text
because in that question the request was to get the text of individual words or lines that are selected. I need to be able to handle multiple lines with the correct whitespace.
I wrote the code below, and it almost works, but it smashes the text from two lines together without a newline character (or anything) separating them. It also doesn't include tabs from the original text. I'm guessing there are other limitations I haven't come across!
function getSelectedText()
{
var selection = DocumentApp.getActiveDocument().getSelection();
if( !selection )
return "";
var selectedElements = selection.getRangeElements();
var theText = "";
for( var i=0; i < selectedElements.length; i++ )
{
var thisText = selectedElements[i].getElement().asText().getText();
if( selectedElements[i].isPartial() )
{
var thisText = thisText.substring( selectedElements[i].getStartOffset(), selectedElements[i].getEndOffsetInclusive() + 1)
}
theText += thisText;
}
return theText;
}
So let's say I have a document that looks like this with all the text selected by the user (with a tab in the second line):
Line 1
Line 2
My script will construct the string, "Line 1Line 2".
The string I would like is, "Line 1\nLine 2" or "Line 1\rLine 2".
This function came from a function I wrote to high light selected text. I modified it to append selected text back into the document so that it could be displayed in a non html format which will not display white space. Hopefully this will be helpful to you.
function getCurrentSelection() {
var doc=DocumentApp.getActiveDocument();
var selection=doc.getSelection();
var total="";
if(selection) {
var selectedElements = selection.getRangeElements();
for(var i=0;i<selectedElements.length;i++) {
var selElem = selectedElements[i];
var el = selElem.getElement();
var isPartial = selElem.isPartial();
if(isPartial) {
var selStart = selElem.getStartOffset();
var selEnd = selElem.getEndOffsetInclusive();
}else {
var selStart = selElem.getStartOffset();
var selEnd = selElem.getEndOffsetInclusive();
}
var elType=el.getType();
if(elType==DocumentApp.ElementType.TEXT) {
var txt = selElem.getElement().asText().getText().slice(selStart,selEnd+1);
}
if(elType==DocumentApp.ElementType.PARAGRAPH) {
var txt = selElem.getElement().asParagraph().getText();
}
total+=txt;
}
}else {
total='';
}
doc.getBody().appendParagraph(total);
}
I have managed to copy the selected text (with line-breaks and tabs) with the following modification of your code:
function myFunction() {
var doc=DocumentApp.getActiveDocument();
var selection = DocumentApp.getActiveDocument().getSelection();
if( !selection )
return "";
var selectedElements = selection.getRangeElements();
for( var i=0; i < selectedElements.length; i++ )
{
var thisText = selectedElements[i].getElement().asText().getText();
doc.getBody().appendParagraph(thisText);
}
}
On selectedElements you get each of the paragraphs you have selected, lets say 2 paragraphs and an intro in the middle. Then you append each of these elements / paragraphs as a new paragraph.
Check if this works for you and let me know!
Kessy's answer made me hypothesize I'm overthinking what elements are, and that it may be appropriate to manually add a single carriage return between them in constructing a string. Here's my original code with that slight modification.
So far it works, but if my assumption about elements is wrong, it may fail with text formatted in some untested way. (Though if text is formatted in a much more complicated way, it may not make sense to have a specific and unique string version of it anyway. E.g. text in a table.)
function getSelectedText()
{
var selection = DocumentApp.getActiveDocument().getSelection();
if( !selection )
return "";
var selectedElements = selection.getRangeElements();
var theText = "";
for( var i=0; i < selectedElements.length; i++ )
{
var thisText = selectedElements[i].getElement().asText().getText();
if( selectedElements[i].isPartial() )
var thisText = thisText.substring( selectedElements[i].getStartOffset(), selectedElements[i].getEndOffsetInclusive() + 1)
theText += thisText;
//I'm assuming each element is separated by one carriage return.
if( i+1 < selectedElements.length )
theText += '\r';
}
return theText;
}

App Script Google Docs Replace Text in Body

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
}
}
}

In Google Scripts (Google Docs), how do identify if certain words in a paragraph object is in bold?

Let's say I have this paragraph object in my Google Docs:
President: Joe Obam
How do identify if the paragraph object has certain parts in it that's in bold? And further more, how do I extract which words are in bold?
function myfunction() {
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
// Analyze the first paragraph in document
var paragraph = body.getChild(0);
// assumes the paragraph only has text
var txt = paragraph.asParagraph().getChild(0);
var len = txt.asText().getText().length;
for (var i = 0; i < len; i++) {
var isbold = txt.asText().isBold(i);
if (isbold) {
Logger.log("yes");
}
else {
word = "";
}
}
}
This code will check your doc char by char, and it will print "yes" if even a single char is bold.

Google Docs Apps script - how to remove really empty paragraphs

How we can remove really empty paragraphs from Google Document?
This code will remove any paragraphs that contains images, hr's etc. Can't understand how to check if a paragraph really empty?
getText() and editAsText() gives nothing to this.
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var docParagraphs = doc.getBody().getParagraphs();
for (var i = 0; i < docParagraphs.length; i++) {
if (docParagraph[i].getText() === '') {
docParagraphs[i].removeFromParent();
}
}
I know there are topic related to ~similar problem, but not the same. How to find and remove blank paragraphs in a Google Document with Google Apps Script?
UPD: correct answer:
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
for (var i = 0; i < doc.getBody().getParagraphs().length; i++) {
if (docParagraph[i].getText() === '') {
if (docParagraph_i.getNumChildren() == 0 && i < (docParagraphs.length - 1)) {
docParagraph[i].removeFromParent();
}
}
}
I've changed for expression too to limit i by a current elements count, not stored in variable. Because elements are deleted (or in other implementation added, for example) there will be error when no paragraphs but cycle will want to get them.
&& i < (...)
because last paragraph can't be deleted and throws an error.
You will want to check for children in the paragraph
paragraph.getNumChildren() //returns the number of children