AppleScript & Adobe アプリケーションで高速リスト処理


script object を使用したリスト処理

AppleScript は、リスト処理がとにかく遅いので有名です。
たとえば、以下のスクリプトは
1〜10,000をループさせて、一つずつ文字列に変換しつつリストに代入してゆくのですが、
とにかく実行してみてください。


サンプルコード1
sample1
use scripting additions
use framework "Foundation"

set eDate to current application's NSDate's timeIntervalSinceReferenceDate()

set a to {}
repeat with i from 1 to 10000
    set end of a to i as string
end repeat

display alert ((((current application's NSDate's timeIntervalSinceReferenceDate()) - eDate) & "秒かかりました") as string)

私のMacBook Pro(os10.14.6/2.2GHz Intel Core i7)では
こうなりました。

いやいや…
こんなのに約1.4秒は遅いでしょ。

ということで、
リストを script object にしてみます。


サンプルコード2
sample2
use scripting additions
use framework "Foundation"

set eDate to current application's NSDate's timeIntervalSinceReferenceDate()

script a
    property contents : {}
end script

set contents of a to {}

repeat with i from 1 to 10000
    set end of contents of a to i as string
end repeat

display alert ((((current application's NSDate's timeIntervalSinceReferenceDate()) - eDate) & "秒かかりました") as string)

結果は、

1/10以下のスピードで処理できます。

単にリストを定義するのではなく、
script objectproperty を使用してリスト定義をすると、
なぜか高速化するのです。

これについては以下のサイトを参考にさせて頂きました。

では早速 Adobe アプリケーションに使ってみよう

こんなに速くなるのなら、と
Illustrator やら、 InDesign やら
大量にリストを使用する script に使ってみます。

以下は、Illustrator ドキュメント上の
全ての text frame をリストに代入しようとしています。


サンプルコード3
sample3
script allText
    property contents : {}
end script

tell application "Adobe Illustrator"
    tell document 1
        set contents of allText to text frames
    end tell
end tell

これを実行すると、

エラーになってしまいます。

というのは、
Adobe Illustrator は、
contents」という property を内部で使っているからです。

なんという意地悪!

じゃ、結局使えないの?

そんなことはないです。


サンプルコード4
sample4
script allText
    property record : {}
end script

tell application "Adobe Illustrator"
    tell document 1
        set record of allText to text frames
    end tell
end tell

contents」を「record」に変えるだけで、
使用できるようになります。

Adobe Indesign も同様に、


サンプルコード5
sample5
script allPageItems
    property record : {}
end script

tell application "Adobe InDesign CC 2019"
    tell document 1
        set record of allPageItems to all page items
    end tell
end tell


なぜ「record」が使えるのか、
私にはよくわかりません。

わかりませんが、
これであなたの作った script も確実に高速化します。

最後に注意点

リストの高速化で、
一点だけ注意して欲しいこと。

それは、script obejct に対して
count」が使えなくなることです。


サンプルコード6
sample6
script allPageItems
    property record : {}
end script

tell application "Adobe InDesign CC 2019"
    tell document 1
        set record of allPageItems to all page items
    end tell
end tell

repeat with i from 1 to count of record of allPageItems
    get item i of record of allPageItems
end repeat


これを実行するとエラーになります。

これの解決策は、
count」を「length」に変えること。


サンプルコード7
sample7
script allPageItems
    property record : {}
end script

tell application "Adobe InDesign CC 2019"
    tell document 1
        set record of allPageItems to all page items
    end tell
end tell

repeat with i from 1 to length of record of allPageItems
    get item i of record of allPageItems
end repeat


よしよし。

では皆様、今後ともよろしくお願いいたします。