Changing multiple 'file' specifiers to «class furl» coercions

Shane’s article ADDING APPLESCRIPTOBJC TO EXISTING SCRIPTS employs the conceit that you may want to add ASObjC code to an existing non-ASObjC script containing loads of file specifiers and you don’t have time to go through changing them all to «class furl» coercions.

If you do have more time, you may be able save some of it by using the following regex in Script Debugger’s “Find” field (with the “RegEx” box checked, of course):

\bfile (?i)([a-z_][a-z0-9_]*+|"(?:[^"]|(?<=\\)")*+"|\([^()]*+(?:\([^()]*+(?:\([^()]*+\)[^()]*+)*+\)[^()]*+)*+\)|\|[^|]*+\|)

This matches the word ‘file’ followed by anything which could be a variable label, text in double-quotes, or a parenthesised expression up to three levels deep.

The corresponding replacement string would be:

($1 as «class furl»)

In use, it’s better to step through finds using “Replace & Find” than to hit “Replace All”, since you could easily end up doing peculiar things to comments or application references:

You could probably protect comments by first switching to raw syntax, and modifying the regex accordingly.

But I’m still scratching my head over that pattern :star_struck:

:smile:

I must admit I don’t actually like it! But I can’t think how to shorten it or make it clearer (apart from in-line comments) in ICU regex.

It’s basically the word “file” followed by any one of four case-insensitive options, although the case-insensitivity only applies to the first:

Non-barred label (letter or underscore followed by 0 or more letters, digits, or underscores):
[a-z_][a-z0-9_]*+

Text (double-quote, 0 or more non-quotes or quotes preceded by backslashes, double-quote):
"(?:[^"]|(?<=\\)")*+"

Parenthesis up to three layers deep (don’t ask!):
\([^()]*+(?:\([^()]*+(?:\([^()]*+\)[^()]*+)*+\)[^()]*+)*+\)

Barred label (literal vertical bar, 0 or more non-bars, bar):
\|[^\|]*+\|

I’ve just noticed here that the bar in the set doesn’t need to be escaped, so that does make the regex slightly shorter. :wink: I’ll edit the top post.

\|[^|]*+\|

If you put that pattern in regex101.com, it will give you a nice explanation, although it may not be as good as Nigel’s. If you also provide some sample text, it will show you the matches.

See https://regex101.com/r/1aDjdT/1

For others who want to test, here is the source text to use:

set filePath to (path to desktop as text) & "Test.txt"
set theText to read file filePath

Or, Nigel, did you have other text in mind?

My own test script was something like this:

set filePath to (path to desktop as text) & "Test.txt"
set _file_path to (path to desktop as text) & "Test.txt"
-- This has to be skipped manually.
set |file path with quotes| to (path to desktop as text) & "\"Test\".txt"

-- The file specifiers here are all correctly matched.
set theText to read file filePath
set theText to (read file filePath)
set theText to (read file _file_path)
set theText to (read file |file path with quotes|)
set theText to (read file "My Disk:Users:me:Desktop:Test.txt")
set theText to (read file "My Disk:Users:me:Desktop:\"Test\".txt")
set theText to (read file ((path to desktop as text) & "Test.txt"))
set theText to (read file ((path to desktop as text) & "\"Test\".txt"))
set theText to (read file ((path to home folder as text) & "Desktop:" & "\"Test\".txt"))
set theText to (read file ((path to home folder as text) & ("Desktop:" & "\"Test\".txt")))
set theText to (read file (((path to home folder as text) & "Desktop:") & ("\"Test\"" & (|the dot| & "txt"))) as «class utf8»)

-- These have to be skipped manually.
-- The file is now ready.
tell application "Finder" to open file "Test.txt" of desktop
1 Like