How do I get the elements of NSArray

I made the following call to get an array of ranges of a matching regex :

set theText to current application's class "NSString"'s stringWithString:html
	set regexPattern to "url\\([" & (ASCII character 34) & ",'](https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\\/\\w\\.-]*)*\\/?"
	set urlRegex to current application's class "NSRegularExpression"'s regularExpressionWithPattern:(regexPattern) options:(0) |error|:(missing value)
	set matchRanges to (urlRegex's matchesInString:(theText) options:(0) range:({0, theText's |length|()}))'s valueForKey:("range")

I get the following result :

(NSArray) {(NSConcreteValue) NSRange: {11780, 52}, (NSConcreteValue) NSRange: {13066, 52}, (NSConcreteValue) NSRange: {15247, 40}, (NSConcreteValue) NSRange: {16288, 39}, (NSConcreteValue) NSRange: {17788, 36}, (NSConcreteValue) NSRange: {18596, 36}, (NSConcreteValue) NSRange: {19806, 75}, (NSConcreteValue) NSRange: {20807, 49}, (NSConcreteValue) NSRange: {21287, 63}, (NSConcreteValue) NSRange: {23892, 46}, (NSConcreteValue) NSRange: {24715, 35}, (NSConcreteValue) NSRange: {25182, 63}, (NSConcreteValue) NSRange: {25667, 44}, (NSConcreteValue) NSRange: {26011, 28}, (NSConcreteValue) NSRange: {26394, 66}, (NSConcreteValue) NSRange: {26769, 72}, (NSConcreteValue) NSRange: {28682, 66}, (NSConcreteValue) NSRange: {29576, 66}, (NSConcreteValue) NSRange: {31236, 32}}

The list of items is a NSArray which means I can’t do :

repeat with range in matchRanges
		set element to range
		set pos to item 1 of element
		set len to item 2 of element
	end repeat

How do I get the position and length attributes of each NSRange ? I have looked for AppleScript documentation on Apple Developer but can only find documents related to the scripting bridge. Thanks, Regards

Answered by DTS Engineer in 910629022

If you have an NSArray, you have to use NSArray methods to access the elements. For example:

use framework "Foundation"

set s to current application's NSString's stringWithString:"Hello Cruel World!"
set a to s's componentsSeparatedByString:" "
(a's objectAtIndex:1) as string
-- -> Cruel

Here I’m using the -objectAtIndex: method.

I have looked for AppleScript documentation on Apple Developer but can only find documents related to the scripting bridge.

Most of the AppleScript documentation is in the Documentation Archive )-:

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

If you have an NSArray, you have to use NSArray methods to access the elements. For example:

use framework "Foundation"

set s to current application's NSString's stringWithString:"Hello Cruel World!"
set a to s's componentsSeparatedByString:" "
(a's objectAtIndex:1) as string
-- -> Cruel

Here I’m using the -objectAtIndex: method.

I have looked for AppleScript documentation on Apple Developer but can only find documents related to the scripting bridge.

Most of the AppleScript documentation is in the Documentation Archive )-:

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I used your suggestion and can now iterate the NSArray. But the NSArray contains items of NSRange.
I don't know how to access each item's properties. I currently have this code

	set matchRanges to (urlRegex's matchesInString:(theText) options:(0) range:({0, theText's |length|()}))'s valueForKey:("range")
	set matchRangesCount to count of matchRanges
	
	repeat with idx from 1 to matchRangesCount
		set element to (matchRanges's objectAtIndex:idx)
		set position to element's location
		set theSize to element's length
	end repeat

But the element's location and element's length properties cannot be accessed this way.
What is the proper way to access the structs members ?
Thanks,
Regards

Accepted Answer

The issue here is that -matchesInString:… returns an array of NSTextCheckingResult objects and you’re getting the range property from that array as a whole, using -valueForKey:, rather than from each element of the array. When you do that, the NSRange struct gets boxed inside an NSValue, and hence the confusion.

I recommend that you iterate over the NSTextCheckingResult objects themselves. You can then fetch the range property and convert that to a record:

use framework "Foundation"

set s to current application's NSString's stringWithString:"Hello Cruel World!"
set re to current application's NSRegularExpression's alloc's initWithPattern:" " options:0 |error|:(missing value)
set matches to re's matchesInString:s options:0 range:{0, s's |length|}
set matchCount to count of matches -- -> 2
set match to matches's objectAtIndex:1
set rv to match's range
rv's rangeValue as record -- -> {location:11, |length|:1}

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for your help. Anyway I just found the documentation to the automation and scripting docs at the top of the respective forum's webpage.