Setting A Position Property From A String

Hi all, first-time poster, long-time reader…

I’m having an issue figuring out how to set a position property from a text string.
I have a plist that I have written the position of a Finder window to. When writing to the plist I converted the position property (that looked something like {900,900}) to a string (which looks something like “{900,900}”) to save it as text to the plist item.

I now want to pull the text from that plist item to use it to change the position of a window. But since it’s a string I have to find a way to convert it to a property??? This the bit that’s confusing me. I understand that it’s not working because the string I’m getting from the plist has quotes around it and I have to somehow find a way to remove the quotes so that the position property sees it as a valid value.

So, I tried many variations for compiling the value for the position so that it doesn’t have quotes but no matter what I do I can’t seem to figure it out.

Example script:


set thePosition to "{900,900}" --this is how it is returned from the plist

tell application "Finder"
set theTarget to ":Users:Shared:" as alias
set newWindow to make new Finder window to theTarget

set position of newWindow to thePosition --this is where it gets hairy because I have a quoted form of a value for a property position. and it shouldn't be quoted. and it's not really a quoted form, it's just text. 

end tell

Thanks for look and I look forward to reading your posts.

JM

Applications that read and store positions in property lists generally use two functions, NSPointFromString() and NSStringFromPoint(). To use them in AppleScript you need a suitable use framework statement, like this:

use AppleScript version "2.5" -- macOS 10.11 or later
use framework "Foundation"
use scripting additions

set thePosition to "{900, 900}"
set thePos to current application's NSPointFromString(thePosition)
--> {x:900.0, y:900.0}

The result is a record, so you can ask for “x of thePos” or “y of thePos”.

And yet another method for your armoury:

set thePosition to "{900,900}" --this is how it is returned from the plist
set thePosition to (run script thePosition)
--> {900, 900}

Nigel,

I deleted my proposal, as you found much better plain AppleScript solution. :slight_smile:

Hi KniazidisR.

You needn’t have. Your solution was somewhat more efficient performancewise. :slight_smile:

set thePosition to "{900,900}" --this is how it is returned from the plist

set o to (offset of "," in thePosition)
set x to (text 2 thru (o - 1) of thePosition) as integer
set y to (text (o + 1) thru -2 of thePosition) as integer
set thePosition to {x, y}
--> {900, 900}

Thanks for all of the support. I ended up using Nigel’s method since it was the easiest but I tested everyone’s to see how they worked. (and they did…)

I’m very interested in Shane’s thought of using foundation “Framework.” I’ve used this once before but on a recommendation and I didn’t understand why I was using but after Shane posting about it I’ve grown a bit more curious about it and did some digging to find that you can use regular expressions (something I’ve been hunting for and can’t believe I never found this). I will definitely do more digging on this front.

Thanks.

FWIW, you can do regular expressions using my RegexAndStuffLib script library, available here:

https://www.macosxautomation.com/applescript/apps/Script_Libs.html

It uses Foundation, but keeps all that side of things out of sight, so you can write stuff like this:

use scripting additions
use script "RegexAndStuffLib" version "1.0.6"

regex change "one two three" search pattern "t(.?)" replace template "t**$1**" --> "one t**w**o t**h**ree"

Here’s another one:

tell application id ("com.apple.Finder")
				tell (make new Finder window to continue ¬
								path to shared documents folder)
								set the position to words of "{900, 900}"
				end tell
				activate
end tell

The key part to highlight is:

words of "{900, 900}"

which works well in this case because the parts of the string you want to extract are clearly word-like, whilst the parts that aren’t needed happen to be non-word characters. It returns a list containing the two words, namely {“900”, “900”}. Despite being a list of strings rather than a list of numbers, AppleScript thankfully has a small amount of intuition about what to do and, somewhere along the lines, turns what it receives into the appropriate data type (which is of a class called point whose superclass is a list, but specifically a list containing precisely two numerical values). Explicitly:

return {"900","900"} as point --> {900, 900}

Technically it’s not actually a subclass of list, but a type of its own (historically based on a QuickDraw point), although it usually gets converted to a list. But it has some limitations lists don’t have: integers only, and a limited range of values.


Thank you.

An alternative which demonstrates the potential speed advantage of text item delimiters:

set thePosition to "{900,900}"
set text item delimiters to {"{", ",", "}"}
set thePosition to {text item 2 of thePosition as integer, text item 3 of thePosition as integer}
set text item delimiters to ""
thePosition --> {900, 900}

Script Geek timings of the scripts in this thread:

Shane: 0.9 millisecond
Nigel: 1.3 millisecond
KniazidisR: 1.3 millisecond
Peavine: 0.3 millisecond

Unfortunately, the method suggested by the CK (words of …) does not work for text without a space (like the OP has). Otherwise, it would be more efficient than the Peavine script.

But here’s another script that is at least 2.5 times faster than the Peavine script:


set thePosition to "{900,900}"
set text item delimiters to {"{", ",", "}"}
tell thePosition to set thePosition to {text item 2, text item 3}
set text item delimiters to "" -- optional 
thePosition as point -- coercion at once --> {900, 900}