1

I have multiple Pages documents in which I need to replace special set of characters - in our language we have one-character prepositions (e.g. v, s, k, u, a), that can't be orphaned at the end of lines, so I need to replace the preposition and the next space with preposition and non-breakable space. Have been trying to use AppleScript (am quite newbie to programming) like this one:

set findList to {"v ", "s "}
set replaceList to {"v ", "s "}

set AppleScript's text item delimiters to ""

tell application "Pages"
    activate
    
    tell body text of front document
        repeat with i from 1 to count of findList
            set word of (words where it is (item i of findList)) to (item i of replaceList)
        end repeat
    end tell
end tell
return

This does not work as long as there are any spaces in the findList and replaceList parameters.

So I found, that text item delimiters might help me. I was able to make this script

set theText to "Some of my text with v in it"
set AppleScript's text item delimiters to "v "
set theTextItems to text items of theText
set AppleScript's text item delimiters to "v " --this is v with non-breakable space (alt+space)
set theText to theTextItems as string
set AppleScript's text item delimiters to {""}
theText

which works, but only with plain text set on the first line of the code (when I copy the result to Pages there is truly a non-breakable space).

But now I need to write a script, that works on the whole text of Pages document.

I have tried something like this:

tell application "Pages"
    activate
    
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to "v "
    set textItems to body text of front document
    set AppleScript's text item delimiters to "v " --again v with non-breakable space (alt+space)
    tell textItems to set editedText to beginning & "v " & rest --again v with non-breakable space (alt+space)
    set AppleScript's text item delimiters to astid
    set text of document 1 to editedText
end tell

but I get the error

Can’t get beginning of "here is the whole text of the Pages document"." number -1728 from insertion point 1 of "and again the whole text of the document"

If I change the script to:

tell application "Pages"
    activate
    
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to "v "
    set textItems to text items of body text of front document
    set AppleScript's text item delimiters to "v "
    tell textItems to set editedText to beginning & "v " & rest
    set AppleScript's text item delimiters to astid
    set text of document 1 to editedText
end tell

I get another error

Pages got an error: Can’t get every text item of body text of document 1." number -1728 from every text item of body text of document 1

Can anyone point me to the right direction how to properly script this?

Thanks.

2 Answers 2

2

I hope this will help you. This uses AppleScript's text item delimiters to split/join back texts. It can be more compact, but this is a comprehensive way to write it. As you can use it often in your script, it's a good thing to put it in a special subroutine. I build a list of pairs {search,replace} easier to maintain in one place, and a "repeat" loop to apply every pair of corrections. Don't forget the "my" statement as Pages doesn't own strRepl() and will fire an error.

Unfortunately, extracting text, and putting it back into Pages will loose any text attributes. So here it is :

set findReplaceList to {{"a", "A"}, {"b ", "B"}, {"this", "that"}}

tell application "Pages"
    set bodyText to body text of front document -- get the content as text
    repeat with thisFindReplaceValues in findReplaceList
        copy thisFindReplaceValues to {findItem, replaceItem} -- put first and second item resp. in findItem and replaceItem
        set bodyText to my strRepl(bodyText, findItem, replaceItem) -- search and replace text
    end repeat
    set body text of front document to bodyText -- put the new text back. Loosing attributes.
end tell
    
on strRepl(SourceStr, searchString, newString)
    set saveDelim to AppleScript's text item delimiters
    set AppleScript's text item delimiters to searchString -- change ATID : the search item
    set temporaryList to every text item in SourceStr -- split the text in parts removing searched items
    set AppleScript's text item delimiters to newString -- New ATID : the replace item
    set SourceStr to temporaryList as text -- this put back the parts to text with newString between
    set AppleScript's text item delimiters to saveDelim -- clean up ATIDs
    return SourceStr
end strRepl
Sign up to request clarification or add additional context in comments.

1 Comment

This one works the same way as the one above, it changes style of all the paragraphs to the style of the first paragraph. Is there any chance of retaining the text attributes?
2

This script is a variation on @Chino22's. Given the consistent requirement here (always a single letter, replaced by itself), I've moved to a simple list of single elements and set the replacement when calling the handler.

-- List of prepositions to seek out (added the 'z' as it was prevalent in the article used for testing)
set chList to {"v", "s", "k", "u", "a", "z"}

    tell application "Pages"
    set bodyText to body text of front document
    repeat with prep in chList
        -- call replacement handler
        set bodyText to my strRepl(bodyText, space & prep & space, space & prep & character id 160)
    end repeat

    set body text of front document to bodyText
end tell

on strRepl(srcStr, oldStr, newStr)
    
    set AppleScript's text item delimiters to oldStr
    considering case
        set temporaryList to every text item in srcStr
    end considering
    set AppleScript's text item delimiters to newStr
    set srcStr to temporaryList as text
    
    return srcStr
end strRepl

NB My search and replace strings include a space both before and after the letter. This ensures that only single-letter words are affected. I added a considering case to further restrict the search to lower case letters. The 'character id 160' specifies the non-breaking space. Finally I left out the first and last delimiter commands to reduce clutter. Add them back at your discretion. A single letter followed by punctuation will not be processed.

Regarding some of the errors you were seeing… They are likely a result of Pages having issues with text item delimiters within its tell block. In general, you would need to split the script into three sections, along these lines:

tell application "Pages" to set bt to body text of front document

myriad delimiters stuff, including 'set editedText to…'

tell application "Pages" to set body text of front document to editedText

Using the handler as Chino22 suggests circumvents this issue by putting all that work within the handler (which is outside the tell block). Also, 'beginning' and 'rest' don't mean what you assume they do in applescript. Finally, I have read of recommendations for working at the paragraph level rather than with the entire body text. It may not be an issue for you but perhaps if you are working with very large documents and have issues, it may be worth making some modifications to the script.

2 Comments

Thank you very much, this one works, but it changes style of all the paragraphs to the style of the first paragraph. Don't know why.
That's a mess. The likely reason is that Pages sucks. That said, as mentioned above, perhaps it is possible to break the entire text into paragraphs, and then for each paragraph, get the color/font/size, perform the search and replace, and then re-set the color/font/size. Personally, I find pages a bear to work with… it does some interesting things very easily and then makes simple things nigh on impossible.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.