READING TEXT FILES AS LISTS

To finish off our discussion series on working with lists, this post focuses on lists created and used when reading delimited text files. Along the way we will get a brief look at finding and replacing text in Adobe InDesign.

Read Delimited Text File

Lets say we have a plain text file with a number of text items separated with a line return. To use these text items in an InDesign document we want to place these into a list. For simplicity our file will read similar to the following:

Text for first paragraph
Text for second paragraph
Text for third paragraph

As a demonstration, our script will place each text item in the file to the beginning of consecutive paragraphs in an InDesign document.

First, we will need to have the script read the text file and place each text item into a list. We will set this up as a handler in AppleScript. The handler will use the choose file command to have the user identify the target file:

set textList to readFileAsList ("Choose plain text file to read")
on readFileAsList(promptStr)
   set fileChoice to choose file of type "txt" with prompt promptStr
   set fileRef to fileChoice as string
   return read file fileRef using delimiter {"/n"}
end readFileAsList

Although this handler is short there is a lot going on here. First an alias to the file chosen is placed into a variable using the choose file command. The alias reference is then coerced to a string. The methods for reading and writing files is part of AppleScript’s StandardAdditions. In its dictionary under the read we see:

read any : the file reference number, alias, or file reference of the file to read
   [using delimiter text] : the value that separates items to read…
   [using delimiters list of text] : …or a list of values that separate items to read that a file can be read 

This requires a little explanation. Notice that the value of the delimiter for the first read option above is text. If you use the word return for the delimiter, the result will not be what you want. Instead, use the string equivalent of a line return “\n”.

set listText to read file textFileReference using delimiter return

The result will be a list of individual items. When the script is compiled, the value of the delimiter “\n” becomes a line return. The list is then returned to the variable textList which can then be parsed with each item used as needed in the script.

PARSING A LIST

As in previous posts, a script can go through a list, item by item (parsing), using any one of a number of repeat methoods.

You can test this out by creating a script, the top part of which is as follows:

set textList to readFileAsList("Choose plain text file to read")
set listLen to length of textList
activate
repeat with i from 1 to listLen
   display alert "Test " & item i of textList
end repeat
--Add readFileAsList handler here

ADDING TEXT TO DOCUMENT

Once a script has a list of strings, adding them to an InDesign document is a simple matter. With the readFileAsList handler added to the following, test with an open document with text added:

try
set textList to readFileAsList("Choose plain text file to read")
set listLen to length of textList
tell application "Adobe InDesign CC 2019"
   set docRef to document 1
   set paraCount to count of paragraphs of story -1 of docRef
   if paraCount ≥ listLen then
	repeat with i from 1 to listLen
	   set thePara to (a reference to paragraph i of story -1 of docRef)
	   set beginning of thePara to (item i of textList & " ")
	end repeat
   else
	error "Story does not have required number of paragraphs"
  end if
end tell
on error errStr 
   activate display alert "Error: " & errStr
end try
--Add readFileAsList handler here

Notice that the variable for each paragraph (thePara) is a reference, and that a space is added to this variable as its value is added to the document.

REPLACING TEXT

Replacing text in a document is not quite as simple. Suppose our document has text to be replaced flagged with the following: “[text 1 here]” and so on scattered throughout the document. We could use a grep find and replace to do the job. The thing to remember is that the result of a find text returns the position of the text within the story as a reference:

   text from character 1947 to character 1959 of story id 279 of document id 7 of application "Adobe InDesign CC 2019"

For this reason, the repeat structuref needs to work from the end of the story to the front so text replacements do not affect the position of the text to be replaced.

Find/Replace Grep

A grep string to replace any text within square brackets could be written:

set grepString to "\\[.*?\\]"

The script then sets find what of find grep preferences to the grepString. The result of the find grep method is a list of text references which can be used for replacement within a repeat loop. Finally, the demonstration script below resets find grep preferences to nothing to be a good neighbor. Add the readFileAsList handler to the following and test with a document to which you have added text flagged with square brackets to designate where text from the file read is to be inserted.

set grepString to "\\[.*?\\]"
try
   set textList to readFileAsList("Choose plain text file to read")
   set listLen to length of textList
   tell application "Adobe InDesign CC 2019"
	set find grep preferences to nothing
	set find what of find grep preferences to grepString
	tell document 1
	   set findList to find grep
	   set myLen to length of findList
	   if myLen is not equal to listLen then
		error ("Not equal number of items for replacement")
	   end if
	   repeat with i from myLen to 1 by -1
		set thisText to item i of textList
		tell item i of findList to set contents to thisText
	   end repeat
	end tell
	set find grep preferences to nothing
   end tell
on error errStr
   activate
   display alert ("Error: " & errStr)
end try
--Add readFileAsList handler here

READ AS LIST OF LISTS

In reading the dictionary for ScriptAdditions it would look as if you could read a tab return delimited file and get a list of lists. Close, but not quite. A script can get a list of the paragraphs and then use text item delimiters to change the tabbed items within each paragraph to a list.

Read File_List of Lists

set dataList to {}
set promptStr to "Choose text file for data"
set fileChoice to choose file of type "txt" with prompt promptStr
set textFile to fileChoice as string
set dataRead to read file textFile using delimiter {"/n"}
set AppleScript's text item delimiters to "	"
repeat with i from 1 to length of dataRead
   set end of dataList to text items of item i of dataRead
end repeat
set AppleScript's text item delimiters to ""
dataList
--Add readFileAsList handler here

ONWARD AND UPWARD

Think of the ways that you could use a text file to automate a repetitive process in InDesign. Then think of the various applications than can create a delimited text file. It opens the imagination to a variety of solutions that may work to automate any number of workflows.

Disclaimer:
Scripts provided are for demonstration and educational purposes. No representation is made as to their accuracy or completeness. Readers are advised to use the code at their own risk.