Find & Replace

I discovered last night, while tracking down an elusive bug in something I was doing, that text item delimiters are now (in Tiger) governed by ‘considering’ and ‘ignoring’ states - at least, when the main text is Unicode text. In other words, they’re case-insensitive unless you specify otherwise. This doesn’t seem to be the case with plain text, where TID’s still behave exclusively case-sensitively on my machine.

The ‘offset’ command is similarly ruled by ‘considering’ and ‘ignoring’, but regardless of the text type.

considering case
	set newText to convertText(oldText)
end considering

I get the same behavior on my 10.4.1 machine:

set the_string to "A String" as Unicode text
set search_string to "a" as Unicode text
set replace_string to "b" as Unicode text
set the_string to my snr(the_string, search_string, replace_string)
-->"b String"

set the_string to "A String" as string
set search_string to "a" as string
set replace_string to "b" as string
set the_string to my snr(the_string, search_string, replace_string)
-->"A String"

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

I consider this a bug.

Jon

Thanks for the confirmation, Jon. I agree about it being a bug - even if it might turn out to be intentional.

The talk is that the various forms of class ‘string’ are now either deprecated or not recommended, which may explain why no-one’s bothered to update TID handling in their respect. But a lot of scripts are going to break now that delimiters are case-insensitive by default; and with a large number of existing scripters still unconsciously assuming that TIDs are sensitive to everything, and with Script Editor still compiling text as strings, there’s a potential for a lot of head-banging as people try to sort out the problems!

Speaking of bugs…

When I have a file which is saved (no dot in the red close-button) and I run this script and there are some changes, the program does not recognizes this as a change (no dot) and ergo does not shows a “save before close Window”-Message as soon as I close the window.

I found this after changing about 200 old files. Now I know that I can do the work again, beacause I didn’t save files that didn’t show the change-dot.

:frowning:

PS: Maybe this error is new on Tiger.

I’m afraid that behaviour’s been around for a while, Manderby. However, it’s possible to persuade some apps that a document has actually been changed - even though it may still not show a changed dot in its red ‘close’ button.

With TextEdit, for example, try something like this:

tell application "TextEdit" to tell document 1
	set its text to "new text" (* or make other changes *)
	set modified to true
	close
end tell

Hm, didn’t work with xcode.

Well, I know this behaviour now so I will always save. Not a big problem.

Not to be a dolt but… I came across this thread and it all looks interesting and cool but too many versions to know which one fits MY needs. I want to add a F&R applescript or automator action to a workflow I’ve created. One of the steps in the workflow copies the path of files into a new text document. I really only need a certain bit of the path so I manually go back in and F&R the first part of the path that is consistent and delete it (replace with “”). Can any of you people who are smarter than me help me with this? A drag and drop application would also work for me.

How about this:

on findAndReplace(toFind, toReplace, theString)
	do shell script "function sq { echo ${1} | perl -pe \"s~/~\"'\\\\\\/'\"~g;\"; }; echo " & quoted form of theString & " | perl -pe \"s/`sq " & quoted form of toFind & "`/`sq " & quoted form of toReplace & "`/g;\""
end findAndReplace

It seems a little more succinct. Should be fast.

Works with unicode too. For example:

yields:

Notes for the Unix inclined:
I’m pretty sure i’ve reinvented the wheel in defining the sq shell function, but i couldn’t come up with an existing Unix tool to do the job so i made my own. The function simply backslash-escapes (i.e. protects) any occurrence of the delimiter character (i.e. a forward slash) contained in either the toFind or toReplace strings. Without that, an error could occur.

For those who are curious, the do shell script call is roughly this after AppleScript gets through with parsing the quotes (italics represent the quoted values of AppleScript variables):

Hi, Rainy Day.

This is a good example of where vanilla AppleScript scores over using a shell script. The shell script code itself may be blindingly fast, but the ‘do shell script’ call that invokes it from AppleScript carries a time overhead that’s comparatively large.

This vanilla handler, although not as “succinct”, is about eleven times as fast as yours on the machine I’m using at the moment. Whether or not it’s easier to understand depends on whether you come from AppleScript or Unix and Perl, I suppose: :wink:

on findAndReplace2(toFind, toReplace, theText)
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to toFind
	set textItems to theText's text items
	set AppleScript's text item delimiters to toReplace
	tell textItems to set editedText to beginning & toReplace & rest
	set AppleScript's text item delimiters to astid
	
	return editedText
end findAndReplace2

This actually returns Unicode regardless of the class of the original. The vanilla handler above contains a technique by kai that returns a result of the same class as the original.

Hey, Kai. How’s this for beating a dead horse: I just came across your post (three years later!) and did it one better:

to switchText from t to r instead of s
repeat with i from (count of items in s) to 1 by -1
set d to text item delimiters
set text item delimiters to item i of 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 repeat
end switchText

It still works with a single text string to replace, but then you can also specify a list of characters to replace, e.g.

switchText from textString to “C” instead of {“A”, “a”, “B”, “b”}

Thanks for doing 90% of the work, though! :smiley:

Hi, theOtter. Welcome to these fora!

I was going to explain that your version wouldn’t work if ‘s’ was Unicode text (or just ‘text’ in Leopard), because it’s recently been discovered that you can’t extract ‘items’ from Unicode text. However, this seems only to apply to the ‘every’ reference form. You can still count Unicode text ‘items’ and can extract them by index as you have. So your script does work with both text and lists of delimiters as claimed. Nice one. :slight_smile:

However, it changes the meaning of a single text parameter for s. In Kai’s script, switchText from “banana” to “c” instead of “nan” would produce “baca”, whereas with yours it’s “bccccc”. To get the same effect as Kai, you’d have to provide a single-item list: switchText from “banana” to “c” instead of {“nan”}.

Sadly, Kai suddenly stopped posting anywhere in April last year and no-one’s heard from him since or been able to contact him. :frowning:

Good catch, Nigel. I actually only needed to replace single characters in the particular script I was testing (adding my own enhancements to iTunes Track CPR 1.3, from Doug’s AppleScripts for iTunes), so I didn’t think to test the “banana” concept. Thanks for pointing that out, and thanks also for the warm welcome! :slight_smile: