Menu

Skip to content
AppleScriptの穴
  • Home
  • Products
  • Books
  • Docs
  • Events
  • Forum
  • About This Blog
  • License
  • 仕事依頼

AppleScriptの穴

Useful & Practical AppleScript archive. Click '★Click Here to Open This Script' Link to download each AppleScript

カテゴリー: list

NSSpeechSynthesizerとAVSpeechSynthesisVoiceで返ってくるTTS Voice IDの違いを計算する

Posted on 10月 11, 2024 by Takaaki Naganoya

macOS 15上でNSSpeechSynthesizerとAVSpeechSynthesisVoiceで返ってくるTTS Voice IDの数が違う、

NSSpeechSynthesizer :205
AVSpeechSynthesisVoice:222

ことが気になりました。NSSpeechSynthesizerについては、あまり真面目にメンテナンスされていないからAVSpeechSynthesisVoiceを使えといった声も聞こえてきますが、具体的にどのあたりに「差」があるのかが気になります。

そこで、実際にAppleScriptで差分を計算して確認してみました。

–>{addItems:{“com.apple.ttsbundle.siri_Nicky_en-US_premium”, “com.apple.ttsbundle.siri_Hattori_ja-JP_premium”, “com.apple.ttsbundle.siri_Helena_de-DE_compact”, “com.apple.ttsbundle.siri_Yu-Shu_zh-CN_compact”, “com.apple.ttsbundle.siri_Gordon_en-AU_compact”, “com.apple.ttsbundle.siri_Martha_en-GB_compact”, “com.apple.ttsbundle.siri_O-Ren_ja-JP_premium”, “com.apple.ttsbundle.siri_Hattori_ja-JP_compact”, “com.apple.ttsbundle.siri_Nicky_en-US_compact”, “com.apple.ttsbundle.siri_Martin_de-DE_compact”, “com.apple.ttsbundle.siri_Li-Mu_zh-CN_compact”, “com.apple.ttsbundle.siri_Dan_fr-FR_compact”, “com.apple.ttsbundle.siri_Aaron_en-US_compact”, “com.apple.ttsbundle.siri_Catherine_en-AU_compact”, “com.apple.ttsbundle.siri_Marie_fr-FR_compact”, “com.apple.ttsbundle.siri_O-Ren_ja-JP_compact”, “com.apple.ttsbundle.siri_Arthur_en-GB_compact”}, minusItems:{}}

17個のTTS Voice IDが追加されたことを確認できました。AVSpeechSynthesisVoice側で検出されていないTTS Voiceはないことも確認。

TTS Voice IDの個人的な理解は上記の表のとおりです。NSSpeechSynthesizerで検出できなかったのは、「com.apple.ttsbundle」ではじまるSiri系の(おそらく他のメーカーからのOEM)Voice Character 17個です。

AppleScript名:NSSpeechSynthesizerとAVSpeechSynthesisVoiceで返ってくるTTS Voice IDの違いを計算する
— Created 2024-10-11 by Takaaki Naganoya
— 2019-2024 Piyomaru Software
use AppleScript version "2.8"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "AVFoundation"

set aList to current application’s NSSpeechSynthesizer’s availableVoices() as list
set bList to (current application’s AVSpeechSynthesisVoice’s speechVoices()’s valueForKey:"identifier") as list
set a1Res to checkAllItemsAreSame(aList, bList) of me
–>{addItems:{"com.apple.ttsbundle.siri_Nicky_en-US_premium", "com.apple.ttsbundle.siri_Hattori_ja-JP_premium", "com.apple.ttsbundle.siri_Helena_de-DE_compact", "com.apple.ttsbundle.siri_Yu-Shu_zh-CN_compact", "com.apple.ttsbundle.siri_Gordon_en-AU_compact", "com.apple.ttsbundle.siri_Martha_en-GB_compact", "com.apple.ttsbundle.siri_O-Ren_ja-JP_premium", "com.apple.ttsbundle.siri_Hattori_ja-JP_compact", "com.apple.ttsbundle.siri_Nicky_en-US_compact", "com.apple.ttsbundle.siri_Martin_de-DE_compact", "com.apple.ttsbundle.siri_Li-Mu_zh-CN_compact", "com.apple.ttsbundle.siri_Dan_fr-FR_compact", "com.apple.ttsbundle.siri_Aaron_en-US_compact", "com.apple.ttsbundle.siri_Catherine_en-AU_compact", "com.apple.ttsbundle.siri_Marie_fr-FR_compact", "com.apple.ttsbundle.siri_O-Ren_ja-JP_compact", "com.apple.ttsbundle.siri_Arthur_en-GB_compact"}, minusItems:{}}

–1D List同士の全要素が(登場順序が変更になっていても)同じかどうかをチェック
on checkAllItemsAreSame(aList, bList)
  set dRes to getDiffBetweenLists(aList, bList) of me
  
set ddRes to (dRes is equal to {addItems:{}, minusItems:{}}) as boolean
  
if ddRes = true then
    return true
  else
    return dRes
  end if
end checkAllItemsAreSame

–1D List同士のdiffを検出
on getDiffBetweenLists(aArray as list, bArray as list)
  set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分を削除する
  
allSet’s minusSet:duplicateSet
  
set resArray to (allSet’s allObjects()) as list
  
  
set aSet to current application’s NSMutableSet’s setWithArray:aArray
  
set bSet to current application’s NSMutableSet’s setWithArray:resArray
  
aSet’s intersectSet:bSet –積集合
  
set addRes to aSet’s allObjects() as list
  
  
set cSet to current application’s NSMutableSet’s setWithArray:bArray
  
cSet’s intersectSet:bSet –積集合
  
set minusRes to cSet’s allObjects() as list
  
  
return {addItems:minusRes, minusItems:addRes}
end getDiffBetweenLists

★Click Here to Open This Script 

Posted in list Text to Speech | Tagged 15.0savvy | Leave a comment

Keynote上で選択中のテキストアイテムを、位置情報をもとにテキスト連結してクリップボードへ

Posted on 5月 13, 2024 by Takaaki Naganoya

Keynoteで作業がめんどくさくなったら、その場でAppleScriptを書いて使うシリーズ。Keynote v14で動かしていますが、別にバージョン依存している箇所はありません。もっと古いKeynoteでも動くと思います(KeynoteのAppleScript対応機能的には、slideのselectionができるようになったv12が実用下限だと思っています)。

Keynote書類の、章トビラに内容を個別のテキストアイテムで箇条書きしていたような場合に、

これを、全部結合して1つのテキストアイテムに入れたくなる時があります。

そこで、本ScriptのようなものをmacOS標準搭載のスクリプトメニューに入れて、

呼び出すために作ったものです。

実行すると、それぞれのテキストアイテムをY座標に着目してソートを行い、上→下の順番にならべかえて、テキストを取り出し、改行をはさみつつ連結します。

この後で、もとのテキストアイテムにこの連結したテキストを入れることになります。

一番上(positionのY座標が一番小さい)のテキストアイテムだけ残してあとは削除するわけですが、このあたりのオブジェクト操作もAppleScriptから操作してしまったほうがよさそうです。

ただし、Keynoteはテキストアイテム内の文字の上寄せ/下寄せの制御をAppleScriptからできないので(キーボードショートかメニューでも操作する?)そのあたりに「残念感」が残ってしまうかもしれません。

macOS標準搭載のスクリプトメニューに入れるAppleScriptで、絵文字を大量に入れるのは、大量のAppleScriptをメニューに入れるため文字だけだと視認性が低く、色付き文字を入れてそれぞれを識別しやすくするためです。

AppleScript名:🧭位置情報🧭をもとに🈴テキスト連結🈴して📎📎クリップボードへ📎📎.scpt
use AppleScript
use scripting additions
use framework "Foundation"

set outList to {}
set outStr to ""

tell application "Keynote"
  tell front document
    set aSel to selection
    
    
if length of aSel = 0 then
      display dialog "Keynote書類上で何も選択されていません。" with title "オブジェクト選択エラー" buttons {"OK"} default button 1 with icon 2
      
return
    else if length of aSel = 1 then
      display dialog "Keynote書類上で複数のオブジェクトが選択されていません。" with title "オブジェクト選択エラー" buttons {"OK"} default button 1 with icon 2
      
return
    else if (class of first item of aSel = slide) then
      display dialog "Keynote書類上でスライドが選択されてしまっています。" with title "オブジェクト選択エラー" buttons {"OK"} default button 1 with icon 2
      
return
    end if
    
    
repeat with i in aSel
      set j to contents of i
      
set aClass to class of j
      
if aClass = text item then
        set {aPosX, aPosY} to position of j
        
set aCon to object text of j
        
set the end of outList to {xPos:aPosX, yPos:aPosY, textCon:aCon}
      end if
    end repeat
    
  end tell
end tell

set bList to sortListAscending(outList, "yPos") of me

repeat with i in bList
  set j to contents of i
  
set aText to textCon of j
  
set outStr to outStr & aText & return
end repeat

set the clipboard to outStr
beep 1

–入れ子のリストを昇順ソート(AppleScriptObjC)
on sortListAscending(theList as list, keyLabel)
  set anArray to current application’s NSMutableArray’s arrayWithArray:(theList)
  
set theDescriptor to current application’s NSSortDescriptor’s sortDescriptorWithKey:(keyLabel) ascending:(true)
  
set sortedList to anArray’s sortedArrayUsingDescriptors:{theDescriptor}
  
return sortedList as list
end sortListAscending

★Click Here to Open This Script 

Posted in list Object control Record Sort | Tagged 12.0savvy 13.0savvy 14.0savvy Keynote | Leave a comment

NaturalLanguage frameworkを使って類語語展開+意味的な距離を計測してソート

Posted on 3月 13, 2024 by Takaaki Naganoya

NaturalLanguage frameworkといえば、macOS 10.14で追加されたものですが、自然言語テキストが「何語」であるかを推測するなどの使い方をAppleScriptから行なってきました。正直、その程度しか「役に立つ機能がない」という認識でした。

日本語のサポートはまだまだですが、日本語でなければ意外と使えることがわかりました。

試しに、NaturalLanguage.frameworkの機能を用いて指定の英単語の類義語を生成して、それぞれの元の単語との意味的な距離を計算してみました。

自然言語処理的にわかりやすい言葉でいえば、類語語のリストをword2vecでベクトル化してコサイン距離を計算する、というところでしょうか。

類義語展開であれば、日本語WordNetを利用して検索するAppleScriptを4年ぐらい前に試作ずみなので、このOS側の類義語展開機能がなくても別に構わないのですが、word2vecやsentence2vecで単語や文章をベクトル化して意味的な距離を計測する演算については、利用したいところです。

ただ、OSの機能が向上するどころか退化しているようなので、この分野ではmacOSの進歩は期待できないのかもしれません。

AppleScript名:指定単語の類義語を展開して元の単語との距離を測る.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/03/12
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "NaturalLanguage"
use scripting additions

set targLang to current application’s NLLanguageEnglish
set aEmb to current application’s NLEmbedding’s wordEmbeddingForLanguage:(targLang)
if aEmb = missing value then return –NLLanguageJapanese is not available here in macOS 13

–類義語展開(Max.50)
set aWord to "computer"
set aSym to (aEmb’s neighborsForString:aWord maximumCount:20 distanceType:(current application’s NLDistanceTypeCosine)) as list

–コサイン距離を計測(0.0〜2.0)数字が小さいと近いはず。ちょっとでも意味が遠いと2.0になるという悪癖を持つ
set distList to {}
repeat with i in aSym
  set j to contents of i
  
set aDist to (aEmb’s distanceBetweenString:aWord andString:j distanceType:(current application’s NLDistanceTypeCosine))
  
set the end of distList to {wordName:j, wordDistance:aDist as real}
end repeat

–昇順ソート
set bList to sortRecListByLabel(distList, "wordDistance", true) of me
–> {{wordDistance:0.837697923183, wordName:"workstation"}, {wordDistance:0.875068962574, wordName:"mainframe"}, {wordDistance:0.886509418488, wordName:"laptop"}, {wordDistance:0.901307225227, wordName:"software"}, {wordDistance:0.901674091816, wordName:"computing"}, {wordDistance:0.904342055321, wordName:"palmtop"}, {wordDistance:0.951638877392, wordName:"desktop"}, {wordDistance:0.954249441624, wordName:"intranet"}, {wordDistance:0.958346903324, wordName:"keystroke"}, {wordDistance:0.961381614208, wordName:"notebook"}, {wordDistance:0.964299142361, wordName:"server"}, {wordDistance:0.970234155655, wordName:"hardware"}, {wordDistance:0.974493980408, wordName:"pager"}, {wordDistance:0.981385648251, wordName:"electronic"}, {wordDistance:0.984282553196, wordName:"peripheral"}, {wordDistance:0.993325233459, wordName:"machine"}, {wordDistance:0.996084809303, wordName:"diskette"}, {wordDistance:0.999181330204, wordName:"portable"}, {wordDistance:1.001676082611, wordName:"compatible"}, {wordDistance:1.00532245636, wordName:"programmer"}}

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList as list, aLabelStr as string, ascendF as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set sortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF
  
set sortedArray to aArray’s sortedArrayUsingDescriptors:{sortDesc}
  
set bList to (sortedArray) as anything
  
return bList
end sortRecListByLabel

★Click Here to Open This Script 

本当は単語ではなく「文章」の距離を計測できないと実用性が低いところです。word2vecではなくsentence2vecの演算を行いたいところ。

自作のAppleScriptによるアイデアプロセッサ「Kamenoko」も、当初から自然言語処理の機能を盛り込むことを企画していました。sentence2vecぐらいの演算を行なって、各ノードに書いてある文章同士の距離を計測して、距離に応じて色を変えるといった機能も検討していました。

ただ、そうした機能を実装するのに割とデータ量が多くなるとか、アプリとしてパッケージングするのに無理があるとか、もういっそWebサーバー側で処理したほうがいいんじゃないの? 的な話になって見送った経緯があります。

このNaturalLanguage.frameworkがもっと使えるように、なったらいいのに。簡体字の中国語に対応しているぐらいなので、日本語への対応も期待したいところですが……macOS 14では対応言語が英語だけになるなど、展開の仕方が謎であります。

Posted in list Natural Language Processing Record | Tagged 13.0savvy 14.0savvy | Leave a comment

CotEditorで2つの書類の行単位での差分検出

Posted on 3月 12, 2024 by Takaaki Naganoya

CotEditorで2つの書類をオープンしておき、行単位での差分を検出し、新規書類に結果を出力するAppleScriptです。

もともと、macOS搭載のFramework名一覧の差分を検出する資料を作成する必要があり、これを片付けるために作成しました。

本AppleScriptを実行すると……

のように、結果を出力します。それほど巨大なデータを想定して作ってはいないので、ほどほどの規模に抑えて利用してください。

AppleScript名:左右のドキュメントを比較.scpt
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

script spd
  property aList : {}
  
property bList : {}
end script

set (aList of spd) to {}
set (bList of spd) to {}

tell application "CotEditor"
  set dCount to count every document
  
if dCount is not equal to 2 then
    display notification "Error: This script needs only 2 documents"
    
return –Document number Error
  end if
  
  
tell window 1
    set w1Bounds to bounds
    
copy w1Bounds to {w1X1, w1Y1, w1X2, w1Y2}
    
set w1Doc to document of it
  end tell
  
  
tell window 2
    set w2Bounds to bounds
    
copy w2Bounds to {w2X1, w2Y1, w2X2, w2Y2}
    
set w2Doc to document of it
  end tell
  
  
if w1X1 > w2X1 then
    set {w1, w2} to {2, 1}
  else
    set {w1, w2} to {1, 2}
  end if
  
  
tell document w1 –左ウィンドウ
    set (aList of spd) to paragraphs of contents
  end tell
  
  
tell document w2 –右ウィンドウ
    set (bList of spd) to paragraphs of contents
  end tell
  
end tell

–ゴミ掃除
set (aList of spd) to cleanUp1DList((aList of spd), {"
"
}) of me

set (bList of spd) to cleanUp1DList((bList of spd), {"
"
}) of me

–差分計算
set (cList of spd) to getDiffBetweenLists((aList of spd), (bList of spd)) of me

–結果出力テキスト組み立て
set aRes to listToTextUsingDelim(addItems of (cList of spd), "")
set bRes to listToTextUsingDelim(minusItems of (cList of spd), "")

–結果の新規書類への出力
set d3 to makeNewCotEditorDoc("左→右で追加された項目" & return & return & aRes) of me
set d4 to makeNewCotEditorDoc("左→右で削除された項目" & return & return & bRes) of me

on getDiffBetweenLists(aArray as list, bArray as list)
  set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分を削除する
  
allSet’s minusSet:duplicateSet
  
set resArray to (allSet’s allObjects()) as list
  
  
set aSet to current application’s NSMutableSet’s setWithArray:aArray
  
set bSet to current application’s NSMutableSet’s setWithArray:resArray
  
aSet’s intersectSet:bSet –積集合
  
set addRes to aSet’s allObjects() as list
  
  
set cSet to current application’s NSMutableSet’s setWithArray:bArray
  
cSet’s intersectSet:bSet –積集合
  
set minusRes to cSet’s allObjects() as list
  
  
return {addItems:minusRes, minusItems:addRes}
end getDiffBetweenLists

on cleanUp1DList(aList as list, cleanUpItems as list)
  set bList to {}
  
repeat with i in aList
    set j to contents of i
    
if j is not in cleanUpItems then
      set the end of bList to j
    end if
  end repeat
  
return bList
end cleanUp1DList

–デリミタ文字を指定してリストを文字列化
on listToTextUsingDelim(aList, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set outText to every text item of aList
  
set outText to outText as string
  
set AppleScript’s text item delimiters to curDelim
  
return outText
end listToTextUsingDelim

–指定テキストでCotEditorの新規書類を作成
on makeNewCotEditorDoc(aCon)
  tell application "CotEditor"
    activate
    
set newDoc to make new document
    
tell newDoc
      set contents to aCon
    end tell
  end tell
end makeNewCotEditorDoc

★Click Here to Open This Script 

Posted in diff list Text | Tagged 13.0savvy 14.0savvy CotEditor | Leave a comment

与えられた文字列の1D Listのすべての順列組み合わせパターン文字列を返す v3(ベンチマーク用)

Posted on 2月 18, 2024 by Takaaki Naganoya

Macの処理速度を測るのにちょうど手頃な内容のプログラムです。与えた配列要素の、順列組み合わせ計算を行います。

M2 MacBook Air@macOS 15.1の環境の実行結果は、

–> {{4, 0.004417896271}, {5, 0.009887933731}, {6, 0.063844919205}, {7, 0.450636982918}, {8, 3.521628022194}, {9, 31.777850985527}}

なので、ほとんどM1 Mac miniと変わりません(少し遅いぐらい)。

AppleScript名:与えられた文字列の1D Listのすべての順列組み合わせパターン文字列を返す v3_for benchmark.scptd
— 2014-10-06 Original By Nigel Garvey@macscripter.net
— 2019-06-19 Modified By Takaaki Naganoya
— 2024-02-18 Modified By Takaaki Naganoya
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

script spdPerm
  property permutations : missing value
  
property allRes : {}
end script

on run
  set allList to {{"A", "T", "G", "C"}, {"A", "T", "G", "C", "1"}, {"A", "T", "G", "C", "1", "2"}, {"A", "T", "G", "C", "1", "2", "3"}, {"A", "T", "G", "C", "1", "2", "3", "4"}, {"A", "T", "G", "C", "1", "2", "3", "4", "5"}}
  
  
repeat with i in allList
    set theList to contents of i
    
    
set a1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()
    
set aRes to permute(theList) of me
    
set b1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()
    
set c1Dat to (b1Dat – a1Dat)
    
set the end of (allRes of spdPerm) to {length of theList, c1Dat}
    
  end repeat
  
  
return (allRes of spdPerm)
  
— MacBook Pro 2012 Retina Core i7 2.6GHz@macOS 10.14.6 の実行結果
  
–> {{4, 0.01 }, {5, 0.010347008705}, {6, 0.05}, {7, 1.44}, {8, 11.54}, {9, 107.271}}
  
  
–M1 Mac mini@macOS 13.6.5 の実行結果
  
–> {{4, 0.005248069763}, {5, 0.01240503788}, {6, 0.063866019249}, {7, 0.434872984886}, {8, 3.519423961639}, {9, 31.62052500248}}
end run

on permute(theList as list)
  set theArray to current application’s NSMutableArray’s arrayWithArray:theList
  
set (permutations of spdPerm) to current application’s NSMutableArray’s array()
  
prmt(theArray, 0, (count theList) – 1)
  
  
–Return AppleScript string list
  
set aFinishArray to current application’s NSMutableArray’s new()
  
set anEnum to (permutations of spdPerm)’s objectEnumerator()
  
repeat
    set aValue to anEnum’s nextObject()
    
if aValue = missing value then exit repeat
    
set aStr to aValue’s componentsJoinedByString:""
    (
aFinishArray’s addObject:aStr)
  end repeat
  
  
return aFinishArray as list
end permute

on prmt(theArray, theStart as number, theEnd as number)
  if (theStart = theEnd) then
    (permutations of spdPerm)’s addObject:theArray
  else
    repeat with x from theStart to theEnd
      set theCopy to theArray’s mutableCopy()
      
–swap
      
if (x > theStart) then (theCopy’s exchangeObjectAtIndex:theStart withObjectAtIndex:x)
      
prmt(theCopy, theStart + 1, theEnd)
    end repeat
  end if
end prmt

★Click Here to Open This Script 

Posted in list | Tagged 13.0savvy 14.0savvy | Leave a comment

可変次元のベクトルに対応したコサイン類似度計算

Posted on 11月 23, 2023 by Takaaki Naganoya

ChatGPTに書かせたAppleScriptを微修正したものです。ベクトルの内積、外積の計算を経てコサイン類似度計算のAppleScriptを書かせました。

もともとは、ChatGPTのAPIを利用して自然言語テキストをベクトル化し、それらの類似度を計算させるための準備で用意しました。自分が試したときには、ChatGPTのREST APIは1536次元のベクトルを返してきました。残念ながら、いま試してみると(全然REST API呼び出しをしていないのに)Quota Exceedのエラーが出てしまって目的の処理はできませんでした。

このあたり、実際にChatGPTのコンソールから利用履歴を確認してみても、全然呼び出していないことが確認できたので、自分の記憶違いではありません。

もともと、日本語テキストを複数の機械翻訳APIを利用して英訳し、再度日本語訳したのちに文章をベクトル化。これらの複数の機械翻訳APIの結果を比較して、もともとの日本語の文章と類似度が高いものを「正確に英訳された文章」として採用してみるといいんじゃないかと思っていました。翻訳文の質を疑似的に評価してみようと思ったわけです。

ChatGPTに出力させたAppleScriptは、「間違ってはいないんだけど、正しくないし、微妙にムカつく(resultを使って計算したりする)」内容で、よくわかっている人間にとっては簡単に修正できるものですが、基礎がわかっていないとどこが間違っているか指摘しにくいし、そもそも間違っているかどうかも指摘しにくいので……より正確な知識が要求されます。

AppleScript名:可変次元のベクトルに対応したコサイン類似度計算.scpt
— ベクトルの例
set vectorA to {1, 2, 3, 4}
set vectorB to {4, 5, 6, 7}

— コサイン類似度を計算
set similarityResult to cosineSimilarity(vectorA, vectorB)

— 結果を表示
return similarityResult
–> 0.975900072949

— ベクトルのノルムを計算する関数
on vectorNorm(aVec)
  set sumSquares to 0
  
repeat with i from 1 to (count of aVec)
    set sumSquares to sumSquares + (item i of aVec) ^ 2
  end repeat
  
return (sumSquares) ^ 0.5
end vectorNorm

— ベクトルのコサイン類似度を計算する関数
on cosineSimilarity(vector1, vector2)
  set dimension1 to count of vector1
  
set dimension2 to count of vector2
  
  
if dimension1 = dimension2 then
    set dotProductResult to dotProduct(vector1, vector2)
    
set norm1 to vectorNorm(vector1)
    
set norm2 to vectorNorm(vector2)
    
set similarity to dotProductResult / (norm1 * norm2)
    
return similarity
  else
    error "ベクトルの次元数が一致していません。"
  end if
end cosineSimilarity

— ベクトルの内積を計算する関数
on dotProduct(vector1, vector2)
  set dimension1 to count of vector1
  
set dimension2 to count of vector2
  
  
if dimension1 = dimension2 then
    set sRes to 0
    
repeat with i from 1 to dimension1
      set sRes to sRes + ((item i of vector1) * (item i of vector2))
    end repeat
    
return sRes
  else
    error "ベクトルの次元数が一致していません。"
  end if
end dotProduct

★Click Here to Open This Script 

Posted in list Natural Language Processing | Tagged 13.0savvy 14.0savvy | Leave a comment

macOS 13でNSNotFoundバグふたたび

Posted on 12月 1, 2022 by Takaaki Naganoya

また、Appleがやらかしてくれたようです。あの会社はNSNotFoundの定義値を何回間違えたら気が済むんでしょうか。これで通算4回目ぐらいです。macOS 10.12で発生し10.13.1で修正された定義値のミスをまたやったわけで、失敗がまったく生かされていない。大したものです。

今回のバグは、文字列の検索処理を行っているときに発見しました。指定文字列から対象文字列の登場位置と長さをリストで返す処理を行っていたところ、NSRangeからlocationを取得したときに、これ以上見つからない場所まで来たときにNSNotFoundを返すことを期待されるわけですが、そこに前回(macOS 10.12…10.13)と同様のおかしな値を返してきました。

この(↓)AppleScriptをmacOS 13上で実行すると、エラーになります。

追記:macOS 13.1でもエラーになります。

AppleScript名:テキストのキーワード検索(結果をNSRangeのlistで返す).scptd
— Created 2017-08-09 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4771

property NSString : a reference to current application’s NSString
property NSMutableArray : a reference to current application’s NSMutableArray
property NSLiteralSearch : a reference to current application’s NSLiteralSearch

set aStr to "ATGC ACGT ATGC AGTC
ATGC ACGT ATGC AGTC
ATGC ACGT ATGC AGTC
ATGC ACGT ATGC AGTC
"

set aRes to searchWordRanges(aStr, "ATGC") of me as list
–>  {​​​​​{​​​​​​​location:0, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:10, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:20, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:30, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:40, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:50, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:60, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:70, ​​​​​​​length:4​​​​​}​​​}

on searchWordRanges(aTargText as string, aSearchStr as string)
  set aStr to NSString’s stringWithString:aTargText
  
set bStr to NSString’s stringWithString:aSearchStr
  
  
set hitArray to NSMutableArray’s alloc()’s init()
  
set cNum to (aStr’s |length|()) as integer
  
  
set aRange to current application’s NSMakeRange(0, cNum)
  
  
repeat
    set detectedRange to aStr’s rangeOfString:bStr options:(NSLiteralSearch) range:aRange
    
set aLoc to detectedRange’s location
    
log aLoc
    
if (detectedRange’s location) is equal to (current application’s NSNotFound) then exit repeat
    
    
hitArray’s addObject:detectedRange
    
    
set aNum to (detectedRange’s location) as number
    
set bNum to (detectedRange’s |length|) as number
    
    
set aRange to current application’s NSMakeRange(aNum + bNum, cNum – (aNum + bNum))
  end repeat
  
  
return hitArray
end searchWordRanges

★Click Here to Open This Script 

症状も前回とまったく同じなので、対処も前回と同じです。Appleは定期的にNSNotFoundの定義値を間違えるトンでもない会社なので(計測された事実)、NSNotFoundまわりはAppleがバグをやらかすことを前提に書いておくべきなんでしょう。

AppleScript名:テキストのキーワード検索(結果をNSRangeのlistで返す)v2.scptd
— Created 2017-08-09 by Takaaki Naganoya
— Modified 2022-12-01 by Takaaki Naganoya
— 2022 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property NSString : a reference to current application’s NSString
property NSMutableArray : a reference to current application’s NSMutableArray
property NSLiteralSearch : a reference to current application’s NSLiteralSearch

set aStr to "ATGC ACGT ATGC AGTC
ATGC ACGT ATGC AGTC
ATGC ACGT ATGC AGTC
ATGC ACGT ATGC AGTC
"

set aRes to searchWordRanges(aStr, "ATGC") of me as list
–>  {​​​​​{​​​​​​​location:0, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:10, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:20, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:30, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:40, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:50, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:60, ​​​​​​​length:4​​​​​}, ​​​​​{​​​​​​​location:70, ​​​​​​​length:4​​​​​}​​​}
–> {{location:0, |length|:4}, {location:10, |length|:4}, {location:20, |length|:4}, {location:30, |length|:4}, {location:40, |length|:4}, {location:50, |length|:4}, {location:60, |length|:4}, {location:70, |length|:4}}

on searchWordRanges(aTargText as string, aSearchStr as string)
  set aStr to NSString’s stringWithString:aTargText
  
set bStr to NSString’s stringWithString:aSearchStr
  
  
set hitArray to NSMutableArray’s alloc()’s init()
  
set cNum to (aStr’s |length|()) as integer
  
  
set aRange to current application’s NSMakeRange(0, cNum)
  
  
repeat
    set detectedRange to aStr’s rangeOfString:bStr options:(NSLiteralSearch) range:aRange
    
set aLoc to detectedRange’s location
    
    
–macOS 13でAppleが新たに作ったバグを回避
    
if (aLoc > 9.999999999E+9) or (aLoc = current application’s NSNotFound) then exit repeat
    
    
hitArray’s addObject:detectedRange
    
    
set aNum to (detectedRange’s location) as number
    
set bNum to (detectedRange’s |length|) as number
    
    
set aRange to current application’s NSMakeRange(aNum + bNum, cNum – (aNum + bNum))
  end repeat
  
  
return hitArray
end searchWordRanges

★Click Here to Open This Script 

Appleと協議した結果、そこは仕様として認識していないという話で、とくに仕様を変えていないという話で平行線をたどってしまいました。

結局、書き方を少々変えることで問題そのものを「なかったこと」にする方向で決着。納得はできませんが、macOS 10.11とか10.12の時代に書いたScriptでもあり、その実行環境は手元に残っていません(macOS 10.13は何台か存在しています。macOS 11のASのCocoa呼び出しバグの検証時に活躍)。

AppleScript名:テキストのキーワード検索(結果をNSRangeのlistで返す)v3.scptd
— Created 2017-08-09 by Takaaki Naganoya
— Modified 2022-08-29 by Takaaki Naganoya
— 2023 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property NSString : a reference to current application’s NSString
property NSLiteralSearch : a reference to current application’s NSLiteralSearch
property NSMutableArray : a reference to current application’s NSMutableArray

set aStr to "ATGC ACGT ATGC AGTC
ATGC ACGT ATGC AGTC
ATGC ACGT ATGC AGTC
ATGC ACGT ATGC AGTC
"

set aRes to searchWordRanges(aStr, "ATGC") of me as list
–> {{location:0, |length|:4}, {location:10, |length|:4}, {location:20, |length|:4}, {location:30, |length|:4}, {location:40, |length|:4}, {location:50, |length|:4}, {location:60, |length|:4}, {location:70, |length|:4}}

on searchWordRanges(aTargText as string, aSearchStr as string)
  set aStr to NSString’s stringWithString:aTargText
  
set bStr to NSString’s stringWithString:aSearchStr
  
  
set hitArray to NSMutableArray’s alloc()’s init()
  
set cNum to (aStr’s |length|()) as integer
  
  
set aRange to current application’s NSMakeRange(0, cNum)
  
  
repeat
    set detectedRange to aStr’s rangeOfString:bStr options:(NSLiteralSearch) range:aRange
    
set aLen to (detectedRange’s |length|) as number
    
    
if aLen = 0 then exit repeat
    
    
hitArray’s addObject:detectedRange
    
    
set aNum to (detectedRange’s location) as number
    
set bNum to (detectedRange’s |length|) as number
    
    
set aRange to current application’s NSMakeRange(aNum + bNum, cNum – (aNum + bNum))
  end repeat
  
  
return hitArray
end searchWordRanges

★Click Here to Open This Script 

Posted in Bug list Text | Tagged 13.0savvy NSLiteralSearch NSMakeRange NSMutableArray NSNotFound NSRange NSString | Leave a comment

Common Elements Libをv1.3aにアップデート

Posted on 7月 12, 2022 by Takaaki Naganoya

対象のキーワードの構成情報を分解して、2つのキーワードの共通要素をリストアップする「マッキー演算」を行うライブラリ「Common Elements Lib」をアップデートしました。

–> Common Elements Libをダウンロード(v1.3a)

マッキー演算とは、「槇原敬之」と「SMAP」の共通項を求め、結果に「世界に一つだけの花」をリストアップする処理です(ほかにも出てきますが)。

–> {“第58回NHK紅白歌合戦”, “木村拓哉”, “東京都”, “ニッポン放送”, “テレビ朝日”, “ミリオンセラー”, “大阪城ホール”, “インターネットアーカイブ”, “社長”, “ミュージックステーション”, “ケンタッキーフライドチキン”, “スポーツニッポン”, “日刊スポーツ”, “第42回NHK紅白歌合戦”, “リクルートホールディングス”, “エフエム東京”, “日本ゴールドディスク大賞”, “フジテレビジョン”, “J-POP”, “小倉博和”, “世界に一つだけの花”, “We are SMAP!”, “日本”, “日本武道館”, “ISBN”}

WikipediaのMedia APIを用いて問い合わせを行って計算を行います。そのため、(Wikipedia上における当該項目の記事内容の変化によって)実行時期によって演算結果に差が出ます。

アップデート理由は、前バージョンではインターネット接続確認を「http://www.google.com」に対して行っていたところに、このドメインに対してhttp経由でのアクセスが行えないようになったので、エラーを起こすようになりました。

このドメインにhttps経由でアクセスするよう変更しました。

Posted in Internet Library list PRODUCTS REST API | Tagged 10.14savvy 10.15savvy 11.0savvy 12.0savvy | Leave a comment

Keynoteの表で選択中のセルの文字列長さを一覧表で表示

Posted on 7月 4, 2022 by Takaaki Naganoya

Keynoteの最前面の書類で表示中のスライド中の表で、選択中の各セルの内容の文字列の長さを表インタフェースで一覧表示するAppleScriptです。

こんなKeynote書類上の表があったとして、その選択中の各セルに入っている文字列の長さを、AppleScriptライブラリ「display table by list」を用いて一覧表示します。実行には同ライブラリのインストールが必要です。

実行の前提として、Keynoteで書類をオープンしてあり、書類上の表の集計対象のセルを選択しておくことが必要です。

文字列長と元の文字列を一覧表示します。

AppleScript名:Keynoteの表で選択中のセルの文字列長さを一覧表で表示.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/07/04
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5" — El Capitan (10.11) or later
use framework "Foundation"
use scripting additions
use easyTable : script "display table by list"

tell application "Keynote"
  tell front document
    tell current slide
      try
        set theTable to first table whose class of selection range is range
      on error
        display notification "Numbers: There is no selection"
        
return
      end try
      
      
tell theTable
        set aRes to value of cells of selection range
      end tell
    end tell
  end tell
end tell

set fLabels to {"文字列長", "文字列"}

set newList to {}
repeat with i in aRes
  set j to contents of i
  
if j is not equal to missing value then
    set aLen to length of j
    
set the end of newList to {aLen, j}
  end if
end repeat

tell current application
  set aRes to (display table by list newList main message "テキストの文字列長" sub message "Keynoteの表で選択中のテキストの各セルの文字列長" size {800, 400} labels fLabels icon "")
end tell

★Click Here to Open This Script 

Posted in list Text | Tagged 10.15savvy 11.0savvy 12.0savvy Keynote | 1 Comment

1D Listを2Dに評価してアイテム内の相違点を検出

Posted on 6月 28, 2022 by Takaaki Naganoya

1次元リスト(配列)を幅を指定しつつ2次元リストとして評価し、1番左側のセルとの変化を横方向にサーチして検出するAppleScriptです。

もともと、macOS標準搭載の「辞書.app」に収録される各辞書データの名称が、各OSバージョンでどのように変化しているかを表計算ソフトNumbers上でチェックしていました。辞書.appの辞書をCocoa Frameworkを通じて呼び出し、さまざまな便利な処理を行っているため、辞書名称が変わると日常的に利用しているAppleScriptに影響が出てしまいます。その変化を検出するために、辞書名の変化を知っておこうというチェック作業が発生しています。

辞書.appの収録辞書名称は、意図したものか意図していないものか不明ですが、OSバージョンごとに微妙に変化することが知られています。そうした名称細部の変化を実際にチェックするのに、専用のScriptを使っていました(過去形)。

ただし、NumbersのデータをAppleScriptから取得すると、2D Listではなく1D Listとして返ってきます。そのさいに、BridgePlusの機能を用いて1D→2D変換を行ったのちに、いろいろ処理を行ってきました。

リストの1D→2D変換処理なんて、使っている場所が多すぎて数えきれないぐらいですが、Script Menu上で動かすScriptでBridgePlusを呼び出せなくなっており(macOS 10.14以降)、今後Script Menuが機能強化されるとは考えにくいところです。

サードパーティのFastScriptsなどでFramework入りScriptの実行をサポートするとか、そういう進化ができてほしいところですが、それもちょっと期待できません。

結果として、BridgePlusを極力使わなくて済むように、機能の置き換えを進めるしかありません。無理な機能もありますが、1D→2D変換ぐらいなら問題ありません(そして、出現頻度がおっそろしく高いものであります)。

そして、実際にNumbers上のデータを横方向(左→右、冒頭から末尾へ)に走査して変更を検出する処理を書いてみました。

処理に柔軟性が欲しかったので、追加でフラグ(reNewF)を用意しました。

これがfalseの場合には、横方向に変更を走査し、変化を検出した場合には評価を打ち切ります。trueの場合には、変化を検出した場合でも変化の検出を続行します。

AppleScript名:1D Listを2D的に評価してアイテム内の相違点を検出.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/06/28
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set aList to {1, 1, 1, 2, 3, 3, 3, 3, 3, 4, 3, 5}
set diffRes to getListDifference2D(aList, 3, true) of me
–> {{xAddrs:{2}, yAddr:2}, {xAddrs:{2}, yAddr:4}}–reNewF=falseで評価
–> {{xAddrs:{2}, yAddr:2}, {xAddrs:{2, 3}, yAddr:4}}—reNewF=true で評価

–1D Listを、2D Listとして評価しつつ、{cell1, cell2, cell3}のcell 1とcell2, cell3が違っていないか評価して返す
on getListDifference2D(dList as list, aWidth as integer, reNewF as boolean)
  script tdSpd
    property dList : {}
  end script
  
  
copy dList to (dList of tdSpd)
  
  
set diffList to {}
  
set diffAdrList to {}
  
  
set yOffsetCount to 1
  
  
set aCountMax to ((length of dList) div aWidth)
  
  
repeat with aC from 1 to (length of dList) by aWidth
    set tmpList to items aC thru (aC + aWidth – 1) of (dList of tdSpd)
    
    
set i1 to first item of tmpList
    
set i2 to rest of tmpList
    
    
set xOffsetCount to 2
    
set xDiffList to {}
    
    
repeat with ii in i2
      set jj to contents of ii
      
      
if i1 is not equal to jj then
        set the end of diffList to {i1, jj}
        
set the end of xDiffList to xOffsetCount
        
        
if reNewF = true then
          copy jj to i1
        else
          exit repeat
        end if
      end if
      
      
set xOffsetCount to xOffsetCount + 1
      
    end repeat
    
    
if xDiffList is not equal to {} then
      set the end of diffAdrList to {xAddrs:xDiffList, yAddr:yOffsetCount}
    end if
    
    
set yOffsetCount to yOffsetCount + 1
  end repeat
  
  
return diffAdrList
end getListDifference2D

★Click Here to Open This Script 

Posted in list | Tagged 10.14savvy 10.15savvy 11.0savvy 12.0savvy Numbers | Leave a comment

Keynote上でテキストアイテムとn重のシェープの重なりを検出 v2

Posted on 6月 25, 2022 by Takaaki Naganoya

Keynoteでオープン中の最前面の書類の現在のスライド(ページ)の上で3重のshapeオブジェクトを下に敷いているテキストアイテムを検出し、文字色を変更するAppleScriptです。

macOS 12.5beta+Keynote v12.1の組み合わせで作成・チェックしてみましたが、Keynote v12.xの固有の機能などは使っていないので、もっと古い環境でも動くはずです。

–> Watch Demo Movie


▲処理前


▲処理後 右側のテキストの色まで変わってしまっているのは意図しなかった処理(わかってたけど)

Keynote書類上でshapeオブジェクトを重ねて何かを表現することはよくありますが、重ねた場所の上に置いてある文字色だけ変更したい場合が往々にしてあります。

さっさと動かすことだけ考えて、ありものの「オブジェクトの重ね合わせ検出」Scriptを使い回しました。そのため、本当に入れ子状態の3つのオブジェクトを検出しているわけではなく、重ね合わせが3回発生しているテキストアイテムを検出しています。

もうちょっと凝った処理を行えば、本当に3階層の入れ子状態のshapeを検出できそうな気はしますが、さすがに使い捨てレベルのScriptにそんなに手間暇をかけるわけにもいかないので、現状ではこんなものでしょう。

Keynoteのselectionがまともに動くようになったので、いろいろ実践的なレベルのScriptを書けるようになりましたが、オブジェクトの重ね合わせ順なども取れたりすると、もっといろいろ書けそうです。

オブジェクトのposition、width、heightを取得する処理は、もうちょっと高速に実行できるように書けそうです(まだまだ、安全第一の処理内容)。

あとは、imageオブジェクトのpathとかイメージデータそのものを取得して、各種画像フィルタをかけてKeynote書類に書き戻せるとよさそうな気がします。

AppleScript名:テキストアイテムと1重のシェープの重なり検出 v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/06/25
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set collisonNum to 1
set targPointSize to 32.0
set targColList to {0, 0, 0} –Black

set tList to {} –text items
set trList to {}

set sList to {} –shapes
set srList to {}
–set bgColList to {} –background color

set colList to choose color

tell application "Keynote"
  tell front document
    tell current slide
      
      
–text itemの情報抽出ループ
      
set allTList to every text item
      
repeat with i in allTList
        set j to contents of i
        
        
tell j
          set {xPos, yPos} to position
          
set aWidth to width
          
set aHeight to height
          
set aRect to makeRect(xPos, yPos, aWidth, aHeight) of me
        end tell
        
        
set the end of tList to j
        
set the end of trList to aRect
      end repeat
      
      
      
–shapeの情報抽出ループ
      
set allSList to every shape
      
repeat with i in allSList
        set j to contents of i
        
tell j
          set {xPos, yPos} to position
          
set aWidth to width
          
set aHeight to height
          
–set aBGCol to background color
          
set aRect to makeRect(xPos, yPos, aWidth, aHeight) of me
        end tell
        
        
set the end of sList to j
        
set the end of srList to aRect
        
set the end of bgColList to aBGCol
        
      end repeat
      
      
set atLen to length of trList
      
set arLen to length of srList
      
      
set outTlist to {}
      
      
      
–shapeと重ね合わせが発生しているtext itemの検出ループ
      
repeat with i from 1 to atLen
        set atRec to contents of item i of trList
        
set atObj to contents of item i of tList
        
set collisionC to 0
        
        
set tmpCSize to point of first character of object text of atObj
        
        
–当該text itemに対して、shapeオブジェクトとのNSRectの重ね合わせが指定数発生しているかをチェック
        
repeat with ii from 1 to arLen
          set tmpRect to contents of item ii of srList
          
set aF to detectRectanglesCollision(atRec, tmpRect) of me
          
          
–背景色(background color)のリストを確認
          
set aBG to contents of item ii of bgColList
          
          
–if {aF, aBG, tmpCSize} = {true, targColList, targPointSize} then set collisionC to collisionC + 1
          
if {aF, tmpCSize} = {true, targPointSize} then set collisionC to collisionC + 1
        end repeat
        
        
–オブジェクトのRectangleが重なり合っている「回数」で判定
        
if collisionC = collisonNum then
          set the end of outTlist to atObj
        end if
      end repeat
    end tell
  end tell
end tell

–文字色を塗り替えるループ
tell application "Keynote"
  tell front document
    tell current slide
      repeat with i in outTlist
        set j to contents of i
        
ignoring application responses
          set color of object text of j to colList
        end ignoring
      end repeat
    end tell
  end tell
end tell

on makeRect(xPos, yPos, aWidth, aHeight)
  return current application’s NSMakeRect(xPos, yPos, aWidth, aHeight)
end makeRect

–NSRect同士の衝突判定
on detectRectanglesCollision(aRect, bRect)
  set a1Res to (current application’s NSIntersectionRect(aRect, bRect)) as {record, list}
  
set tmpClass to class of a1Res
  
  
if tmpClass = record then
    –macOS 10.10, 10.11, 10.12
    
return not (a1Res = {origin:{x:0.0, y:0.0}, |size|:{width:0.0, height:0.0}})
  else if tmpClass = list then
    –macOS 10.13 or later
    
return not (a1Res = {{0.0, 0.0}, {0.0, 0.0}})
  end if
end detectRectanglesCollision

–1から任意の数までのアイテムで、2個ずつの組み合わせのすべての順列組み合わせパターンを計算して返す
–ただし、1×1とか2×2などの同一アイテム同士の掛け合わせを除去するものとする
on retPairPermutationsWithoutSelfCollision(aMax)
  set aList to {}
  
  
repeat with x from 1 to aMax
    repeat with xx from 1 to aMax
      if x is not equal to xx then
        
        
set tmpItem to {x, xx}
        
set a2List to sort1DNumList(tmpItem, true) of me
        
        
if {a2List} is not in aList then
          set the end of aList to a2List
        end if
      end if
      
    end repeat
  end repeat
  
  
return aList
end retPairPermutationsWithoutSelfCollision

–1D List(数値)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DNumList(theList as list, aBool as boolean)
  tell current application’s NSSet to set theSet to setWithArray_(theList)
  
tell current application’s NSSortDescriptor to set theDescriptor to sortDescriptorWithKey_ascending_(missing value, aBool)
  
set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor}
  
return (sortedList) as list
end sort1DNumList

★Click Here to Open This Script 

Posted in bounds list Object control | Tagged 10.15savvy 11.0savvy 12.0savvy Keynote | Leave a comment

相対パスを計算で求める

Posted on 6月 14, 2022 by Takaaki Naganoya

指定のPOSIX pathを元に相対パスを計算するAppleScriptです。

Unix shellであれば、相対パスについては「../../../」などと表現できるわけですが、シェルを介さずに計算する方法が見つからなかったので、必要に迫られて作っておきました。

AppleScript名:上位パスを相対的に求める.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/06/14
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set aFile to "/Users/me/Documents/1/2/3"

set aNum to 1
set bFile to getUpperDir(aFile, aNum) of me

–> "/Users/me/Documents/1/2"

set aNum to 2
set cFile to getUpperDir(aFile, aNum) of me
–>"/Users/me/Documents/1"

set aNum to 3
set dFile to getUpperDir(aFile, aNum) of me
–> "/Users/me/Documents"

–与えられたパスから指定階層「上」のパスを求める
on getUpperDir(aPOSIXpath as string, aNum as integer)
  if aNum < 1 then return aPOSIXpath
  
set pathString to current application’s NSString’s stringWithString:aPOSIXpath
  
repeat aNum times
    set pathString to pathString’s stringByDeletingLastPathComponent()
  end repeat
  
return pathString as string
end getUpperDir

★Click Here to Open This Script 

AppleScript名:下位パスを配列で追加して求める.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/06/14
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set aPOSIXpath to "/Users/me/Documents/" –AppleScriptのPOSIX path表現(フォルダを表現するさい、末尾に「/」)
set catDirList to {"1", "2", "3"}
set bPath to getChildPathByAppendingDirsByArray(aPOSIXpath, catDirList) of me
–> /Users/me/Documents/1/2/3

set aPOSIXpath to "/Users/me/Documents" –CocoaのPOSIX path表現(フォルダを表現する場合でも、末尾に「/」入らず)
set catDirList to {"3", "2", "1"}
set cPath to getChildPathByAppendingDirsByArray(aPOSIXpath, catDirList) of me
–> "/Users/me/Documents/3/2/1"

on getChildPathByAppendingDirsByArray(aPOSIXpath, catDirList)
  set pathString to current application’s NSString’s stringWithString:aPOSIXpath
  
set aList to (pathString’s pathComponents()) as list
  
set aList to aList & catDirList
  
  
set bPath to current application’s NSString’s pathWithComponents:aList
  
return bPath as string
end getChildPathByAppendingDirsByArray

★Click Here to Open This Script 

Posted in File path list Text | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy 12.0savvy | Leave a comment

RectangleBinPackを用いて2D Bin Packを解く v2.3

Posted on 5月 31, 2022 by Takaaki Naganoya

オープンソースの「RectangleBinPack」を用いて2D Bin Packagingを解き、Keynote上の汎用オブジェクト(iWork item)を指定矩形内に詰め込むAppleScriptです。

–> Watch Demo Movie

2D Bin Packは、指定のオブジェクトを面積で評価して、ターゲットの領域に「詰め込む」(オブジェクト回転あり)という処理で、ワードクラウドであるとか、記事レイアウト時の最適化配置といった用途に用いられます。

さまざまなアルゴリズムが提唱され、コンピュータの登場初期からどえらい先人たちが攻めまくった分野であるため、ありがたく、その成果をいただいているという用途でもあります。

よく、ゲームのテクスチャ画像を1枚の画像ファイルに詰め込む際に2D Bin Packの処理を用いている例を見かけます。なんでファイルごとに分けないのかはわかりませんけれども(ファイル容量の節約???)。

–> Download Script bundle with RectangleBinPack in its bundle + sample Keynote document

# This AppleScript requires RectangleBinPack executable in its bundle. So, download the whole AppleScript bundle archive from the link above (↑)

オープン中のKeynote書類の表示中のスライド(ページ)上にある矩形オブジェクト(Shape)を指定の矩形エリア内に2D Packingします。エリアの大きさが小さすぎると正常にPackingされなかったり、false(エラー)を返したりします。

変更履歴:

v2.1: BinPackTestをIntel x64とARM binaryのそれぞれのバイナリでビルドしてバンドルに入れた(Makeを書き換えて直接Universalバイナリに仕立てられるといいのに)
v2.2: BridgePlusがなくても動くように書き換えた(ないと動かないのはいろいろ運用上問題がある)
v2.3: shapeに対してBinPackしていたのを、Keynote上の汎用オブジェクトへのアクセス予約語iWork itemでアクセスするように変更した

AppleScript名:rectBinPack v2.3_Universal.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/05/31
—
–  Copyright © 2019-2022 Piyomaru Software, All Rights Reserved
—
— 2D Bin Packing by juj https://github.com/juj/RectangleBinPack
— v2.1: BinPackTestをIntel x64とARM binaryのそれぞれのバイナリでビルドしてバンドルに入れた(Universalバイナリに仕立てられるといいのに)
— v2.2: BridgePlusを外した(ないと動かないのはいろいろ運用上問題がある)
— v2.3: shapeに対してBinPackしていたのを、Keynote上の汎用オブジェクトへのアクセス予約語iWork itemでアクセスするように変更した

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

–Packaging Target Area
set binSizeX to 600
set binSizeY to 600

set packRes to packKeynoteObjectsOnCurrentSlide(binSizeX, binSizeY) of me

on packKeynoteObjectsOnCurrentSlide(binSizeX, binSizeY)
  set {tList, a0List} to retRectsFromKeynote() of me
  
  
set aList to sortList2DDecending(a0List, {"myWidth", "myHeight", "myArea"}) of me –Sorting key is Width(main) and Area(sub) and Height(sub)
  
  
set aRes to twoDBinPacking(binSizeX, binSizeY, aList) of me
  
if aRes = false then return false
  
  
tell application "Keynote"
    tell front document
      tell current slide
        repeat with i in aRes
          set {posX, posY} to myPos of i
          
set itemIndex to myID of i
          
set aDeg to myDegree of i
          
          
–sample data {itemCounter:5, myWidth:573, myHeight:52, myArea:29796}
          
set anObjID to itemCounter of (item itemIndex of aList)
          
          
set rotation of iWork item anObjID to aDeg
          
set position of iWork item anObjID to {posX, posY}
        end repeat
      end tell
    end tell
  end tell
  
  
return true
end packKeynoteObjectsOnCurrentSlide

on twoDBinPacking(binSizeX as integer, binSizeY as integer, boxList as list)
  set aParamList to {binSizeX, binSizeY}
  
  
repeat with i in boxList
    –copy i to {tmpID, tmpX, tmpY, tmpArea}
    
— {itemCounter:iCount, myWidth:aWidth, myHeight:aHeight, myArea:anArea}
    
set tmpID to itemCounter of i
    
set tmpX to myWidth of i
    
set tmpY to myHeight of i
    
set tmpArea to myArea of i
    
    
set aParamList to aParamList & tmpX
    
set aParamList to aParamList & tmpY
  end repeat
  
  
set aParam to retDelimitedText(aParamList, " ") of me
  
–> "800 800 340 243 340 73 340 73 155 240 147 125 147 125 147 125 147 125"
  
  
–Parameters for result parsing
  
set s1Str to "Packed to (x,y)=("
  
set s2Str to ")"
  
set s3Str to ","
  
  
set cpuRes to CPU type of (system info)
  
if cpuRes begins with "ARM" then
    set exName to "arm"
  else if cpuRes begins with "Intel" then
    set exName to "x86"
  end if
  
  
set binName to "BinPackTest_" & exName
  
set aPath to POSIX path of (path to resource binName)
  
  
try
    set aRes to do shell script quoted form of aPath & " " & aParam
  on error
    return false
  end try
  
  
if aRes does not end with "Done. All rectangles packed." then return false
  
  
set aList to paragraphs of aRes
  
  
set bList to {}
  
set aCount to 1
  
repeat with i in aList
    set j to contents of i
    
if j begins with "Packing rectangle of size " and j does not contain "Failed!" then
      set xyRes to pickUpFromToStrAndParse(j, s1Str, s2Str, s3Str) of me
      
      
–RectangleBinPackがオブジェクトの回転をサポートしているため、その対処
      
if xyRes is not equal to false then
        set s11Str to "(w,h)=("
        
set s12Str to ")"
        
set s13Str to ","
        
        
set whRes to pickUpFromToStrAndParse(j, s11Str, s12Str, s13Str) of me
        
set tmpBox to item aCount of boxList
        
        
— {itemCounter:5, myWidth:573, myHeight:52, myArea:29796}
        
–copy tmpBox to {tmpID, tmpX, tmpY, tmpArea}
        
set tmpID to itemCounter of tmpBox
        
set tmpX to myWidth of tmpBox
        
set tmpY to myHeight of tmpBox
        
set tmpArea to myArea of tmpBox
        
        
if whRes = {tmpX, tmpY} then
          set aDeg to 0
        else if whRes = {tmpY, tmpX} then
          set aDeg to 90
        else
          return false
        end if
        
        
set the end of bList to {myPos:xyRes, myID:aCount, myDegree:aDeg}
      end if
      
set aCount to aCount + 1
    end if
  end repeat
  
  
return bList
end twoDBinPacking

on pickUpFromToStrAndParse(aStr as string, s1Str as string, s2Str as string, s3Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
set {x, y} to parseByDelim(cStr, s3Str) of me
  
  
return {x as integer, y as integer}
end pickUpFromToStrAndParse

on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

–リストを指定デリミタでテキスト化
on retDelimitedText(aList, aNewDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aNewDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retDelimitedText

on retRectsFromKeynote()
  tell application "Keynote"
    tell front document
      tell current slide
        set tList to every iWork item
        
set bList to {}
        
set iCount to 1
        
        
repeat with i in tList
          set aWidth to width of i
          
set aHeight to height of i
          
set {xPos, yPos} to position of i
          
set anArea to aWidth * aHeight
          
          
set the end of bList to {itemCounter:iCount, myWidth:aWidth, myHeight:aHeight, myArea:anArea}
          
set iCount to iCount + 1
        end repeat
        
        
return {tList, bList}
      end tell
    end tell
  end tell
end retRectsFromKeynote

–入れ子のリストを降順ソート
on sortList2DDecending(a, keyLabelList)
  set fLen to length of keyLabelList
  
set fList to {}
  
  
repeat fLen times
    set the end of fList to false
  end repeat
  
  
return cocoaSortListAscending(a, keyLabelList, fList) of me
end sortList2DDecending

–Cocoaで入れ子のリストをソート true:昇順、false:降順
on cocoaSortListAscending(theList as list, keyLabelList as list, ascendingF as list)
  set anArray to current application’s NSMutableArray’s arrayWithArray:(theList)
  
  
set sortDesc to {}
  
set dLen to length of keyLabelList
  
repeat with i from 1 to dLen
    set tmpKeyLabel to contents of item i of keyLabelList
    
set tmpSortF to contents of item i of ascendingF
    
set theDescriptor to (current application’s NSSortDescriptor’s sortDescriptorWithKey:(tmpKeyLabel) ascending:(tmpSortF))
    
set the end of sortDesc to theDescriptor
  end repeat
  
  
set sortedList to anArray’s sortedArrayUsingDescriptors:(sortDesc)
  
  
return sortedList as list
end cocoaSortListAscending

★Click Here to Open This Script 

Posted in 2D Bin Packing list Sort | Tagged 11.0savvy 12.0savvy Keynote | 1 Comment

Keynoteで選択中のスライドのすべての表のセル内文字色を黒にする

Posted on 5月 27, 2022 by Takaaki Naganoya

Keynote v12.0以降で、最前面の書類で選択中のスライド(複数可)にある表のすべての文字色を「黒」に変更するAppleScriptです。

–> Watch Demo Movie

Keynote v12.0で「selection」がまともに機能するようになったので、Keynote用Scriptの実用性がたいへんに高まっています。

# ファイル保存できないとかいうバグが一刻も早く治ることを希望しています。とくに、Pages!

もともと、複数ページにわたって掲載している「表」の中に赤字でマークした箇所があって、そのマークの意図とは別の赤字を入れたかったので、いったんすべて書式をリセットしたかったので書いたものです。

もうちょっと長いScriptを書かなければならないかと思っていたのですが、ことのほかシンプルに書けました。
もっとシンプルに書けるか(everyを使ってスライドごと指定するとか)も試してみたのですが、どうやらこのあたりが限界のようです。

Keynoteのselectionを活かしたScriptでいまいちばん活躍しているのは、Keynoteのテキストアイテム(text item)から内容を取得して、メモリ上でAppleScriptとしてコンパイルし、構文色分けを反映させたスタイル付きテキストを取得して、テキストアイテムに書式を反映させるものです。実に、Keynote上にテキストで書いておいたAppleScriptのリストを構文色分けを反映させた掲載リストに変換できるので便利です。

AppleScript名:Keynoteで選択中のスライドのすべての表のセル内文字色を黒にする.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/05/27
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—

tell application "Keynote"
  set aVer to version
  
  
considering numeric strings
    if aVer < 12.0 then return –Keynote v12.0より以前のバージョンでは実行できない
  end considering
  
  
tell front document
    set aaSel to selection
    
set selClass to class of contents of first item of aaSel
    
if selClass is not equal to slide then return –選択中のオブジェクトがslide(ページ)でなければ処理終了
    
    
repeat with i in aaSel
      set j to contents of i
      
      
tell j
        –現在のスライド上のすべての表のすべてのセルの文字色を黒 {0, 0, 0}に
        
set text color of every cell of every table to {0, 0, 0}
      end tell
      
    end repeat
    
  end tell
  
end tell

★Click Here to Open This Script 

Posted in list Object control | Tagged 10.15savvy 11.0savvy 12.0savvy Keynote | Leave a comment

Keynoteで選択中のGroup内オブジェクトを座標でソートし、テキスト抜き出し

Posted on 5月 15, 2022 by Takaaki Naganoya

Keynote v12.0以降でオープン中の最前面の書類の、表示中のスライド(ページ)上で選択中のグループから、その内部に収められているオブジェクトからテキストを取り出し、リスト(配列)にまとめるAppleScriptです。


▲書類上のオブジェクト(グループ)を選択した状態


▲1冊分のデータがグループにまとめられており、グループ内にオブジェクトを格納

いったんデータを組み上げた「書類」からデータを抜き出すのは、AppleScriptの重要な仕事です。各データ内のフィールドについて座標情報から自動判別するようにしていますが、座標値が想定どおりになっていない場合もあるため、これでもまだ不十分なので、相対的な位置関係(左上、右上、下 などといった)を定義してデータを取り出すようにするとよいでしょう。

……そこまで高度なものを作らなくても、文字列の長さに着目してソートしたら瞬殺でした。

AppleScript名:選択中のGroup内オブジェクトを座標でソートし、テキスト抜き出し.scpt
use AppleScript version "2.8"
use framework "Foundation"
use framework "AppKit"
use scripting additions

property NSFont : a reference to current application’s NSFont
property NSColor : a reference to current application’s NSColor
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName

script spd
  property allList : {}
  
property aaSel : {}
end script

set (allList of spd) to {}

tell application "Keynote"
  set aVer to version
  
if aVer < "12.0" then return
  
  
set acceptClass to {text item, shape}
  
  
tell front document
    set (aaSel of spd) to selection –need Keynote v12.0 or later
    
    
repeat with i in (aaSel of spd)
      set j to contents of i
      
set aClass to class of j
      
      
if aClass = group then
        tell j
          set gItemList to every iWork item
        end tell
        
        
set posList to {}
        
set aCount to 1
        
        
repeat with ii in gItemList
          set jj to contents of ii
          
set bClass to class of jj
          
          
if bClass is in acceptClass then
            tell jj
              set {posX, posY} to position
              
              
try
                set tmpStr to object text as string
              on error
                set tmpStr to ""
              end try
            end tell
            
            
set the end of posList to {positionX:posX, positionY:posY, objID:aCount, myStr:tmpStr}
          end if
          
          
set aCount to aCount + 1
        end repeat
        
        
–座標データをもとにソート
        
set sortedList to sortRecListByLabel(posList, {"positionY", "positionX"}, {true, true}) of me
        
        
–1グループ分のテキストを組み立てる
        
set tmpList to {}
        
repeat with ii in sortedList
          set jj to contents of ii
          
set aStr to myStr of jj
          
set the end of tmpList to aStr
        end repeat
        
set the end of (allList of spd) to tmpList
      end if
    end repeat
  end tell
end tell

return (allList of spd)
–> {{"変数名", "❺", "意外と苦労している人が多い、変数やプロパティ名の命名ルール。とくに、予約語と衝突しない名前について"}, {"条件分岐", "❼", "条件分岐はプログラムに必須。自転車でいえば、カーブで曲がれないとか、水たまりを避けられないぐらい困ります。"}, {"用語辞書", "❹", "読めないと書けない、でも、あの人もこの人も読めない用語辞書。自由自在に読めれば、自由自在に書ける!"}, {"ループ処理", "➓", "プログラムをシンプルに書くための一番大事な構文。書き方によって速度が違ったり、高度な処理を簡潔に書ける!"}, {"アプレット", "⓫", "AppleScriptをアプリケーションとして書き出す、簡易アプリケーション「アプレット」の最新動向!"}, {"間接指定", "❶", "対象としたデータだけでなく、幅広いデータに対応できるよう、プログラムに柔軟性を与える間接指定"}, {"ダイアログ表示", "❾", "簡単に行えるメッセージ表示手段。外部ライブラリの利用でさらなる高機能ダイアログを紹介。"}, {"環境整備", "❽", "macOSに標準で入っているツールを呼び出しやすくしたり設定したりする程度。全体像を掴んでレッツ環境整備。"}, {"フィルタ参照", "❻", "AppleScript独特の概念で、「膨大なデータから正規表現で絞り込む」などの他の処理系と異なる、基礎にして奥義"}, {"tellブロック", "❷", "AppleScriptの7割以上を占める、tellブロックの記述や整理方法を楽に書く秘訣のかずかず"}, {"❸", "ファイルパス", "まさに「基礎」中の「基礎」。「できて当たり前」といえるパス操作。知っているだけで差がつく基礎"}}

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList as list, aLabelStr as list, ascendF as list)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
  
set aCount to length of aLabelStr
  
set sortDescArray to current application’s NSMutableArray’s new()
  
repeat with i from 1 to aCount
    set aLabel to (item i of aLabelStr)
    
set aKey to (item i of ascendF)
    
set sortDesc to (current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabel ascending:aKey)
    (
sortDescArray’s addObject:sortDesc)
  end repeat
  
  
return (aArray’s sortedArrayUsingDescriptors:sortDescArray) as list
end sortRecListByLabel

★Click Here to Open This Script 

Posted in list Sort | Tagged 12.0savvy Keynote | Leave a comment

Keynoteで選択中のtext itemとshapeをもとにtext itemを敷き詰める

Posted on 4月 15, 2022 by Takaaki Naganoya

Keynote v12で正常化した「selection」を用いて、選択中のshapeオブジェクトの範囲に、選択中のtext itemを指定数敷き詰めるAppleScriptです。

–> Watch Demo Movie

Keynote書類上に、敷き詰める領域を示すshapeオブジェクトを1つ、敷き詰める内容を示すtext itemオブジェクトを1つ配置し、これら2つを選択して本Scriptを実行。

選択状態で実行。

指定の最小文字サイズから最大文字サイズ(Keynote書類上で選択したtext item中の文字サイズ)までの間で乱数選択しつつ、指定個数を指定エリア中に作成します。

AppleScript名:選択中のtext itemとshapeをもとにtext itemを敷き詰める.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/04/15
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property textItem : missing value
property shapeItem : missing value

property objMax : 200 –生成するオブジェクト(text item)の個数
property fontSizeMin : 12 –生成するオブジェクト内のobject textのフォントサイズ(これ以下のサイズは生成しない)

tell application "Keynote"
  set aVer to (version as real)
  
if aVer < 12 then return
  
  
tell front document
    –書類上で選択中のオブジェクトを種別に抽出する
    
set aaSel to selection
    
if length of aaSel is not equal to 2 then error "You have to select one text item and one shape."
    
    
repeat with i in aaSel
      set j to contents of i
      
set tmpClass to class of j
      
      
if tmpClass = text item and textItem = missing value then
        set textItem to j
      else if tmpClass = shape and shapeItem = missing value then
        set shapeItem to j
      end if
    end repeat
    
    
if {textItem, shapeItem} contains missing value then error "Selected objects are not suitable"
    
    
    
–選択されたshapeオブジェクトから情報を取得
    
set aPos to (position of shapeItem)
    
set minX to item 1 of aPos
    
set maxX to minX + (width of shapeItem)
    
set minY to item 2 of aPos
    
set maxY to minY + (height of shapeItem)
    
    
–選択されたtext itemオブジェクトから情報を取得
    
set maxFSize to size of object text of textItem
    
set oText to object text of textItem
    
set tWidth to width of textItem
    
set tHeight to height of textItem
    
    
    
–shapeオブジェクトで指定された領域に、text itemを生成
    
repeat objMax times
      –座標を乱数で指定
      
set randomX to random number from minX to (maxX – tWidth)
      
set randomY to random number from minY to (maxY – tHeight)
      
–文字サイズを乱数で指定
      
set randomCSize to random number from fontSizeMin to maxFSize
      
      
tell current slide
        set tmpT to make new text item with properties {object text:oText, position:{randomX, randomY}, width:tWidth, height:tHeight} at the end
        
ignoring application responses
          set size of every character of object text of tmpT to randomCSize
        end ignoring
      end tell
      
    end repeat
  end tell
end tell

★Click Here to Open This Script 

Posted in list | Tagged 10.15savvy 11.0savvy 12.0savvy Keynote | Leave a comment

Keynoteで選択中のオブジェクトを取得して座標でソート

Posted on 4月 10, 2022 by Takaaki Naganoya

Keynote 12.0でまともになった「selection」を使って、選択状態にあるKeynote書類上のオブジェクト(text item)をX座標、Y座標でソートするAppleScriptです。

--> {{objID:2, positionY:219, myCon:"①①①①①", positionX:184}, {objID:4, positionY:492, myCon:"❷❷❷❷❷", positionX:184}, {objID:1, positionY:219, myCon:"③③③③③", positionX:1047}, {objID:3, positionY:492, myCon:"❹❹❹❹❹", positionX:1047}}

選択したtext itemを座標で並べ替え、内容を個別に評価してファイル書き出しするAppleScriptを別途用意して書籍作成用のツールとして、使っています。

書籍の作成作業用に作ったので、アホみたいに高機能です。text itemの内容をAppleScriptとして構文確認して、AppleScriptのオブジェクトを生成し、中間言語コードに解釈ずみの.scptファイルとして書き出しています(書籍のサンプルScript生成用)。こういうツールを作ってすぐに実戦投入できるのも、Keynoteのselectionがまともになったおかげです。

–> Watch Demo Movie

AppleScript名:選択中のオブジェクトを座標をもとにソート.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/04/09
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

tell application "Keynote"
  tell front document
    set aaSel to selection
    
set posList to {}
    
set aCount to 1
    
    
repeat with i in aaSel
      set j to contents of i
      
set mySource to object text of j
      
      
tell j
        set {posX, posY} to position
      end tell
      
      
set the end of posList to {positionX:posX, positionY:posY, objID:aCount, myCon:mySource}
      
      
set aCount to aCount + 1
    end repeat
    
  end tell
end tell

set zList to sortRecListByLabel(posList, {"positionX", "positionY"}, {true, true}) of me

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList as list, aLabelStr as list, ascendF as list)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
  
set aCount to length of aLabelStr
  
set sortDescArray to current application’s NSMutableArray’s new()
  
repeat with i from 1 to aCount
    set aLabel to (item i of aLabelStr)
    
set aKey to (item i of ascendF)
    
set sortDesc to (current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabel ascending:aKey)
    (
sortDescArray’s addObject:sortDesc)
  end repeat
  
  
return (aArray’s sortedArrayUsingDescriptors:sortDescArray) as list
end sortRecListByLabel

★Click Here to Open This Script 

Posted in list Sort | Tagged 11.0savvy 12.0savvy Keynote | Leave a comment

Keynoteの最前面の書類の現在のスライド上の表オブジェクトの重なり合い(2つ以上対応)を検出 v3

Posted on 4月 5, 2022 by Takaaki Naganoya

Keynote書類の現在のスライド(ページ)上に存在する表オブジェクトの重なり合いを検出するAppleScriptです。

前バージョンでは、複数の表オブジェクトが配置されていると、表オブジェクトの位置情報と大きさから生成したNSRect同士の重なりチェックを行なった際に、同じ表同士の重なりチェックも行なっていたので、

複数の表が存在していると、もれなく「重なっている」という警告が出てくるものでした。

本バージョンでは、同じ表同士を重なりチェックしないようにとか、1×3と3×1という「同じオブジェクト同士の重なりチェックを2度行っている」ようなものを排除しています。

今度の順列組み合わせパターン生成ルーチン「retPairPermutationsWithoutSelfCollision」では、これらのパターンを除去しています。

{{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5}, {3, 4}, {3, 5}, {4, 5}}

↑余計な組み合わせパターンは生成されなくなりました。

実際に本Scriptを用いて(複数ページ対応板)、121ページ分の表の重なり合わせチェックを行なってみたところ、M1 Mac miniで3.4秒程度です。

–> Watch Demo Movie


▲重なり合わせ判定:なし


▲重なり合わせ判定:あり


▲重なり合わせ判定:なし


▲重なり合わせ判定:あり(400%拡大表示)


▲重なり合わせ判定:あり(75%拡大表示)

本Scriptの完全版を「AppleScript基礎テクニック集(1)〜間接指定」に収録しています。

AppleScript名:現在のスライド上の表オブジェクトの重なり合い(2つ以上対応)を検出 v3.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/04/03
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

tell application "Keynote"
  tell front document
    set docHeight to height
    
    
tell current slide
      set tList to every table
      
      
if length of tList < 2 then return false –複数の「表」がなかったら衝突は発生していない
      
      
–表の座標とサイズによりNSRectangleを作成する
      
set bList to {}
      
      
repeat with i in tList
        set j to contents of i
        
        
tell j
          set {xPos, yPos} to position
          
set aWidth to width
          
set aHeight to height
          
          
set aRect to makeRect(xPos, yPos, aWidth, aHeight) of me
        end tell
        
        
set the end of bList to aRect
      end repeat
      
      
–作成したNSRectangleの順列組み合わせペア・パターンを作成して、NSRectangle同士の衝突判定を順次行う
      
set aLen to length of bList
      
set permuList to retPairPermutationsWithoutSelfCollision(aLen) of me
      
set corruptList to {}
      
      
repeat with i in permuList
        copy i to {i1, i2}
        
set rectRes to detectRectanglesCollision(item i1 of bList, item i2 of bList) of me
        
if rectRes = true then return true –表同士の衝突が発生している
      end repeat
      
      
return false –表同士の衝突は発生していない
    end tell
  end tell
end tell

on makeRect(xPos, yPos, aWidth, aHeight)
  return current application’s NSMakeRect(xPos, yPos, aWidth, aHeight)
end makeRect

–NSRect同士の衝突判定
on detectRectanglesCollision(aRect, bRect)
  set a1Res to (current application’s NSIntersectionRect(aRect, bRect)) as {record, list}
  
set tmpClass to class of a1Res
  
  
if tmpClass = record then
    –macOS 10.10, 10.11, 10.12
    
return not (a1Res = {origin:{x:0.0, y:0.0}, |size|:{width:0.0, height:0.0}})
  else if tmpClass = list then
    –macOS 10.13 or later
    
return not (a1Res = {{0.0, 0.0}, {0.0, 0.0}})
  end if
end detectRectanglesCollision

–1から任意の数までのアイテムで、2個ずつの組み合わせのすべての順列組み合わせパターンを計算して返す
–ただし、1×1とか2×2などの同一アイテム同士の掛け合わせを除去するものとする
on retPairPermutationsWithoutSelfCollision(aMax)
  set aList to {}
  
  
repeat with x from 1 to aMax
    repeat with xx from 1 to aMax
      if x is not equal to xx then
        
        
set tmpItem to {x, xx}
        
set a2List to sort1DNumList(tmpItem, true) of me
        
        
if {a2List} is not in aList then
          set the end of aList to a2List
        end if
      end if
      
    end repeat
  end repeat
  
  
return aList
end retPairPermutationsWithoutSelfCollision

–1D List(数値)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DNumList(theList as list, aBool as boolean)
  tell current application’s NSSet to set theSet to setWithArray_(theList)
  
tell current application’s NSSortDescriptor to set theDescriptor to sortDescriptorWithKey_ascending_(missing value, aBool)
  
set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor}
  
return (sortedList) as list
end sort1DNumList

★Click Here to Open This Script 

Posted in list | Tagged 12.0savvy Keynote NSRect | 1 Comment

Keynoteの最前面の書類の現在のスライドで、表オブジェクトの重なり合い(2つ以上対応)を検出 v2

Posted on 4月 3, 2022 by Takaaki Naganoya

Keynote書類の現在のスライド(ページ)上に存在する表オブジェクトの重なり合いを検出するAppleScriptです。

Cocoa Scripting Course #4のチェックを行なっていたら、表オブジェクトが重なり合っていたページがあってヘコみました(再チェック中です)。

これを自動でチェックするためのAppleScriptを書いてみました。とりあえず、現在表示しているスライド(ページ)を対象に。最終的には、開始と終了のスライドの番号を与えておくと、その間のスライドをすべてチェックできるとよいでしょう。

CocoaのNSRect同士であれば、重なり合いを検出できるので大変便利です。Keynote上の表オブジェクトから、位置情報と大きさの情報を取得すれば、簡単に目的のデータ(配列に入れたNSRect)を作れることでしょう。

ただし、NSIntersectionRectでNSRect同士の衝突検出を行えるとしても、1対1でしかチェックできないようなので、検出された表同士のすべての衝突チェック組み合わせを行うべく、順列組み合わせペア・パターンを計算する部品を急遽作って(以前作った、Permutation計算とは仕様が違うので)、2つずつ表(から作ったNSRect)を取り出して矩形座標の衝突判定を行なっています。

Keynoteの座標系は「左上」が原点座標で、Cocoaの座標系は左下のはずで….macOS 12で左上になったという話もありますが、実戦投入してみたら衝突が発生していないスライドでも衝突が検出されていたので、このあたり修正する必要があるかもしれません。

Keynoteのスライド上の表の配置状況をCocoaのNSRectで表現し、デバッグ用に画像で表示させてみました。重なりをシミュレーションするだけなら、とくに問題はなさそうです。

→ 原因がわかりました。表の座標とサイズから作ったNSRect同士を重なり合い計算するための、順列組み合わせパターン計算ルーチンで1×1とか2×2とかの「同じNSRect同士」の重なりを計算するようなパターンまで出力していたのが原因です。

つまり、現状では「複数の表オブジェクトが入っているスライド」を検出するだけの計算を行なってしまっているようです。

--> {{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 1}, {2, 2}, {2, 3}, {2, 4}, {2, 5}, {3, 1}, {3, 2}, {3, 3}, {3, 4}, {3, 5}, {4, 1}, {4, 2}, {4, 3}, {4, 4}, {4, 5}, {5, 1}, {5, 2}, {5, 3}, {5, 4}, {5, 5}}

と計算してしまうところを、

--> {{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 1}, {2, 3}, {2, 4}, {2, 5}, {3, 1}, {3, 2}, {3, 4}, {3, 5}, {4, 1}, {4, 2}, {4, 3}, {4, 5}, {5, 1}, {5, 2}, {5, 3}, {5, 4}}

のように、同じアイテム同士の組み合わせになるパターンだけを除外してあげればよかったわけです。自分で資料を作ってみてわかりました。

あとは、3×5と5×3は計算としては同じ意味なので、こういう重複パターンを除去してあげる必要があるのですが…重なりの「個数」を数えるのであるのであればともかく、重なりを「検出」するだけなら重複除去まではする必要がないでしょう。

AppleScript名:現在のスライド上の表オブジェクトの重なり合い(2つ以上対応)を検出 v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/04/03
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

tell application "Keynote"
  tell front document
    tell current slide
      set tList to every table
      
      
if length of tList < 2 then return false –複数の「表」がなかったら衝突は発生していない
      
      
–表の座標とサイズによりNSRectangleを作成する
      
set bList to {}
      
      
repeat with i in tList
        set j to contents of i
        
        
tell j
          set {xPos, yPos} to position
          
set aWidth to width
          
set aHeight to height
          
set aRect to makeRect(xPos, yPos, aWidth, aHeight) of me
        end tell
        
        
set the end of bList to aRect
      end repeat
      
      
–作成したNSRectangleの順列組み合わせペア・パターンを作成して、NSRectangle同士の衝突判定を順次行う
      
set aLen to length of bList
      
set permuList to retPairPermutations(aLen) of me
      
set corruptList to {}
      
      
repeat with i in permuList
        copy i to {i1, i2}
        
set rectRes to detectRectanglesCollision(item i1 of bList, item i2 of bList) of me
        
if rectRes = true then return true –表同士の衝突が発生している
      end repeat
      
      
return false –表同士の衝突は発生していない
    end tell
  end tell
end tell

on makeRect(xPos, yPos, aWidth, aHeight)
  return current application’s NSMakeRect(xPos, yPos, aWidth, aHeight)
end makeRect

–NSRect同士の衝突判定
on detectRectanglesCollision(aRect, bRect)
  set a1Res to (current application’s NSIntersectionRect(aRect, bRect)) as {record, list}
  
set tmpClass to class of a1Res
  
  
if tmpClass = record then
    –macOS 10.10, 10.11, 10.12
    
return not (a1Res = {origin:{x:0.0, y:0.0}, |size|:{width:0.0, height:0.0}})
  else if tmpClass = list then
    –macOS 10.13 or later
    
return not (a1Res = {{0.0, 0.0}, {0.0, 0.0}})
  end if
end detectRectanglesCollision

–1から任意の数までのアイテムで、2個ずつの組み合わせのすべての順列組み合わせパターンを計算して返す
on retPairPermutations(aMax)
  set aList to {}
  
  
repeat with x from 1 to aMax
    repeat with xx from 1 to aMax
      set tmpItem to {x, xx}
      
if tmpItem is not in aList then
        set the end of aList to tmpItem
      end if
    end repeat
  end repeat
  
  
return aList
end retPairPermutations

★Click Here to Open This Script 

Posted in list | Tagged 12.0savvy Keynote NSRect | 1 Comment

Pages書類内の表の指定ラベルの行を削除

Posted on 2月 14, 2022 by Takaaki Naganoya

Pagesの書類上にある表に対して、指定のラベルを持つ行を削除するAppleScriptです。macOS 12.3beta2+Pages 11.2で動作確認しています。

現在作成中のWebブラウザのScripting本で、各種AppleScript実行環境の一覧表を掲載しているのですが、

それぞれの差別化ポイントとして掲載していたデータのうちの1つが、執筆後に一律で解決できることになり(NSAlertダイアログの最前面表示)、そのデータ行については削除することになりました。

そこで、複数のPages書類に記載した表を一括で削除することになり、AppleScriptを組んで削除することにしました。

必要はありませんでしたが、ヘッダー列が1列だけでなく、複数の列になった場合と、ヘッダーの複数セルが1つにまとめられていた場合への対処も行っておきました。ただし、気休め程度であって、本気で対処したものではありません。

AppleScript名:Pages書類内の表の指定ラベルの行を削除.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/02/14
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

set targRowLabel to "NSAlert ダイアログの最前面表示"

tell application "Pages"
  tell front document
    set tList to every table whose column count = 2
  end tell
end tell

delRowInEveryTable(tList, targRowLabel) of me

on delRowInEveryTable(tList as list, targRowLabel as string)
  tell application "Pages"
    repeat with i in tList
      set j to contents of i
      
      
tell j
        set hCCount to header column count
        
set hRCount to header column count
        
        
–ヘッダーカラムが複数存在している場合に対処?
        
repeat with hc from 1 to hCCount
          tell column hc
            set aList to value of every cell
          end tell
          
          
if targRowLabel is in aList then
            set aRes to search1DList(aList, targRowLabel) of me
            
            
–ヘッダー列に削除対象ラベルが存在しつつ、削除対象ラベルがヘッダー行の範囲ではない場所に出現した場合に削除
            
if (aRes is not equal to false) and (aRes ≥ hRCount) then
              try –ねんのため
                delete row aRes
              end try
            end if
          end if
          
        end repeat
      end tell
    end repeat
    
  end tell
end delRowInEveryTable

on search1DList(aList, aTarg)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set anIndex to anArray’s indexOfObject:aTarg
  
if (anIndex = current application’s NSNotFound) or (anIndex > 9.99999999E+8) then
    return false
  end if
  
return (anIndex as integer) + 1 –convert index base (0 based to 1 based)
end search1DList

★Click Here to Open This Script 

Posted in list | Tagged 10.15savvy 11.0savvy 12.0savvy Pages | Leave a comment

Post navigation

  • Older posts
  • Newer posts

電子書籍(PDF)をオンラインストアで販売中!

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • macOS 15, Sequoia
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • Numbersで選択範囲のセルの前後の空白を削除
  • メキシカンハットの描画
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AppleScriptによる並列処理
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • macOS 15でも変化したText to Speech環境
  • AppleScript入門③AppleScriptを使った「自動化」とは?
  • デフォルトインストールされたフォント名を取得するAppleScript
  • macOS 15 リモートApple Eventsにバグ?
  • 【続報】macOS 15.5で特定ファイル名パターンのfileをaliasにcastすると100%クラッシュするバグ
  • AppleScript入門① AppleScriptってなんだろう?
  • Script Debuggerの開発と販売が2025年に終了
  • macOS 14で変更になったOSバージョン取得APIの返り値
  • NSObjectのクラス名を取得 v2.1
  • 有害ではなくなっていたSpaces
  • macOS 15:スクリプトエディタのAppleScript用語辞書を確認できない
  • Xcode上のAppleScriptObjCのプログラムから、Xcodeのログ欄へのメッセージ出力を実行

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1391) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (212) 13.0savvy (194) 14.0savvy (147) 15.0savvy (135) CotEditor (66) Finder (51) iTunes (19) Keynote (119) NSAlert (61) NSArray (51) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (53) NSDictionary (28) NSFileManager (23) NSFont (21) NSImage (41) NSJSONSerialization (21) NSMutableArray (63) NSMutableDictionary (22) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (119) NSURL (98) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (76) Pages (55) Safari (44) Script Editor (27) WKUserContentController (21) WKUserScript (20) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • Beginner
  • Benchmark
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • check sum
  • Clipboard
  • Cocoa-AppleScript Applet
  • Code Sign
  • Color
  • Custom Class
  • date
  • dialog
  • diff
  • drive
  • Droplet
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • Font
  • GAME
  • geolocation
  • GUI
  • GUI Scripting
  • Hex
  • History
  • How To
  • iCloud
  • Icon
  • Image
  • Input Method
  • Internet
  • iOS App
  • JavaScript
  • JSON
  • JXA
  • Keychain
  • Keychain
  • Language
  • Library
  • list
  • Locale
  • Localize
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • parallel processing
  • PDF
  • Peripheral
  • process
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • rectangle
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • Review
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • selection
  • shell script
  • Shortcuts Workflow
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Telephony
  • Text
  • Text to Speech
  • timezone
  • Tools
  • Update
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 2025年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2024年2月
  • 2024年1月
  • 2023年12月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年12月
  • 2019年11月
  • 2019年10月
  • 2019年9月
  • 2019年8月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年11月
  • 2018年10月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年5月
  • 2018年4月
  • 2018年3月
  • 2018年2月

https://piyomarusoft.booth.pm/items/301502

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org

Forum Posts

  • 人気のトピック
  • 返信がないトピック

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org
Proudly powered by WordPress
Theme: Flint by Star Verte LLC