配列(リスト)のうち、指定要素が何番目に登場するかを検索するAppleScriptです。
もともと、AppleScriptの配列に該当するリスト(list)は、非常に機能が素朴で、要素数を数える(length、count every item of)ほかはループで順次要素を取り出すとか、指定データが配列中に入っているかのチェックを行うとか(is in)、1番目の要素を取り出して元の配列から削除するといった程度の機能しかありません。「検索」については、データベース(FileMaker Proなど)に処理を依頼してね、というのが当初の立ち位置でした。
ただ、それだとたいした処理が書けないので、自力で配列の全要素をループして照合する、といった力技が全世界的に使われてきました。高速化を考慮しているとか、高度な技術を使っているとか、外部のOSAX(プラグイン形式の命令語拡張書類。macOS 10.14で廃止に)を利用するといっても「高級な力技」の域を出るものではありませんでした。
set aList to {9, 4, 2, 6, 4, 7}
set aTarg to 7
set aCount to 1
repeat with i in aList
set j to contents of i
if j = aTarg then
exit repeat
end if
set aCount to aCount + 1
end repeat
return aCount
★Click Here to Open This Script
macOS 10.6でXcode上記述するAppleScriptでCocoaの機能が利用できるようになり、macOS 10.10で通常のAppleScript上でもCocoaの機能が呼び出せるようになると、AppleScriptからCocoaの機能を利用することが検討されはじめました。
Cocoaの配列であるNSArray、NSMutableArrayは、多次元配列の作成や操作に難を抱えています(正直なところ、2次元配列の操作は補助プログラムを使わないとやりたくないレベル)。多次元配列の作成や操作ならCocoaの機能を使わずにAppleScriptだけで行なったほうが数億倍簡単です。
# その後、多次元配列専用のクラス「MLMultiArray」がCoreML.frameworkに用意されることになりました。AppleScriptからは直接アクセスできないんで、用はないんですが、、、
ただ、これらのCocoaの配列オブジェクトには検索や抽出などの機能があるため、複数キーによる検索程度なら少ない行数で記述することが可能です。さらに、いくつかの前提条件を満たせば、速度的なメリットもあります。
(1)AppleScriptの配列をCocoaの配列に変換するのに若干時間がかかる
まったく世界観が異なる世界の配列を変換するのに、若干時間がかかります。そのため、AppleScriptからCocoaの配列を使う目的が「スピードアップ」だとしたら、それに見合った「巨大なデータ」が処理対象であることが前提条件です。目安としては、AppleScriptの配列のアクセスが遅くなってくる(高速化処理を行えば、そのかぎりではありませんが)4,000項目以上、もう少しいえば10,000項目の配列の処理ぐらいでないと速度向上のメリットを感じにくいところです。
また、Cocoaの配列が持っている条件抽出や正規表現による抽出を使うぐらいでないと、「ただ漫然とループする」ぐらいでは使う価値がありません。
(2)Cocoaの配列にAppleScriptの世界のアプリケーションのオブジェクトを入れられない
Cocoaの配列には、AppleScript上で普通に扱っている「Photoshopの最前面のドキュメント」とか「iTunesで選択中の音楽トラック」といったオブジェクトを直接入れることはできません。これらのオブジェクトのIDを取り出して、「単なる数値」として扱うのであれば別ですが、これらのアプリケーションのオブジェクトをCocoaの配列に入れることはできません。
(3)AppleScriptの配列(リスト)とCocoaの配列(NSArray/NSMutableArray)はアイテムの開始値が違う
普通、配列といえば0番目の要素から始まりますが、AppleScriptでは1番目から始まります。そのため、Cocoaの配列の機能を利用するときには、これらの仕様の違いを念頭におく必要があります。
ここで紹介するのは、Cocoaの配列を作ってCocoaの配列の機能を利用して指定要素の登場位置を求めるものです。さらに、Cocoaのバグ(OSのバグ)に対処するために若干の処理を追加してあります。macOS 10.12〜10.13の間、定数「NSNotFound」の定義が間違ったまま出荷されていました。その値がAppleScriptで扱える範囲を超える巨大な定義値だったために、そのバグの影響を受けました。
過去の情報を調べてみたところ、AppleがNSNotFoundの定義値を間違えてOSを出荷するというのはこれが初めてのことではありません(2度目か3度目)。そんな基礎的かつ重要な値の定義を間違えるなんて●●としか思えないのですが、そういうことのようです。
AppleがNSNotFoundの定義値を今後も間違える可能性があるため、本来シンプルで済むはずの記述でもこの程度の対処が必要となります。
AppleScript名:AppleScript名:配列の指定要素を検索する(テキスト) |
— Created 2015-09-02 by Takaaki Naganoya — 2015 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set aList to {"AAAAAAAAAAAAAAAAAAA", "BBBBBBBBBBBBBBBBBBBBB", "CCCCCCCCCCCCCCCCCCCCCCCC"} set anArray to current application’s NSArray’s arrayWithArray:aList –> (NSArray) {"AAAAAAAAAAAAAAAAAAA", "BBBBBBBBBBBBBBBBBBBBB", "CCCCCCCCCCCCCCCCCCCCCCCC"} –指定要素を検索する set aInd to anArray’s indexOfObject:"CCCCCCCCCCCCCCCCCCCCCCCC" if (aInd = current application’s NSNotFound) or (aInd > 9.999999999E+9) then return false else return aInd –> 2 end if |