Find & Replace

I made this little script to find & replace anything in a string of text, the values passed to the handler are 1. what to find 2. what to replace it with 3. the text

set thefile to "Hi my mame is joe!"
findAndReplace("joe", "Mike", thefile)

on findAndReplace(tofind, toreplace, TheString)
	set ditd to text item delimiters
	set res to missing value
	set text item delimiters to tofind
	repeat with tis in text items of TheString
		if res is missing value then
			set res to tis
		else
			set res to res & toreplace & tis
		end if
	end repeat
	set text item delimiters to ditd
	return res
end findAndReplace

Hi, LobsterMan.

You don’t need a repeat. You can simply “glue the bits back together” with another delimiter.

set thefile to "Hi my mame is joe!" as Unicode text
findAndReplace("joe", "Mike", thefile)

on findAndReplace(tofind, toreplace, TheString)
	set ditd to text item delimiters
	set text item delimiters to tofind
	set textItems to text items of TheString
	set text item delimiters to toreplace
	if (class of TheString is string) then
		set res to textItems as string
	else -- if (class of TheString is Unicode text) then
		set res to textItems as Unicode text
	end if
	set text item delimiters to ditd
	return res
end findAndReplace

wow, nice. but why do you need the if unicode, can’t you just write

 set res to textItems

and applescript will try and set it to the right type ?

AppleScript does get it right when it creates the list of text items. Each text item is the same class (‘string’ or ‘Unicode text’) as the original string or Unicode text from which it was derived. But we have to use either ‘as string’ or ‘as Unicode text’ to coerce the list back to a continuous text, and have to use the right one for the class of result we want.

In the spirit of compromise, perhaps both points could be accommodated… :wink:

to switchText from t to r instead of s
	set d to text item delimiters
	set text item delimiters to s
	set t to t's text items
	set text item delimiters to r
	tell t to set t to item 1 & ({""} & rest)
	set text item delimiters to d
	t
end switchText

set theText to "Hi - my name is Joe!" as Unicode text
switchText from theText to "Mike" instead of "Joe"

Fiendishly clever, Moriarty! :o It’s fast, preserves Unicode-only characters, and gives the correct result when ‘t’ doesn’t actually contain ‘s’. I’ll use ‘beginning’ rather than ‘item 1’, to save an extra millionth of a second or so, but otherwise that’s going to be my standard usage from now on. (Unless you think of something else in the meantime, of course!)

Now if there were just some way to preserve text styles… :rolleyes:

wow! nice. i have zero experience with writing commands like that, so i don’t know if its possible, but can the syntax make more sense, like

to switchText in t with r replacing s

or is this kind of thing not possible?

If you want to do replacements that way you will need osaxen! (Satimage’s osax does it this way!)

It’s not possible, I’m afraid. A handler defined and called that way is said to have “labeled” (sic) parameters. (The ‘switchText(t, r, s)’ arrangement is called “positional” parameters.) “Labeled parameter” handlers must have at least one parameter, with one the following labels: about, above, against, apart from, around, aside from, at, below, beneath, beside, between, by, for, from, instead of, into, on, onto, out of, over, since, thru (or through), under. There can also be a parameter labelled either ‘in’ or ‘of’, but this must be the first in the list and there must be at least one other parameter, with one of the other labels. There’s also a ‘given’ label, which must go at the end if used, and which has particular usages, one of which allows the use of ‘with’ or ‘without’ in the handler call. (See the AppleScript Language Guide, p.290 → )

These are the only labels allowed, so you have to balance intelligibility against usefulness when deciding whether or not to use this kind of handler. Apart from ‘in’, ‘of’, and ‘given’, the labels are just labels and don’t have any particular meanings themselves. You can use whichever ones you like and arrange them in any order. However, it’s usually quite difficult to think up a combination that makes perfect sense in English.

“Labeled” parameters in a handler call don’t have to be in the same order as in the handler definition. So while the first line of kai’s definition is:

to switchText from t to r instead of s

… he could, if he’d been feeling particularly eccentric, have arranged the call like this:

switchText instead of “Joe” from theText to “Mike”

… or in any other combination, and the variables in the handler would still have been correctly assigned.

Thanks, Nigel. I like your idea of using ‘beginning’, too (so consider it nicked) - and no, don’t think there’s any danger of my thinking of anything else (not at this time of night, anyway)… :wink:

Incidentally, I must be missing the point about ‘t’ containing ‘s’ (but then I have loads of experience in the point-missing department). Could you enlarge, perhaps?

That’s what I like so much about you, Mr G. You just never know when to stop, do you? :stuck_out_tongue:

I won’t echo Nigel’s excellent explanation - but you might prefer something like this (incorporating, just for the record, the “Garvey tweak”):

to switchText of t from s to r
	set d to text item delimiters
	set text item delimiters to s
	set t to t's text items
	set text item delimiters to r
	tell t to set t to beginning & ({""} & rest)
	set text item delimiters to d
	t
end switchText

set theText to "Hi Mike, my name is Joe!" as Unicode text
switchText of theText from "Joe" to "Mike"
--> "Hi Mike, my name is Mike!"

Let’s leave my eccentricities out of this, shall we? Anyway, I much prefer:

switchText to “Mike” from theText instead of “Joe” :slight_smile:

It’s nothing really. The point was actually about ‘t’ not containing ‘s’ - ie. what happens when you do something like this?:

set theText to "Hi - my name is Joe!" as Unicode text
switchText from theText to "Mike" instead of "fish"

It looked at first sight as though your handler might trip up on that, but in fact it doesn’t. :slight_smile: (Unlike my other attempt at a speed improvement. :()

Ah yes. I was trying to remember the other label. The ‘to’ label isn’t mentioned in ASLG’s discussion of “Subroutines With Labeled Parameters”, but it works (and in fact appears in a few examples in ASLG’s “Script Objects” chapter).

Ah - right. (Even though I’d tested for that, you still made me jumpy! :o)

I think I may have tried that one, too… :lol:

Good thing we don’t believe everything we read, right? :wink:

Hi everyone,

sorry to reincarnate an old thread which has obviously been discussed over and over. But I was searching for a solution of my problem and all the time I came to the example given in this thread with Mike an Joe.

My demands are simple: Replace and Find. I want to create a script that exchanges automatically all german umlaut-characters into html-code in a xcode-document. The example looked very nice but how do I get the document’s text?

Nothing seemes to work. I tried several things:

tell application "Xcode"
	activate
	findAndReplace("ä", "ä", window 1)
	findAndReplace("ä", "ä", document of window 1)
	findAndReplace("ä", "ä", text of window 1)
	findAndReplace("ä", "ä", text document of window 1)
	findAndReplace("ä", "ä", text of document of window 1)
	findAndReplace("ä", "ä", text of text document)
	findAndReplace("ä", "ä", text document)
	findAndReplace("ä", "ä", text)
end tell

So, there are three things I want to ask:

  1. How to make my code work?
  2. Where will the result be placed? Will it automatically be placed within the document again or do I need to restore it as with something like
set text of document to findAndReplace("ä", "ä", text of text document)
  1. Where are the existing AppleScripts of XCode stored so in the future, I can see for myself?

Thanks in advance!

Hi Everyone,

I am very new for applescript. I want to develop a script to find and replace in a InDesign document.

Is it possible to do it. See I want to replace “rajeev” with “kumar” and so on.

Please help me and if the root program is sufficient for me then please tell me how can I use it.
regards,
Rajeev

what happens when you try using one of the above scripts? what happens? can you give us a code example?

When I’m using one of the examples above, I get an error in the scripteditor: It is something like(translated into english)

“XCode receyved an error. Impossible to continue: findAndReplace”

As example, I have a file with the following content (This is german):

“Würde dieses Script funktionieren, dann hätte ich keine Fehlermeldung erhalten.”

I want to run this script to get the following:

“Würde dieses Script funktionieren, dann hätte ich keine Fehlermeldung erhalten.”

You can use whatever routine you want for the search and replace, and this is how you target the content of the currently edited window:

tell application "Xcode"
	tell first responder of window 1
		set content to my snr((get content), "ä", "ä")
	end tell
end tell

on snr(the_string, search_string, replace_string)
	tell (a reference to my text item delimiters)
		set {old_tid, contents} to {contents, search_string}
		set {the_string, contents} to {the_string's text items, replace_string}
		set {the_string, contents} to {the_string as Unicode text, old_tid}
	end tell
	return the_string
end snr

Jon

Great! Thank you so much!

This is a completely new field for me. Very nice of you to help me so much. I still don’t understand every step of your implementation, but it works.

I will try to understand your code so that I do not need to disturb you in this forum again. :wink:

Greetings.

There are a few issues involved here, and a brief explanation might help…

The various handlers discussed in this thread all modify a string within AppleScript. However, for such a script to have any practical use, we really need to do something like this:

[i]b[/b] bring in the text, from either a file or an application

b[/b] modify the text in AppleScript, using an appropriate routine/handler

b[/b] return the modified text to the file or application, replacing the original*.

(* Or create a ‘copy’ of the file/document to contain the modifications.)[/i]

Depending on the situation or application involved, the method of ‘importing’ and ‘exporting’ text may vary - but the general principles remain the same.

If there are several changes to be made to the text, it’s usually faster and more convenient to get the original text, perform all the required changes in AppleScript - and then return the finally modified text - rather than repeating the get/modify/return operations. (There may be exceptions with very large gobs of text - but that’s probably worth a separate discussion.)

Multiple search/replace operations could be handled using a couple of lists (obviously of equal length), one containing the search strings - the other, the replace strings. The examples below should give some idea of how all this might be put together.

Note: all the script examples that follow should include these properties and handlers:
(In an effort to reduce the length of this message, they have not been repeated in each example.)

Editing note: The ‘considering case’ block above was added to deal with certain Unicode text issues in Tiger (raised by Nigel Garvey later in this thread).

Converting a text file:

To change a text file directly, we might do something like this (make sure you test on file copies - not originals):

(* insert above script properties & handlers here *)

(* stage 1: import old text *)
set currFile to choose file
set openFile to open for access currFile with write permission
set oldText to read openFile

(* stage 2: convert text *)
set newText to convertText(oldText)

(* stage 3: export new text *)
set eof openFile to 0 (* delete old text *)
write newText to openFile
close access openFile

Converting text in an application document/window:

To do something similar in, say, a TextEdit document, we could modify the script to something like this:

(* insert above script properties & handlers here *)

(* stage 1: import old text *)
tell application "TextEdit" to set oldText to document 1's text

(* stage 2: convert text *)
set newText to convertText(oldText)

(* stage 3: export new text *)
tell application "TextEdit" to set document 1's text to newText

However, it’s quite common to get and set application objects within a single application tell block. So what happens if we try the following construct instead?

(* insert above script properties & handlers here *)

tell application "TextEdit"
	
	(* stage 1: import old text *)
	set oldText to document 1's text
	
	(* stage 2: convert text *)
	set newText to convertText(oldText)
	
	(* stage 3: export new text *)
	set document 1's text to newText
	
end tell

--> "TextEdit got an error: Can't continue convertText."

This is the same sort of error (number -1708) that Manderby reported earlier from XCode. Such errors occur when an AppleEvent is not handled by any handler, and so the script cannot continue. Some confusion can result when the reasons (and remedies) are not known or understood. So what’s causing the problem here?

Simply this: if we need to call a subroutine from within a tell statement, we must use the reserved words ‘of me’ (or ‘my’). This indicates that the subroutine is part of the script - and not a command that should be executed by the object of the tell statement (in this case, TextEdit).

In the above example, TextEdit just doesn’t know what to do with the ‘convertText(oldText)’ statement - so it throws up its hands in confusion, and the event is not handled. To avoid an error, we need to change the line:

to:

Of course, once we’re clear in our thinking about the different stages and objects, we could (if required) abbreviate the tell statement to a single line:

(* insert above script properties & handlers here *)

tell application "TextEdit" to tell document 1 to set its text to my convertText(its text)

As mentioned earlier, the precise syntax may vary from one application to the next - but you could probably do something similar with Xcode:

(* insert above script properties & handlers here *)

tell application "Xcode" to tell first responder of window 1 to set content to my convertText(get content)

Sorry about the length of this - but I hope it helps to clear up one or two things… :slight_smile:

Hello kai,

sorry for the long responding time. This is amazing. Big thank you.

I haven’t had the time to try your examples out but I will. I think that I can learn a lot about AppleScript by your post. The idea of switching context within a script is new to me but as soon as I got this idea it’s clear why to use a “of me”-Statement. I also think that changing the text as a whole within the script rather than copying back the results each time a replacement has been done will improve the speed of the script.

I already encountered some Problems with the capital umlauts ÄÖÜ instead of äöü but I think I can solve this problem with your examples.

Again. Thanks for your help to the master of AppleScript :slight_smile:

Greetings.