Copy link to clipboard
Copied
Hi Everyone,
At a previous job of mine, a colleague had developed and shared an awesome script that cleans all the whitespace out of InDesign layouts (Multiple Space to Single Space, Remove Leading Whitespace, Remove Trailing Whitespace, Multiple Return to Single Return). This thing works like magic.
Every job I've had since getting this script were in Mac environments. The only thing I had to do to make it work on later versions of InDesign was to edit "tell application" to the updated app. However, right now I'm working remotely and I've been forced to use my PC to get work done and it would be really helpful if I had a javascript version of it.
Of course you guys can use this and/or pass it around so long as you credit my colleague. His info is in the prologue of the script.
Warning: this script does not play well with designers who do not lay their text out properly. If you use double returns and multiple spaces or tabs in your layout instead of proper paragraph styles with "space after", this script will wreck the layout.
-----------------------------------------------------------------------------------
--
-- Script Name: Clean Text White Space.scpt
-- Version: 1.0
-- Author: Brendan McBryan
-- Contact: brendan.mcbryan@gmail.com
-- Date: March 3, 2011
-- Application: Adobe InDesign CS4
--
-- Description: This AppleScript is designed to be run from the scripts panel in InDesign CS4. It will run the most common Find & Change actions relating to cleaning up white space in Text.
--
--The Actions included are: Multiple Space to Single Space, Remove Leading Whitespace, Remove Trailing Whitespace, Multiple Return to Single Return.
--
-----------------------------------------------------------------------------------
tell application "Adobe InDesign CC 2018"
--MULTIPLE SPACE TO SINGLE SPACE
--Clear the find/change preferences.
set find grep preferences to nothing
set change grep preferences to nothing
--Load Find/Change variables for Multiple Space to Single Space
set varFind to "[~m~>" & "~f~|~S~s~<~/~.~3~4~% ]{2,}" as string
set varChange to "\\s" as string
set include hidden layers of find change grep options to true
set the find what of find grep preferences to varFind
set the change to of change grep preferences to varChange
-- Execute Multiple Space to Single Space
tell active document
set varFoundMultipleSpace to change grep
end tell
--REMOVE LEADEING WHITESPACE
--Clear the find/change preferences.
set find grep preferences to nothing
set change grep preferences to nothing
--Load Find/Change variables for Remove Leading Whitespace
set varFind to "^ " as string
set varChange to "" as string
set include hidden layers of find change grep options to true
set the find what of find grep preferences to varFind
set the change to of change grep preferences to varChange
-- Execute Multiple Space to Remove Leading Whitespace
tell active document
set varFoundLeadingSpace to change grep
end tell
--MULTIPLE RETURN TO SINGLE RETURN
--Clear the find/change preferences.
set find grep preferences to nothing
set change grep preferences to nothing
--Load Find/Change variables for Multiple Return to Single Return
set varFind to "~b~b+" as string
set varChange to "\\r" as string
set include hidden layers of find change grep options to true
set the find what of find grep preferences to varFind
set the change to of change grep preferences to varChange
-- Execute Multiple Return to Single Return
tell active document
set varFoundMultipleReturn to change grep
end tell
--REMOVE TRAILING WHITESPACE
--Clear the find/change preferences.
set find grep preferences to nothing
set change grep preferences to nothing
--Load Find/Change variables for Remove Trailing Whitespace
set varFind to "\\s+$" as string
set varChange to "" as string
set include hidden layers of find change grep options to true
set the find what of find grep preferences to varFind
set the change to of change grep preferences to varChange
-- Execute Remove Trailing Whitespace
tell active document
set varFoundTrailingSpace to change grep
end tell
--Display Change Count
set varAnswer to the button returned of (display dialog ¬
("Changed " & (count varFoundMultipleSpace) & " Multiple Spaces to Single Spaces" & return & ¬
"Removed " & (count varFoundLeadingSpace) & " instances of Leading Space" & return & ¬
"Changed " & (count varFoundMultipleReturn) & " Multiple Returns to Single Returns" & return & ¬
"Removed " & (count varFoundTrailingSpace) & " instances of Trailing Space") ¬
as string ¬
buttons {"Undo", "Thanks!"} ¬
with title "Success!")
--Undo if requested
if varAnswer = "Undo" then
tell application "System Events"
repeat 4 times
keystroke "z" using command down
end repeat
end tell
end if
end tell
This script does a grep find and change for several things, prompts you with how many things it changed, and gives you the option to undo what it did.
Please let me know if anyone can help with this. Thanks!!
1 Correct answer
Here's my go-to findchange. You'd put the existing strings from your applescript into the multidimensional "fcs" array.
var myChangeGrep = function( findPrefs, changePrefs, story ) {
for ( var i in findPrefs ) {
app.findGrepPreferences[i] = findPrefs[i];
}
for ( var j in changePrefs ) {
app.changeGrepPreferences[j] = changePrefs[j];
}
story.changeGrep( true );
app.findGrepPreferences = NothingEnum.NOTHING;
app.changeGrepPreferences = NothingEnum.NOTHING;
};
var main =
...
Copy link to clipboard
Copied
Here's my go-to findchange. You'd put the existing strings from your applescript into the multidimensional "fcs" array.
var myChangeGrep = function( findPrefs, changePrefs, story ) {
for ( var i in findPrefs ) {
app.findGrepPreferences[i] = findPrefs[i];
}
for ( var j in changePrefs ) {
app.changeGrepPreferences[j] = changePrefs[j];
}
story.changeGrep( true );
app.findGrepPreferences = NothingEnum.NOTHING;
app.changeGrepPreferences = NothingEnum.NOTHING;
};
var main = function() {
var doc = app.activeDocument;
var fcs = [
["findstring", "changestring"],
["findstring", "changestring"],
//more arrays here
];
app.findGrepPreferences = NothingEnum.NOTHING;
app.changeGrepPreferences = NothingEnum.NOTHING;
for (var i = 0; i < fcs.length; i++) {
myChangeGrep({findWhat:fcs[i][0]}, {changeTo:fcs[i][1]}, doc);
}
}
main();
Copy link to clipboard
Copied
That sounds promising. Unfortunately, I'm not much of a coder at all. Could you expand on your explanation a bit?
Thanks!
Copy link to clipboard
Copied
Everywhere where you have this expression:
set varFind to "\\s+$" as string
set varChange to "" as string
Fill in the "findstring" and "changestring" in the fcs array in my example:
fcs = [
["\\s+$", ""],
["[~m~>" & "~f~|~S~s~<~/~.~3~4~% ]{2,}", "\\s"],
and so on
];
Copy link to clipboard
Copied
Ok I tried making the followinng into a .jsx file:
var myChangeGrep = function( findPrefs, changePrefs, story ) {
for ( var i in findPrefs ) {
app.findGrepPreferences[i] = findPrefs[i];
}
for ( var j in changePrefs ) {
app.changeGrepPreferences[j] = changePrefs[j];
}
story.changeGrep( true );
app.findGrepPreferences = NothingEnum.NOTHING;
app.changeGrepPreferences = NothingEnum.NOTHING;
};
var main = function() {
var doc = app.activeDocument;
var fcs = [
["[~m~>" & "~f~|~S~s~<~/~.~3~4~% ]{2,}", "\\s"],
["^ ", ""],
["~b~b+", "\\r"],
["\\s+$", ""],
];
app.findGrepPreferences = NothingEnum.NOTHING;
app.changeGrepPreferences = NothingEnum.NOTHING;
for (var i = 0; i < fcs.length; i++) {
myChangeGrep({findWhat:fcs[i][0]}, {changeTo:fcs[i][1]}, doc);
}
}
main();
and i got the following error:
PS: I'm using InDesign CS6 right now. Maybe the FCS string is new code that this version of ID doesn't understand.
Also, is this script supposed to work on selected text or does it do the whole document? Either way the one I posted does the whole document and it would be great if we could get this version to do it that way as well.
Thanks!!!
Copy link to clipboard
Copied
This would do it on the whole doc. I think you need to escape your quote mark in the first array, or break it up into two arrays. Not exactly sure what that expression is looking for.
["[~m~>" & "~f~|~S~s~<~/~.~3~4~% ]{2,}", "\\s"],
Copy link to clipboard
Copied
Ok its working! I had to troubleshoot some weird things the script was doing but now I think its working.
var myChangeGrep = function( findPrefs, changePrefs, story ) {
for ( var i in findPrefs ) {
app.findGrepPreferences[i] = findPrefs[i];
}
for ( var j in changePrefs ) {
app.changeGrepPreferences[j] = changePrefs[j];
}
story.changeGrep( true );
app.findGrepPreferences = NothingEnum.NOTHING;
app.changeGrepPreferences = NothingEnum.NOTHING;
};
var main = function() {
var doc = app.activeDocument;
var fcs = [
["[~m~>~f~|~S~s~<~/~.~3~4~% ]{2,}", "\\s"],
["^ ", ""],
["~b~b+", "\r"],
["\\s+$", ""],
];
app.findGrepPreferences = NothingEnum.NOTHING;
app.changeGrepPreferences = NothingEnum.NOTHING;
for (var i = 0; i < fcs.length; i++) {
myChangeGrep({findWhat:fcs[i][0]}, {changeTo:fcs[i][1]}, doc);
}
}
main();
That first string that was giving us trouble was searching for multiple spaces. Luckily, InDesign had a preset GREP search that looks for the multiple spaces that worked correctly so I swapped that one in.
Also for some reason the trailing space part of the script was removing multiple trailing spaces but leaving 1 trailing space. For some reason, having
\\s+$
instead of
\s+$
in the find part of the string made it work properly even though the replace part of the string was just
""
Wow this is going great!
So the Applescript version has a dialogue box that opens after running the script. It display how many instances of each string it found. It also has an "undo" button and a "Thanks!" button. Pessing the undo button undoes the script by pressing cmd-z 4 times (on PC I guess it would have to be ctrl-z). Pressing "thanks" just closes the dialog box. So how would we go about doing this for the javascript version?
Copy link to clipboard
Copied
Outside my paygrade for free forum help! If you want to undo, you can hit undo four times.
Copy link to clipboard
Copied
Fair enough. You get all the stars today. Thanks for your help!!
Copy link to clipboard
Copied
I use an Applescript with a handler so the code is easier to read and edit, and the searches can be set as single lines:
tell application "Adobe InDesign 2020"
activate
--replaces multiple tabs with single tab
my GrepSearch("\\t+", "\\t")
--removes any white space at the start of a paragraph including multiple returns
my GrepSearch("^\\s*", "")
--replaces multiple spaces with one space
my GrepSearch("\\p{zs}{2,}", "\\s")
--replaces soft return with a hard return
my GrepSearch("\\s?\\n", "\\r")
--replaces non breaking spaces with spaces
my GrepSearch("~s|~S", "\\s")
end tell
on GrepSearch(f, c)
tell application "Adobe InDesign 2020"
set find grep preferences to nothing
set change grep preferences to nothing
set find what of find grep preferences to f
set change to of change grep preferences to c
change grep
end tell
end GrepSearch
Here’s the equivalent in JS—both search the entire document:
//replaces multiple tabs with single tab
grepSearch("\t+", "\t");
//removes any white space at the start of a paragraph including multiple returns
grepSearch("^\s*", "")
//replaces multiple spaces with one space
grepSearch("\p{zs}{2,}", "\s")
//replaces soft return with a hard return
grepSearch("\s?\n", "\r")
//replaces non breaking spaces with spaces
grepSearch("~s|~S", "\s")
function grepSearch(f,c){
app.findGrepPreferences.findWhat=NothingEnum.NOTHING
app.changeGrepPreferences.changeTo=NothingEnum.NOTHING
app.findGrepPreferences.findWhat = f;
app.changeGrepPreferences.changeTo = c;
app.activeDocument.changeGrep( true )
}
Copy link to clipboard
Copied
Thanks for posting! I'm not sure those search terms would be helpful in my workflow. The script I use is primarily to clean up text that I'm bringing in from Word docs from other people. This script cleans up all the garbage that comes from bad practices that people who are accustomed to using Word pick up and also people just not being careful. (Pasting in from word has it own annoyances too, like when you paste in a bulleted or numbered list, and now I can build a script to fix that).
I'm just curious why you would want to replace soft returns with hard returns and non breaking spaces with spaces. I need to use those all the time.
Copy link to clipboard
Copied
Now it's my turn to give back a bit.
Here are scripts I just made that would help clean up your text brought in from word. Of course the correct way to have bulleted and numbered lists is with a proper InDesign paragraph style. But pasting lists in from Word comes with extra junk. So these scripts will clean that up.
Bulleted List script:
var myChangeGrep = function( findPrefs, changePrefs, story ) {
for ( var i in findPrefs ) {
app.findGrepPreferences[i] = findPrefs[i];
}
for ( var j in changePrefs ) {
app.changeGrepPreferences[j] = changePrefs[j];
}
story.changeGrep( true );
app.findGrepPreferences = NothingEnum.NOTHING;
app.changeGrepPreferences = NothingEnum.NOTHING;
};
var main = function() {
var doc = app.activeDocument;
var fcs = [
["~8\t", ""],
];
app.findGrepPreferences = NothingEnum.NOTHING;
app.changeGrepPreferences = NothingEnum.NOTHING;
for (var i = 0; i < fcs.length; i++) {
myChangeGrep({findWhat:fcs[i][0]}, {changeTo:fcs[i][1]}, doc);
}
}
main();
Numbered list script:
var myChangeGrep = function( findPrefs, changePrefs, story ) {
for ( var i in findPrefs ) {
app.findGrepPreferences[i] = findPrefs[i];
}
for ( var j in changePrefs ) {
app.changeGrepPreferences[j] = changePrefs[j];
}
story.changeGrep( true );
app.findGrepPreferences = NothingEnum.NOTHING;
app.changeGrepPreferences = NothingEnum.NOTHING;
};
var main = function() {
var doc = app.activeDocument;
var fcs = [
["\\d+\.\t", ""],
];
app.findGrepPreferences = NothingEnum.NOTHING;
app.changeGrepPreferences = NothingEnum.NOTHING;
for (var i = 0; i < fcs.length; i++) {
myChangeGrep({findWhat:fcs[i][0]}, {changeTo:fcs[i][1]}, doc);
}
}
main();
I hope this helps someone!
Copy link to clipboard
Copied
For example both your searches run with a 10 line script:
grepSearch("~8\t", "");
grepSearch("\\d+\.\t", "")
function grepSearch(f,c){
app.findGrepPreferences.findWhat=NothingEnum.NOTHING
app.changeGrepPreferences.changeTo=NothingEnum.NOTHING
app.findGrepPreferences.findWhat = f;
app.changeGrepPreferences.changeTo = c;
app.activeDocument.changeGrep( true )
}
I'm just curious why you would want to replace soft returns with hard returns and non breaking spaces with spaces. I need to use those all the time.
If the text is from an outside source usually I’m trying to completely strip the formatting from the Word doc. The author’s soft return or non breaking space might not be needed when the text is reformatted in InDesign. I certainly don’t want tabbed indents or returns as space between paragraphs
Copy link to clipboard
Copied
You can edit the function calls to be anything you want. A function or Applescript handler makes the code more effiecient—my 12 lines of code is running 5 grep searches.
To customize for your needs simply add or edit the function calls as needed
grepSearch("your grep search string", "your grep change string");
Note that in AppleScript you have to escape backslashes with a backslash
my GrepSearch("\\t+", "\\t")
--not my GrepSearch("\t+", "\t")

