Menu

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

AppleScriptの穴

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

カテゴリー: Record

構成要素を指定して漢字検索 v3

Posted on 2月 22 by Takaaki Naganoya

旧称「部首で漢字検索」のバージョンアップ版です。部首ではなく構成部品の文字を指定して漢字を検索するAppleScriptです。

便利な道具ではありますが、あくまでも子供の学習用以外の用途にお使いください。

–> Download kanjiSearchFromPartsV3.zip (AppleScript Bundle with library and JSON files in its bundle)

前バージョンでは常用漢字の範囲を超えるデータが出力されるという問題点があったため、常用漢字の一覧データを作成し、これに合致するものだけを出力するようにしました。

常用漢字との照合処理に時間がかかっており、v2ではAppleScriptのネイティブ機能でループして除外チェックを行なっておりました。これをv3ではCocoaの機能を用いて一括で重複部分の抽出を行うことで、v2の半分の時間で完了できることに。v2で0.6秒程度かかっていたものが、v3では0.3秒を下回る時間で処理できるようになりました(MacBook Pro Core i7 2.66GHz)。

そもそも論でいえば、元のJSONデータから常用漢字+人名漢字を超える文字の情報を削除すればいいだけの話なので、JSONデータから常用漢字+人名漢字を超える文字を削除するプログラムを書いて実行するのがよいのでしょう。

AppleScript名:構成要素を指定して漢字検索 v3.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/02/21
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.7"
use framework "Foundation"
use scripting additions
use jkLib : script "jyoyoKanjiLib" –常用漢字一覧を返してくるAppleScriptライブラリ

script jsonStr
  property aJsonDict : missing value –JSONから読み取ったNSDictionary
  
property jKanji : missing value –常用漢字データ(NSArray)
end script

property NSString : a reference to current application’s NSString
property NSCountedSet : a reference to current application’s NSCountedSet
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

–図形としての構成要素を指定して漢字検索(部首ではない)
–set aRes to searchKanjiFromElementJ("木") of me –きへん? のぎへんや他のものも返ってくるよ
–> {"椅", "植", "椎", "検", "頼", "漆", "鉢", …}

–set bRes to searchKanjiFromElementJ("氵") of me –さんずい
–> {"滴", "漁", "漂", "漆", "漏", "演", "漠",…}

set dRes to searchKanjiFromElementJ("⻖") of me
–>{"堕", "墜", "阪", "防", "阻", "附", "降"…}

–検索に使える部首のキー文字の一覧を返す
–set qList to listupQueryKeysForKanji() of me
–> {"工", "棘", "左", "位", "婁", "攴", …}

on searchKanjiFromElementJ(aQueryStr)
  if (aJsonDict of jsonStr) = missing value then my init()
  
if (jKanji of jsonStr) = missing value then my initJ()
  
set aRes to (aJsonDict of jsonStr)’s valueForKey:aQueryStr
  
if aRes = missing value then return missing value
  
  
set cArray to aRes’s arrayByAddingObjectsFromArray:(jKanji of jsonStr)
  
set cRes to returnDuplicatesOnly(cArray) of me
  
return cRes
end searchKanjiFromElementJ

on searchKanjiFromElement(aQueryStr)
  if (aJsonDict of jsonStr) = missing value then my init()
  
set aRes to (aJsonDict of jsonStr)’s valueForKey:aQueryStr
  
if aRes = missing value then return missing value
  
return aRes as list
end searchKanjiFromElement

on listupQueryKeysForKanji()
  if (aJsonDict of jsonStr) = missing value then my init()
  
set aRes to (aJsonDict of jsonStr)’s allKeys()
  
return aRes as list
end listupQueryKeysForKanji

on initJ()
  set (jKanji of jsonStr) to current application’s NSArray’s arrayWithArray:(retJyouyouKanji() of jkLib)
end initJ

on init()
  –https://github.com/yagays/kanjivg-radical
  
set aPath to (POSIX path of (path to me)) & "Contents/Resources/element2kanji.json"
  
set jsonString to NSString’s alloc()’s initWithContentsOfFile:(aPath) encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set (aJsonDict of jsonStr) to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
end init

on returnDuplicatesOnly(anArray)
  set aSet to NSCountedSet’s alloc()’s initWithArray:anArray
  
set bList to (aSet’s allObjects()) as list
  
  
set dupList to {}
  
repeat with i in bList
    set aRes to (aSet’s countForObject:i)
    
if aRes > 1 then
      set the end of dupList to (contents of i)
    end if
  end repeat
  
  
return dupList
end returnDuplicatesOnly

★Click Here to Open This Script 

Posted in JSON Record | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy | Leave a comment

部首で漢字検索

Posted on 2月 21 by Takaaki Naganoya

漢字の部首を指定して、漢字を検索するAppleScriptです。厳密にいえば「部首」の文字ではなく、それっぽい文字で探せます。用途や利用者を想定できれば(子供が勉強用に使わないのであれば)十分に有用だと思います(理由は後述)。

Unicodeのデータから検索できるのではないかと考え、Unicodeの規格を調べていたのですが、漢字のSVGデータから構成文字情報を抽出したとされる「kanjivg-radical」を偶然みつけ、これを利用することで、割と手軽に実現できました。

–> kanjiSearch.zip(Download Script Bundle included JSON in its bundle)

開発環境のMac(Intel Core i7 2.66GHz)で、キャッシュがヒットしていれば(JSONから変換したデータがpropertyに読み込まれていれば)0.02秒程度で検索できています。この手の処理はデータのローディング(読み込み)が命なので、SSD使用必須です。

同データはJSON形式なので、AppleScriptバンドル中にJSONのまま突っ込んで、Cocoaの機能を用いてNSDictionaryに読み込んで検索しています。

ほかにも、Mac OS Xへの移行時に散々紹介されたMac OS Xのビックリドッキリ機能「関連文字に変換」をAppleScriptで実現した「関連文字を検索」も作ってみました。

このあたりをまとめてAppleScriptライブラリにしておけば便利そうですが、まだ使い勝手をテストしている段階です。義務教育で習う漢字の構成要素(へん、つくり etc)の呼び名とkanjivg-radicalで利用できる構成パーツの間に不整合(kanjivg-radicalの方が柔軟)があるので、そのあたりを埋めないと使いにくそう(下手に子供が使うと間違った国語知識を持ってしまう)な危険があるので、そのあたりを補う必要性を感じます。

たとえば、「禾」(のぎへん)を持つ漢字を「木」で検索できてしまうところです。大人は「実用的で使いやすい!」と喜ぶところですが、義務教育課程では両者は厳密に区別されています。自分は使いやすいので喜んで使っていますが、用途によっては使わないほうがよいかもしれません。

追記:

へんやつくりを元に検索できるデータとして、同梱の「radical2kanji_left_right.json」や「radical2kanji_top_bottom.json」が存在していることに気づいたので、そちらをAppleScriptのバンドル中に入れて、同様に検索してみました。

ただ、こちらのデータは随分と粗が多く、「⻖」(こざとへん)で自分の名前に使われている「隆」を「radical2kanji_left_right.json」から検索したところヒットしません。

{"阨", "陵", "隈", "険", "陣", "院", "陲", "陦", "陽", "陳", "陬", "隧", "險", "除", "隍", "陜", "陀", "陏", "隗", "階", "障", "隕", "降", "陂", "隴", "隔", "際", "隅", "附", "限", "陸", "陟", "陌", "阮", "阡", "阯", "阻", "阿", "阪", "防"}

国語辞書や文字コード表との照合といいますか、きちんとした検証作業は行われておらず、機械的に処理しただけのデータという印象を受けます。

一方で、「element2kanji.json」を用いて「⻖」(こざとへん)で検索したところ、

{"嶐", "阨", "蔭", "橢", "薩", "隣", "婀", "陵", "隈", "窿", "険", "隠", "陷", "陣", "痾", "院", "陶", "隙", "陲", "陦", "陽", "陪", "陳", "隘", "陥", "陬", "墜", "隧", "陰", "險", "除", "隍", "陜", "陀", "陛", "陏", "隗", "階", "障", "隕", "降", "陂", "隨", "隴", "隔", "随", "際", "隋", "陞", "隰", "墮", "隱", "陝", "隅", "隊", "附", "限", "陋", "陸", "陟", "隲", "陌", "隆", "阮", "阡", "阯", "阻", "阿", "阪", "堕", "防"}

と、結果が返ってきており……どうも複数のJSONデータを用いて、へんやつくりを考慮したJSONデータで検索して、ヒットしなかったら「element2kanji.json」を用いて物量でダメ押しするように設計されているようです。つまり、「radical2kanji_left_right.json」や「radical2kanji_top_bottom.json」が粗いのを複数のデータで補うように使うものである、と。

無限の量とバリエーションを持つデータに対するアプローチとしては間違っていないと思いますが、文字コードという有限のデータに対しての処理としては少し疑問が残る実装です。本当に使い物になるデータにするには、実際に人間の手による検証と校正が必要な内容でしょう。そのことは明記されるべきです。

「element2kanji.json」は現状のままで有用だと思いますが、「radical2kanji_left_right.json」や「radical2kanji_top_bottom.json」については、実際に国語辞典と照合してデータを補わないと実用レベルにはならないと感じました。盲目的に信用しないで、手元で実際に評価・検証することが重要です。

データ自体、CJK(中国語、日本語、韓国語)の統合漢字をサポートする範囲で作成されているようで、日本語で日常的に利用する常用漢字よりも幅広い文字がデータ化されています。常用漢字の範囲内に含まれているかをチェックするデータを併用するのが妥当でしょう。

AppleScript名:部首で漢字検索.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/02/21
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—

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

script jsonStr
  property aJsonDict : missing value
end script

property NSString : a reference to current application’s NSString
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

–部首を指定して漢字検索
set aRes to searchKanjiFromElement("木") of me –きへん
–> {"稾", "欅", "謀", "酥", "悚", "椁", "検"….}

–set bRes to searchKanjiFromElement("氵") of me–さんずい
–> {"溯", "湮", "漁", "漕", "濶", "懣", "添", "淨",…..}

–set cRes to searchKanjiFromElement("之") of me
–> {"芝", "泛", "貶", "乏"}

–set dRes to searchKanjiFromElement("⻖") of me
–> {"嶐", "阨", "蔭", "橢", "薩", "隣", "婀"…}

–検索に使える部首のキー文字の一覧を返す
–set qList to listupQueryKeysForKanji() of me
–> {"工", "棘", "左", "位", "婁", "攴", "巨", "攵"…}

on searchKanjiFromElement(aQueryStr)
  if (aJsonDict of jsonStr) = missing value then my init()
  
set aRes to (aJsonDict of jsonStr)’s valueForKey:aQueryStr
  
if aRes = missing value then return missing value
  
return aRes as list
end searchKanjiFromElement

on listupQueryKeysForKanji()
  if (aJsonDict of jsonStr) = missing value then my init()
  
set aRes to (aJsonDict of jsonStr)’s allKeys()
  
return aRes as list
end listupQueryKeysForKanji

on init()
  –https://github.com/yagays/kanjivg-radical
  
set aPath to (POSIX path of (path to me)) & "Contents/Resources/element2kanji.json"
  
set jsonString to NSString’s alloc()’s initWithContentsOfFile:(aPath) encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set (aJsonDict of jsonStr) to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
end init

★Click Here to Open This Script 

Posted in File path Record | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy NSJSONSerialization NSString NSUTF8StringEncoding | Leave a comment

CotEditorの各Windowで選択しておいた内容を座標でソートして結合

Posted on 2月 11 by Takaaki Naganoya

CotEditorでオープン中の複数のウィンドウから、各ウィンドウ(書類)の選択範囲を取得し、各ウィンドウの画面上の位置情報をもとに、その順番(Y座標、X座標)にテキストを組み合わせて新規書類を作成するAppleScriptです。


▲DEMO


▲Live Coding

当初、ウィンドウの重ね合わせ順(windowのindex)も考慮していたのですが、実際にためしてみたところ、重ね合わせ順を使うのは無駄だったので、機能を外しました。

AppleScript名:CotEditorの各Windowで選択しておいた内容を重ね合わせ順と座標でソートして結合.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/02/10
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

set wList to {}

tell application "CotEditor"
  set wCount to count (every window whose visible is true)
  
if wCount < 2 then return
  
  
repeat with i from 1 to wCount
    tell window i
      set tmpBounds to bounds
      
      
set tmpProp to properties
    end tell
    
    
set tmpDoc to document of tmpProp
    
tell tmpDoc
      set aCon to contents of selection
    end tell
    
    
set tmpX to item 1 of tmpBounds
    
set tmpY to item 2 of tmpBounds
    
set tmpRec to {winIndex:i, winX:tmpX, winY:tmpY, selText:aCon}
    
    
set the end of wList to tmpRec
    
  end repeat
  
end tell

–座標値をもとにソートして選択テキストを返す
set sWList to sortRecListByLabel(wList, {"winY", "winX"}, {true, true}) of me
set anArray to current application’s NSArray’s arrayWithArray:sWList
set vList to (anArray’s valueForKey:"selText") as list
set jointStr to retArrowText(vList, return) of me

–CotEditor上で指定テキストでドキュメントを新規作成
makeNewCotEditorDoc(jointStr) of me

–リストを指定デリミタを追加しつつテキスト化
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

–リストに入れたレコードを、指定の属性ラベルの値でソート
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

–指定テキストで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 list Record | Tagged 10.14savvy 10.15savvy 11.0savvy CotEditor | Leave a comment

現在のスライドと次のスライドでオーバーラップしている画像とグループを検出して位置をそろえる

Posted on 9月 10, 2020 by Takaaki Naganoya

Keynoteの最前面の書類で、現在表示中のスライドと次のスライドの間で、矩形座標が重なっている「画像」と「グループアイテム」(複数のオブジェクトをグループ化したアイテム)を検出して、現在のスライドの開始位置に場所をそろえるAppleScriptです。

# 最初掲載したもの(v1)は、動作しているものの処理内容に誤りがあったので修正しました(v2)

連続したスライド上に画面図を配置して、その画面図の位置をそろえるためのものです。何回か書いたような気がします。見た目より書くのが大変ではないので、ついつい書いてしまう処理です。

単にそれぞれの対象候補のオブジェクトの矩形開始座標と幅&高さをリスト化して、それをNSRectに変換して重ね合わせが発生していないかをCocoaの機能で判定しているだけです。この、一番めんどくさい部分をCocoaに丸投げしているので、おおよそ知性というものを感じさせないレベルのScriptです。

画像やグループアイテム 以外の表オブジェクト同士の重なりあいの検出を行うものに書き換えるのは簡単ですが、複数のオブジェクトの重なり合いが発生している場合には対処できません。

AppleScript名:現在のスライドと次のスライドでオーバーラップしている画像とグループを検出して位置をそろえる v2.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/09/10
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

tell application "Keynote"
  set dCount to count every document
  
if dCount = 0 then return –ドキュメントがオープンしていないと処理終了
  
  
tell front document
    set allNum to count every slide
    
if allNum < 2 then return –slideの枚数が少なかった場合に処理終了
    
    
set curSlide to current slide
    
if allNum = curSlide then return –current slideが末尾だった場合処理終了
    
    
set sNum to slide number of curSlide
    
set nextSlide to slide (sNum + 1)
    
    
–最初のページ(スライド)からオブジェクトを収集
    
tell current slide
      set curObj1 to every image
      
set curObj2 to every group
      
set curObjList to curObj1 & curObj2
      
if curObjList = {} then return
    end tell
    
    
–次のページ(スライド)からオブジェクトを収集
    
tell nextSlide
      set nextObj1 to every image
      
set nextObj2 to every group
      
set nextObjList to nextObj1 & nextObj2
      
if nextObjList = {} then return
    end tell
    
    
set nexObjRes to calcOverlappedObj(curObjList, nextObjList) of me
    
repeat with i in nexObjRes
      copy i to {origID, targID}
      
set aOrigObj to contents of item origID of curObjList
      
set aTargObj to contents of item origID of nextObjList
      
set origPos to position of aOrigObj
      
set position of aTargObj to origPos
    end repeat
    
    
set current slide to slide sNum
  end tell
end tell

–与えられた2つのリストに入っているKeynoteオブジェクトの矩形座標が重なっているものをIDペアで出力する
–同時に複数のオブジェクトが重なっていないことが前提
on calcOverlappedObj(objList1, objList2)
  tell application "Keynote"
    –最初のページのオブジェクトからオブジェクトIDとNSRectからなるリストを作成
    
set objRecList1 to {}
    
set aCount to 1
    
repeat with i in objList1
      if contents of i is not equal to {} then
        set {x1, y1} to position of i
        
set aRect to {origin:{x:x1, y:y1}, |size|:{|width|:(width of i), |height|:(height of i)}}
        
        
set the end of objRecList1 to {objID:aCount, rect:aRect}
      end if
      
set aCount to aCount + 1
    end repeat
    
    
–次のページのオブジェクトからオブジェクトIDとNSRectからなるリストを作成
    
set objRecList2 to {}
    
set aCount to 1
    
repeat with i in objList2
      if contents of i is not equal to {} then
        set {x1, y1} to position of i
        
set aRect to {origin:{x:x1, y:y1}, |size|:{|width|:(width of i), |height|:(height of i)}}
        
        
set the end of objRecList2 to {objID:aCount, rect:aRect}
      end if
      
set aCount to aCount + 1
    end repeat
    
    
–最初のページのオブジェクトと次のページのオブジェクトで矩形エリアが重なっているオブジェクトを抽出してそれぞれのIDをペアにしたリストを作成
    
set matchList to {}
    
repeat with i in objRecList1
      
      
set origRect to rect of i
      
set origID to objID of i
      
      
repeat with ii in objRecList2
        
        
set targRect to rect of ii
        
set targID to objID of ii
        
set tRes to detectRectanglesCollision(origRect, targRect) of me
        
        
if tRes = true then
          set the end of matchList to {origID, targID}
        end if
      end repeat
      
    end repeat
    
    
return matchList
  end tell
end calcOverlappedObj

–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

★Click Here to Open This Script 

Posted in list Record | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy Keynote | Leave a comment

指定TTSボイスキャラクタの読み上げ例文テキストを取得

Posted on 7月 6, 2020 by Takaaki Naganoya

指定のテキスト読み上げ(Text To Speech)ボイスキャラクターの読み上げ例文テキストを取得して実際に読み上げるAppleScriptです。

TTS音声は言語や性別、年齢、高音質かどうかなどの情報を持っているので、これらを指定して絞り込むことが可能です。また、指定TTS音声キャラクターの例文テキストもこのように取得できます。

AppleScript名:指定TTSボイスキャラクタの読み上げ例文テキストを取得.scpt
— Created 2015-08-25 by Takaaki Naganoya
— Modified 2015-08-26 by Shane Stanley, Takaaki Naganoya
— Modified 2020-07-06 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use scripting additions

set vList to getVoiceNames() of me
using terms from scripting additions
  set aTargTTSVoiceName to contents of (choose from list vList)
end using terms from

using terms from scripting additions
  set v1Res to getDemoText(aTargTTSVoiceName) of me
  
say v1Res using aTargTTSVoiceName
end using terms from

–Get TTS Voice sample text
on getDemoText(aName as string)
  set vList to getVoiceNames() of me
  
if aName is not in vList then return ""
  
set anID to getSpecifiedVoiceIDfromVoiceName(aName) of me
  
  
set aDemoText to ((current application’s NSSpeechSynthesizer’s attributesForVoice:anID)’s VoiceDemoText)
  
return aDemoText as string
end getDemoText

–Get all voice names
on getVoiceNames()
  –Make Blank Array
  
set outArray to current application’s NSMutableArray’s arrayWithObject:{}
  
set aList to {}
  
  
–Make Installed Voice List
  
set nameList to current application’s NSSpeechSynthesizer’s availableVoices()
  
repeat with i in nameList
    set j to contents of i
    
    
set aDic to ((current application’s NSSpeechSynthesizer’s attributesForVoice:j))
    
    
set aDemoText to (aDic’s VoiceDemoText) as string
    
set aName to (aDic’s VoiceName) as string
    
    
set the end of aList to aName
  end repeat
  
  
return aList as list
end getVoiceNames

–Voice Name –> Voice ID
on getSpecifiedVoiceIDfromVoiceName(VoiceName as string)
  set outArray to current application’s NSMutableArray’s arrayWithObject:{}
  
  
set aList to current application’s NSSpeechSynthesizer’s availableVoices()
  
set bList to aList as list
  
  
repeat with i in bList
    set j to contents of i
    
set aDic to (current application’s NSSpeechSynthesizer’s attributesForVoice:j)
    (
outArray’s addObject:aDic)
  end repeat
  
  
–Filter Voice
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat_("VoiceName == %@", VoiceName)
  
  
set filteredArray to outArray’s filteredArrayUsingPredicate:aPredicate
  
set aReList to (filteredArray’s valueForKey:"VoiceIdentifier") as list
  
  
if length of aReList = 1 then
    return first item of aReList
  else
    return ""
  end if
end getSpecifiedVoiceIDfromVoiceName

★Click Here to Open This Script 

Posted in list Record System Text to Speech | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy NSMutableArray NSPredicate NSSpeechSynthesizer | Leave a comment

chartJSでアニメーション円グラフをダイアログ表示 v2.scptd

Posted on 6月 30, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを作成し、その上でChart.jsによる円グラフを表示するAppleScriptです。


▲実行するとテーマ選択ののちにグラフ表示を行います


–> Download chartJSPieChartDemo.scptd(Script Bundle with Lirbrary and HTML)

Chart.jsは、ダイアグラムやフローチャートなどを描画するJavaScriptのライブラリです。割とデータのカスタマイズがしやすい感じです。

AppleScript名:chartJSでアニメーション円グラフをダイアログ表示 v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/06/26
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use webD : script "webDialogLib"

set aRes to first item of (choose from list {"light1", "light2", "dark1", "dark2"} with prompt "Choose theme")

set aList to {{y:45.43, label:"Chrome"}, {y:32.4, label:"Safari"}, {y:6.67, label:"Firefox"}, {y:5.41, label:"Microsoft Edge"}, {y:5.26, label:"Internet Explorer"}, {y:1.19, label:"Samsung Internet"}}
set myTitle to "Desktop Browser Market Share in Japan May 2020"

–https://canvasjs.com/javascript-charts/pie-chart-legends/
set mePath to path to me
set resPath to (mePath as string) & "Contents:Resources:index.html"
set myStr to (read (resPath as alias) as «class utf8») as string

set aJsonStr to array2DToJSONArray(aList) of me
set aString to current application’s NSString’s stringWithFormat_(myStr, aRes as string, myTitle, aJsonStr) as string

set paramObj to {myMessage:"Animation Pie Chart", mySubMessage:"This is a canvasJS test", htmlStr:aString, jsDelimiters:{"<script>", "</script>"}, viewSize:{900, 620}}

webD’s displayWebDialog(paramObj)

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value)
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

★Click Here to Open This Script 

Posted in dialog list Record 未分類 | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy NSJSONSerialization NSMutableArray NSString | Leave a comment

CotEditor上で選択中のJavaScriptのrecord in listをASのオブジェクトに変換

Posted on 6月 29, 2020 by Takaaki Naganoya

CotEditorの最前面のドキュメントで選択中の、JavaScriptのrecord in listをAppleScriptのオブジェクトに変換するAppleScriptです。

こんな風にJavaScriptのプログラム中のrecord in listを選択しておいてScriptを実行すると、

AppleScriptのオブジェクトに変換します。

AppleScript名:CotEditor上で選択中のJavaScriptのrecord in listをASのオブジェクトに変換.scpt
— Created 2015-07-20 by Takaaki Naganoya
— 2015 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

tell application "CotEditor"
  tell front document
    set jsonText to contents of selection
  end tell
end tell

set a to repChar(jsonText, "[", "{") of me
set b to repChar(a, "]", "}") of me
set c to repChar(b, string id 10, "") of me
set d to repChar(c, tab, "") of me

try
  set e to run script d
  
set f to convToStr(e) of textKit
  
  
tell application "CotEditor"
    make new document
    
tell front document
      set contents to f
    end tell
  end tell
on error erM
  display dialog erM
  
end try

–文字置換
on repChar(origText as string, targChar as string, repChar as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

–リストでもレコードでもなんでも文字列化して返すキット
script textKit
  
  
on convToStr(aRec)
    set aClass to (class of aRec) as string
    
    
if (aClass = "integer") or (aClass = "number") or (aClass = "real") or (aClass = "string") or (aClass = "text") or (aClass = "Unicode text") or (aClass = "boolean") then
      set aRes to aRec as string
    else if aClass is "list" then
      set aRes to listToString(aRec)
    else if aClass is "record" then
      set aRes to recToString(aRec)
    else
      try
        set aRes to aRec as string
      on error
        –アプリケーションのオブジェクトとかはエラーで返す
        
return false
      end try
    end if
    
    
return aRes
    
  end convToStr
  
  
  
–レコードをStringに変換
  
  
–エラートラップを使って、わざとエラーを発生させ、エラーメッセージからレコードをstringに変換する
  
on recToString(aRec)
    
    
–レコードを無理矢理stringにcastして、エラーメッセージを取得する
    
try
      set a to aRec as string –ここでエラー発生
    on error aMes
      set a to aMes
    end try
    
    
–エラーメッセージ文字列から、元のレコードの情報を組み立てる
    
set b to trimStrFromTo(a, "{", "}")
    
set b to "{" & b & "}"
    
    
return b
  end recToString
  
  
  
on trimStrFromTo(aStr, fromStr, toStr)
    –fromStrは前から探す
    
if fromStr is not equal to "" then
      set sPos to (offset of fromStr in aStr) + 1
    else
      set sPos to 1
    end if
    
    
–toStrは後ろから探す
    
if toStr is not equal to "" then
      set b to (reverse of characters of aStr) as string
      
set ePos to (offset of toStr in b)
      
set ePos to ((length of aStr) – ePos)
    else
      set ePos to length of aStr
    end if
    
set aRes to text sPos thru ePos of aStr
    
    
return aRes
    
  end trimStrFromTo
  
  
  
–リストおよびリストに入ったレコードをStringに変換
  
  
on listToString(aList)
    set listText to {"{"}
    
set quotChar to ASCII character 34
    
set firstFlag to true
    
    
repeat with i in aList
      set j to contents of i
      
set aClass to (class of i) as string
      
if (aClass = "integer") or (aClass = "number") or (aClass = "real") or (aClass = "boolean") then
        set the end of listText to (getFirst(firstFlag) of me & j as text)
        
set firstFlag to false
      else if (aClass = "string") or (aClass = "text") or (aClass = "Unicode text") then
        set the end of listText to ((getFirst(firstFlag) of me & quotChar & j as text) & quotChar)
        
set firstFlag to false
      else if aClass is "list" then
        set the end of listText to (getFirst(firstFlag) & listToString(j)) –ちょっと再帰処理
        
set firstFlag to false
      else if aClass is "record" then
        set the end of listText to (getFirst(firstFlag) & recToString(j))
        
set firstFlag to false
      end if
    end repeat
    
    
set the end of listText to "}"
    
set listText to listText as text
    
    
return listText
  end listToString
  
  
on getFirst(aFlag)
    if aFlag = true then return ""
    
if aFlag = false then return ", "
  end getFirst
  
end script

★Click Here to Open This Script 

Posted in list Record Text | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy CotEditor | Leave a comment

AMChartsでバブルチャート+世界地図をダイアログ上に表示 v2

Posted on 6月 26, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを作成し、その上でAMChartsによるバブルチャートつき世界地図を表示するAppleScriptです。

–> Download amBubbleMap.zip(Script Bundle with AppleScript Library and HTML)

表示用のデータをAppleScriptのRecord(をListに入れたもの)に変換して、外部から供給するようにして、表示するさいにJSONに変換してHTMLに差し込んで表示しています。

正直、record形式にすると編集が大変なような気がするので、プログラムリスト中から外部に追い出して、plistとかJSONとかいろいろ他の形式で保持しておくといいと思います。もちろん、AppleScriptらしくNumbersの表データ中にデータを展開してもよいのですが、「ならNumbersでグラフ表示させたほうがよいのでは?」というところなので、あえて触れませんでした。

AMChart掲載のグラフはデータを差し込みやすくていいですね。

AppleScript名:AMChartsでバブルチャート+世界地図をダイアログ上に表示 v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/06/25
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use webD : script "webDialogLib"

set aList to retData() of me
set jStr to array2DToJSONArray(aList) of me as string

–https://www.zingchart.com/
set mePath to path to me
set resPath to (mePath as string) & "Contents:Resources:index.html"
set myStr to read (resPath as alias) as «class utf8»

set aString to current application’s NSString’s stringWithFormat_(myStr, jStr) as string

set paramObj to {myMessage:"Map with Bubbles", mySubMessage:"This is a AMCharts test", htmlStr:aString, jsDelimiters:{"<script>", "</script>"}, viewSize:{1000, 620}}

webD’s displayWebDialog(paramObj)

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value)
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

on retData()
  return {{|id|:"AF", |name|:"Afghanistan", value:32358260, |color|:"#ff0000"}, {|id|:"AL", |name|:"Albania", value:3215988, |color|:"#00ff00"}, {|id|:"DZ", |name|:"Algeria", value:35980193, |color|:"#0000ff"}, {|id|:"AO", |name|:"Angola", value:19618432, |color|:"#0000ff"}, {|id|:"AR", |name|:"Argentina", value:40764561, |color|:"#ffff00"}, {|id|:"AM", |name|:"Armenia", value:3100236, |color|:"#00ff00"}, {|id|:"AU", |name|:"Australia", value:22605732, |color|:"#8aabb0"}, {|id|:"AT", |name|:"Austria", value:8413429, |color|:"#00ff00"}, {|id|:"AZ", |name|:"Azerbaijan", value:9306023, |color|:"#00ff00"}, {|id|:"BH", |name|:"Bahrain", value:1323535, |color|:"#ff0000"}, {|id|:"BD", |name|:"Bangladesh", value:150493658, |color|:"#ff0000"}, {|id|:"BY", |name|:"Belarus", value:9559441, |color|:"#00ff00"}, {|id|:"BE", |name|:"Belgium", value:10754056, |color|:"#00ff00"}, {|id|:"BJ", |name|:"Benin", value:9099922, |color|:"#0000ff"}, {|id|:"BT", |name|:"Bhutan", value:738267, |color|:"#ff0000"}, {|id|:"BO", |name|:"Bolivia", value:10088108, |color|:"#ffff00"}, {|id|:"BA", |name|:"Bosnia and Herzegovina", value:3752228, |color|:"#00ff00"}, {|id|:"BW", |name|:"Botswana", value:2030738, |color|:"#0000ff"}, {|id|:"BR", |name|:"Brazil", value:196655014, |color|:"#ffff00"}, {|id|:"BN", |name|:"Brunei", value:405938, |color|:"#ff0000"}, {|id|:"BG", |name|:"Bulgaria", value:7446135, |color|:"#00ff00"}, {|id|:"BF", |name|:"Burkina Faso", value:16967845, |color|:"#0000ff"}, {|id|:"BI", |name|:"Burundi", value:8575172, |color|:"#0000ff"}, {|id|:"KH", |name|:"Cambodia", value:14305183, |color|:"#ff0000"}, {|id|:"CM", |name|:"Cameroon", value:20030362, |color|:"#0000ff"}, {|id|:"CA", |name|:"Canada", value:34349561, |color|:"#888822"}, {|id|:"CV", |name|:"Cape Verde", value:500585, |color|:"#0000ff"}, {|id|:"CF", |name|:"Central African Rep.", value:4486837, |color|:"#0000ff"}, {|id|:"TD", |name|:"Chad", value:11525496, |color|:"#0000ff"}, {|id|:"CL", |name|:"Chile", value:17269525, |color|:"#ffff00"}, {|id|:"CN", |name|:"China", value:1.347565324E+9, |color|:"#ff0000"}, {|id|:"CO", |name|:"Colombia", value:46927125, |color|:"#ffff00"}, {|id|:"KM", |name|:"Comoros", value:753943, |color|:"#0000ff"}, {|id|:"CD", |name|:"Congo, Dem. Rep.", value:67757577, |color|:"#0000ff"}, {|id|:"CG", |name|:"Congo, Rep.", value:4139748, |color|:"#0000ff"}, {|id|:"CR", |name|:"Costa Rica", value:4726575, |color|:"#888822"}, {|id|:"CI", |name|:"Cote d’Ivoire", value:20152894, |color|:"#0000ff"}, {|id|:"HR", |name|:"Croatia", value:4395560, |color|:"#00ff00"}, {|id|:"CU", |name|:"Cuba", value:11253665, |color|:"#888822"}, {|id|:"CY", |name|:"Cyprus", value:1116564, |color|:"#00ff00"}, {|id|:"CZ", |name|:"Czech Rep.", value:10534293, |color|:"#00ff00"}, {|id|:"DK", |name|:"Denmark", value:5572594, |color|:"#00ff00"}, {|id|:"DJ", |name|:"Djibouti", value:905564, |color|:"#0000ff"}, {|id|:"DO", |name|:"Dominican Rep.", value:10056181, |color|:"#888822"}, {|id|:"EC", |name|:"Ecuador", value:14666055, |color|:"#ffff00"}, {|id|:"EG", |name|:"Egypt", value:82536770, |color|:"#0000ff"}, {|id|:"SV", |name|:"El Salvador", value:6227491, |color|:"#888822"}, {|id|:"GQ", |name|:"Equatorial Guinea", value:720213, |color|:"#0000ff"}, {|id|:"ER", |name|:"Eritrea", value:5415280, |color|:"#0000ff"}, {|id|:"EE", |name|:"Estonia", value:1340537, |color|:"#00ff00"}, {|id|:"ET", |name|:"Ethiopia", value:84734262, |color|:"#0000ff"}, {|id|:"FJ", |name|:"Fiji", value:868406, |color|:"#8aabb0"}, {|id|:"FI", |name|:"Finland", value:5384770, |color|:"#00ff00"}, {|id|:"FR", |name|:"France", value:63125894, |color|:"#00ff00"}, {|id|:"GA", |name|:"Gabon", value:1534262, |color|:"#0000ff"}, {|id|:"GM", |name|:"Gambia", value:1776103, |color|:"#0000ff"}, {|id|:"GE", |name|:"Georgia", value:4329026, |color|:"#00ff00"}, {|id|:"DE", |name|:"Germany", value:82162512, |color|:"#00ff00"}, {|id|:"GH", |name|:"Ghana", value:24965816, |color|:"#0000ff"}, {|id|:"GR", |name|:"Greece", value:11390031, |color|:"#00ff00"}, {|id|:"GT", |name|:"Guatemala", value:14757316, |color|:"#888822"}, {|id|:"GN", |name|:"Guinea", value:10221808, |color|:"#0000ff"}, {|id|:"GW", |name|:"Guinea-Bissau", value:1547061, |color|:"#0000ff"}, {|id|:"GY", |name|:"Guyana", value:756040, |color|:"#ffff00"}, {|id|:"HT", |name|:"Haiti", value:10123787, |color|:"#888822"}, {|id|:"HN", |name|:"Honduras", value:7754687, |color|:"#888822"}, {|id|:"HK", |name|:"Hong Kong, China", value:7122187, |color|:"#ff0000"}, {|id|:"HU", |name|:"Hungary", value:9966116, |color|:"#00ff00"}, {|id|:"IS", |name|:"Iceland", value:324366, |color|:"#00ff00"}, {|id|:"IN", |name|:"India", value:1.24149196E+9, |color|:"#ff0000"}, {|id|:"ID", |name|:"Indonesia", value:242325638, |color|:"#ff0000"}, {|id|:"IR", |name|:"Iran", value:74798599, |color|:"#ff0000"}, {|id|:"IQ", |name|:"Iraq", value:32664942, |color|:"#ff0000"}, {|id|:"IE", |name|:"Ireland", value:4525802, |color|:"#00ff00"}, {|id|:"IL", |name|:"Israel", value:7562194, |color|:"#ff0000"}, {|id|:"IT", |name|:"Italy", value:60788694, |color|:"#00ff00"}, {|id|:"JM", |name|:"Jamaica", value:2751273, |color|:"#888822"}, {|id|:"JP", |name|:"Japan", value:126497241, |color|:"#ff0000"}, {|id|:"JO", |name|:"Jordan", value:6330169, |color|:"#ff0000"}, {|id|:"KZ", |name|:"Kazakhstan", value:16206750, |color|:"#ff0000"}, {|id|:"KE", |name|:"Kenya", value:41609728, |color|:"#0000ff"}, {|id|:"KP", |name|:"Korea, Dem. Rep.", value:24451285, |color|:"#ff0000"}, {|id|:"KR", |name|:"Korea, Rep.", value:48391343, |color|:"#ff0000"}, {|id|:"KW", |name|:"Kuwait", value:2818042, |color|:"#ff0000"}, {|id|:"KG", |name|:"Kyrgyzstan", value:5392580, |color|:"#ff0000"}, {|id|:"LA", |name|:"Laos", value:6288037, |color|:"#ff0000"}, {|id|:"LV", |name|:"Latvia", value:2243142, |color|:"#00ff00"}, {|id|:"LB", |name|:"Lebanon", value:4259405, |color|:"#ff0000"}, {|id|:"LS", |name|:"Lesotho", value:2193843, |color|:"#0000ff"}, {|id|:"LR", |name|:"Liberia", value:4128572, |color|:"#0000ff"}, {|id|:"LY", |name|:"Libya", value:6422772, |color|:"#0000ff"}, {|id|:"LT", |name|:"Lithuania", value:3307481, |color|:"#00ff00"}, {|id|:"LU", |name|:"Luxembourg", value:515941, |color|:"#00ff00"}, {|id|:"MK", |name|:"Macedonia, FYR", value:2063893, |color|:"#00ff00"}, {|id|:"MG", |name|:"Madagascar", value:21315135, |color|:"#0000ff"}, {|id|:"MW", |name|:"Malawi", value:15380888, |color|:"#0000ff"}, {|id|:"MY", |name|:"Malaysia", value:28859154, |color|:"#ff0000"}, {|id|:"ML", |name|:"Mali", value:15839538, |color|:"#0000ff"}, {|id|:"MR", |name|:"Mauritania", value:3541540, |color|:"#0000ff"}, {|id|:"MU", |name|:"Mauritius", value:1306593, |color|:"#0000ff"}, {|id|:"MX", |name|:"Mexico", value:114793341, |color|:"#888822"}, {|id|:"MD", |name|:"Moldova", value:3544864, |color|:"#00ff00"}, {|id|:"MN", |name|:"Mongolia", value:2800114, |color|:"#ff0000"}, {|id|:"ME", |name|:"Montenegro", value:632261, |color|:"#00ff00"}, {|id|:"MA", |name|:"Morocco", value:32272974, |color|:"#0000ff"}, {|id|:"MZ", |name|:"Mozambique", value:23929708, |color|:"#0000ff"}, {|id|:"MM", |name|:"Myanmar", value:48336763, |color|:"#ff0000"}, {|id|:"NA", |name|:"Namibia", value:2324004, |color|:"#0000ff"}, {|id|:"NP", |name|:"Nepal", value:30485798, |color|:"#ff0000"}, {|id|:"NL", |name|:"Netherlands", value:16664746, |color|:"#00ff00"}, {|id|:"NZ", |name|:"New Zealand", value:4414509, |color|:"#8aabb0"}, {|id|:"NI", |name|:"Nicaragua", value:5869859, |color|:"#888822"}, {|id|:"NE", |name|:"Niger", value:16068994, |color|:"#0000ff"}, {|id|:"NG", |name|:"Nigeria", value:162470737, |color|:"#0000ff"}, {|id|:"NO", |name|:"Norway", value:4924848, |color|:"#00ff00"}, {|id|:"OM", |name|:"Oman", value:2846145, |color|:"#ff0000"}, {|id|:"PK", |name|:"Pakistan", value:176745364, |color|:"#ff0000"}, {|id|:"PA", |name|:"Panama", value:3571185, |color|:"#888822"}, {|id|:"PG", |name|:"Papua New Guinea", value:7013829, |color|:"#8aabb0"}, {|id|:"PY", |name|:"Paraguay", value:6568290, |color|:"#ffff00"}, {|id|:"PE", |name|:"Peru", value:29399817, |color|:"#ffff00"}, {|id|:"PH", |name|:"Philippines", value:94852030, |color|:"#ff0000"}, {|id|:"PL", |name|:"Poland", value:38298949, |color|:"#00ff00"}, {|id|:"PT", |name|:"Portugal", value:10689663, |color|:"#00ff00"}, {|id|:"PR", |name|:"Puerto Rico", value:3745526, |color|:"#888822"}, {|id|:"QA", |name|:"Qatar", value:1870041, |color|:"#ff0000"}, {|id|:"RO", |name|:"Romania", value:21436495, |color|:"#00ff00"}, {|id|:"RU", |name|:"Russia", value:142835555, |color|:"#00ff00"}, {|id|:"RW", |name|:"Rwanda", value:10942950, |color|:"#0000ff"}, {|id|:"SA", |name|:"Saudi Arabia", value:28082541, |color|:"#ff0000"}, {|id|:"SN", |name|:"Senegal", value:12767556, |color|:"#0000ff"}, {|id|:"RS", |name|:"Serbia", value:9853969, |color|:"#00ff00"}, {|id|:"SL", |name|:"Sierra Leone", value:5997486, |color|:"#0000ff"}, {|id|:"SG", |name|:"Singapore", value:5187933, |color|:"#ff0000"}, {|id|:"SK", |name|:"Slovak Republic", value:5471502, |color|:"#00ff00"}, {|id|:"SI", |name|:"Slovenia", value:2035012, |color|:"#00ff00"}, {|id|:"SB", |name|:"Solomon Islands", value:552267, |color|:"#8aabb0"}, {|id|:"SO", |name|:"Somalia", value:9556873, |color|:"#0000ff"}, {|id|:"ZA", |name|:"South Africa", value:50459978, |color|:"#0000ff"}, {|id|:"ES", |name|:"Spain", value:46454895, |color|:"#00ff00"}, {|id|:"LK", |name|:"Sri Lanka", value:21045394, |color|:"#ff0000"}, {|id|:"SD", |name|:"Sudan", value:34735288, |color|:"#0000ff"}, {|id|:"SR", |name|:"Suriname", value:529419, |color|:"#ffff00"}, {|id|:"SZ", |name|:"Swaziland", value:1203330, |color|:"#0000ff"}, {|id|:"SE", |name|:"Sweden", value:9440747, |color|:"#00ff00"}, {|id|:"CH", |name|:"Switzerland", value:7701690, |color|:"#00ff00"}, {|id|:"SY", |name|:"Syria", value:20766037, |color|:"#ff0000"}, {|id|:"TW", |name|:"Taiwan", value:23072000, |color|:"#ff0000"}, {|id|:"TJ", |name|:"Tajikistan", value:6976958, |color|:"#ff0000"}, {|id|:"TZ", |name|:"Tanzania", value:46218486, |color|:"#0000ff"}, {|id|:"TH", |name|:"Thailand", value:69518555, |color|:"#ff0000"}, {|id|:"TG", |name|:"Togo", value:6154813, |color|:"#0000ff"}, {|id|:"TT", |name|:"Trinidad and Tobago", value:1346350, |color|:"#888822"}, {|id|:"TN", |name|:"Tunisia", value:10594057, |color|:"#0000ff"}, {|id|:"TR", |name|:"Turkey", value:73639596, |color|:"#00ff00"}, {|id|:"TM", |name|:"Turkmenistan", value:5105301, |color|:"#ff0000"}, {|id|:"UG", |name|:"Uganda", value:34509205, |color|:"#0000ff"}, {|id|:"UA", |name|:"Ukraine", value:45190180, |color|:"#00ff00"}, {|id|:"AE", |name|:"United Arab Emirates", value:7890924, |color|:"#ff0000"}, {|id|:"GB", |name|:"United Kingdom", value:62417431, |color|:"#00ff00"}, {|id|:"US", |name|:"United States", value:313085380, |color|:"#888822"}, {|id|:"UY", |name|:"Uruguay", value:3380008, |color|:"#ffff00"}, {|id|:"UZ", |name|:"Uzbekistan", value:27760267, |color|:"#ff0000"}, {|id|:"VE", |name|:"Venezuela", value:29436891, |color|:"#ffff00"}, {|id|:"PS", |name|:"West Bank and Gaza", value:4152369, |color|:"#ff0000"}, {|id|:"VN", |name|:"Vietnam", value:88791996, |color|:"#ff0000"}, {|id|:"YE", |name|:"Yemen, Rep.", value:24799880, |color|:"#ff0000"}, {|id|:"ZM", |name|:"Zambia", value:13474959, |color|:"#0000ff"}, {|id|:"ZW", |name|:"Zimbabwe", value:12754378, |color|:"#0000ff"}}
end retData

★Click Here to Open This Script 

Posted in dialog list Record | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy NSJSONSerialization NSMutableArray NSString | Leave a comment

アラートダイアログ上にTable Viewを表示 v5_複数キー抽出つき

Posted on 12月 23, 2019 by Takaaki Naganoya

アラートダイアログ上にTableViewを表示し、複数キーの組み合わせによって項目抽出。選択項目のデータを返すAppleScriptです。

あくまで試作品なので、あちらこちらに「お可愛らしい」実装が転がっています。NSBoxがまだまともに使いこなせていないあたりとか(Xcode上で部品として配置するのは楽勝ですが、プログラムから動的に生成して使用するのは別なので)。

抽出キー数は可変で外部から指定できるとよいのですが、本Scriptでは固定です。また、各抽出条件も外部から供給するのが本来あるべき姿ですが、ハードコーディングしています。

あと、TableViewの下側に謎の余白があるのは、めんどくさくなってそのまま放置しています。これで外部から各種パラメータを指定できるようにして、sdefつけて1命令で呼び出せるようにしておけば、レコード数の多い選択項目から条件抽出しつつ項目選択できてよいでしょう。

プログラム内容自体は、高度でもなければ高尚でもありません。実にダラダラとGUI部品のパラメータを設定しているだけです。

AppleScript名:アラートダイアログ上にTable Viewを表示 v5_複数キー抽出つき
— Created 2019-12-22 by Takaaki Naganoya
— 2019 Piyomaru Software
set aRes to displayCondTable() of filterTableDialogView
–> {field3:"3.0GHz 6コア Intel Core i5(Turbo Boost使用時最大4.1GHz)", field2:198800, field1:"iMac 5K 27"}

script filterTableDialogView
  use scripting additions
  
use framework "Foundation"
  
use framework "AppKit"
  
property parent : AppleScript
  
  
property NSBox : a reference to current application’s NSBox
  
property NSView : a reference to current application’s NSView
  
property NSAlert : a reference to current application’s NSAlert
  
property NSColor : a reference to current application’s NSColor
  
property NSIndexSet : a reference to current application’s NSIndexSet
  
property NSPredicate : a reference to current application’s NSPredicate
  
property NSScrollView : a reference to current application’s NSScrollView
  
property NSTableView : a reference to current application’s NSTableView
  
property NSTableColumn : a reference to current application’s NSTableColumn
  
property NSPopUpButton : a reference to current application’s NSPopUpButton
  
property NSMutableArray : a reference to current application’s NSMutableArray
  
property NSRunningApplication : a reference to current application’s NSRunningApplication
  
property NSCompoundPredicate : a reference to current application’s NSCompoundPredicate
  
property NSModalPanelWindowLevel : a reference to current application’s NSModalPanelWindowLevel
  
property NSAlertSecondButtonReturn : a reference to current application’s NSAlertSecondButtonReturn
  
  
  
property theResult : 0
  
property returnCode : 0
  
property theDataSource : {}
  
property tView : missing value
  
property aDataList : {}
  
property aSel : 0
  
property bSel : 0
  
property cSel : 0
  
property predList : {}
  
property a1Button : missing value
  
property a2Button : missing value
  
property a3Button : missing value
  
  
on displayCondTable()
    set (my theResult) to 0 –initialize
    
    
set aDataList to {{field1:"MacBook Air", field2:119800, field3:"1.6GHzデュアルコアIntel Core i5(Turbo Boost使用時最大3.6GHz)、4MB L3キャッシュ"}, {field1:"MacBook Pro 13", field2:139800, field3:"1.4GHzクアッドコアIntel Core i5(Turbo Boost使用時最大3.9GHz)、128MB eDRAM"}, {field1:"MacBook Pro 15", field2:258800, field3:"2.6GHz 6コアIntel Core i7(Turbo Boost使用時最大4.5GHz)、12MB共有L3キャッシュ"}, {field1:"Mac mini", field2:122800, field3:"3.0GHz 6コアIntel Core i5 Turbo Boost使用時最大4.1GHz 9MB共有L3キャッシュ"}, {field1:"iMac 21.5", field2:120800, field3:"2.3GHzデュアルコアIntel Core i5(Turbo Boost使用時最大3.6GHz)"}, {field1:"iMac 4K 21.5", field2:142800, field3:"3.6GHzクアッドコアIntel Core i3"}, {field1:"iMac 5K 27", field2:198800, field3:"3.0GHz 6コア Intel Core i5(Turbo Boost使用時最大4.1GHz)"}, {field1:"iMac Pro", field2:558800, field3:"3.2GHz Intel Xeon W Turbo Boost使用時最大4.2GHz 19MBキャッシュ"}, {field1:"Mac Pro 2019", field2:599800, field3:"3.5GHz 8コアIntel Xeon Wプロセッサ(Turbo Boost使用時最大4.0GHz)"}}
    
    
set paramObj to {myMessage:"項目の選択", mySubMessage:"適切なものを以下からえらんでください", aTableList:aDataList, aSortOrder:{"field1", "field2", "field3"}}
    
    
–my chooseItemByTableView:paramObj –for debug
    
my performSelectorOnMainThread:"chooseItemByTableView:" withObject:paramObj waitUntilDone:true
    
    
return (my theResult)
  end displayCondTable
  
  
on chooseItemByTableView:paramObj
    set aMainMes to myMessage of paramObj
    
set aSubMes to mySubMessage of paramObj
    
set aTList to (aTableList of paramObj) as list
    
set labelSortList to (aSortOrder of paramObj) as list
    
    
set aWidth to 800
    
set aHeight to 400
    
set my aSel to 0
    
set my bSel to 0
    
    
–Viewをつくる
    
set parentView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
    
    
    
–BOX Aをつくる
    
set aBox to (NSBox’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aHeight – 60, aWidth, 60)))
    (
aBox’s setTitle:("Filter Condition"))
    
    
–このあたり、項目数に合わせてUIを可変で生成するように(本Scriptは試作品なので、決め打ちでUI生成)
    
set a1Button to (NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 200, 30)) pullsDown:false)
    
a1Button’s removeAllItems()
    (
a1Button’s addItemsWithTitles:{"▼Select Item", "MacBook", "iMac", "mini", "Air", "Pro"})
    
a1Button’s setTarget:(me)
    
a1Button’s setAction:("mySelector:")
    
a1Button’s setEnabled:(true)
    
    
set a2Button to (NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(220, 0, 200, 30)) pullsDown:false)
    
a2Button’s removeAllItems()
    (
a2Button’s addItemsWithTitles:{"▼Select Item", "150000", "200000", "300000", "400000", "600000"})
    
a2Button’s setTarget:(me)
    
a2Button’s setAction:("mySelector:")
    
a2Button’s setEnabled:(true)
    
    
set a3Button to (NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(440, 0, 200, 30)) pullsDown:false)
    
a3Button’s removeAllItems()
    (
a3Button’s addItemsWithTitles:{"▼Select Item", "デュアルコア", "クアッドコア", "6コア", "8コア"})
    
a3Button’s setTarget:(me)
    
a3Button’s setAction:("mySelector:")
    
a3Button’s setEnabled:(true)
    
    
    (
aBox’s addSubview:a1Button)
    (
aBox’s addSubview:a2Button)
    (
aBox’s addSubview:a3Button)
    
    
    
–BOX Bをつくる
    
set bBox to (NSBox’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight – 80)))
    (
bBox’s setTitle:("Data"))
    
    
set aScroll to makeTableView(aTList, aWidth, aHeight – 150, labelSortList) of me
    
    (
bBox’s addSubview:aScroll)
    
    
parentView’s setSubviews:{aBox, bBox}
    
    
— set up alert  
    
set theAlert to NSAlert’s alloc()’s init()
    
tell theAlert
      its setMessageText:aMainMes
      
its setInformativeText:aSubMes
      
its addButtonWithTitle:"OK"
      
its addButtonWithTitle:"Cancel"
      
its setAccessoryView:(parentView)
      
      
set myWindow to its |window|
    end tell
    
    
myWindow’s setLevel:(NSModalPanelWindowLevel)
    
    
— show alert in modal loop
    
NSRunningApplication’s currentApplication()’s activateWithOptions:0
    
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
    
if (my returnCode) = 1001 then error number -128
    
    
set tmpResult to (aScroll’s documentView’s selectedRow()) + 1
    
set (my theResult) to contents of item tmpResult of ((my theDataSource) as list)
  end chooseItemByTableView:
  
  
  
on doModal:aParam
    set (my returnCode) to (aParam’s runModal()) as number
  end doModal:
  
  
  
  
  
–TableView Event Handlers
  
on numberOfRowsInTableView:aView
    return (my theDataSource)’s |count|()
  end numberOfRowsInTableView:
  
  
on tableView:aView objectValueForTableColumn:aColumn row:aRow
    set aRec to (my theDataSource)’s objectAtIndex:(aRow as number)
    
set aTitle to (aColumn’s headerCell()’s title()) as string
    
set aRes to (aRec’s valueForKey:aTitle)
    
return aRes
  end tableView:objectValueForTableColumn:row:
  
  
  
  
on makeTableView(aDicList, aWidth, aHeight, labelSortList)
    set aOffset to 40
    
set theDataSource to NSMutableArray’s alloc()’s init()
    
theDataSource’s addObjectsFromArray:aDicList
    
    
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aOffset, aWidth, aHeight))
    
set tView to NSTableView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aOffset, aWidth, aHeight))
    
    
set aLen to length of labelSortList
    
    
repeat with i in labelSortList
      set j to contents of i
      
set aColumn to (NSTableColumn’s alloc()’s initWithIdentifier:j)
      (
aColumn’s setWidth:(aWidth div aLen))
      (
aColumn’s headerCell()’s setStringValue:j)
      (
tView’s addTableColumn:aColumn)
    end repeat
    
    
tView’s setDelegate:me
    
tView’s setDataSource:me
    
tView’s reloadData()
    
    
aScroll’s setDocumentView:tView
    
tView’s enclosingScrollView()’s setHasVerticalScroller:true
    
aScroll’s setVerticalLineScroll:(30.0 as real)
    
    
–1行目を選択
    
set aIndexSet to NSIndexSet’s indexSetWithIndex:0
    
tView’s selectRowIndexes:aIndexSet byExtendingSelection:false
    
    
–強制的にトップにスクロール
    
set aDBounds to aScroll’s documentView()’s |bounds|()
    
if class of aDBounds = list then
      –macOS 10.13 or later
      
set maxHeight to item 2 of item 1 of aDBounds
    else
      –macOS 10.10….10.12
      
set maxHeight to height of |size| of aDBounds
    end if
    
    
set aPT to current application’s NSMakePoint(0.0, -1 * (maxHeight as real))
    
aScroll’s documentView()’s scrollPoint:aPT
    
    
return aScroll
  end makeTableView
  
  
  
on alertShowHelp:aNotification
    display dialog "Help Me!" buttons {"OK"} default button 1 with icon 1
    
return false –trueを返すと親ウィンドウ(アラートダイアログ)がクローズする
  end alertShowHelp:
  
  
  
on mySelector:aObject
    set aIndex to (aObject’s indexOfSelectedItem()) as number
    
filterByMultipleCondition() of me
  end mySelector:
  
  
  
  
on filterByMultipleCondition()
    set prediCatesArray to {}
    
    
set aInd to (my a1Button’s indexOfSelectedItem()) as number
    
set bInd to (my a2Button’s indexOfSelectedItem()) as number
    
set cInd to (my a3Button’s indexOfSelectedItem()) as number
    
    
if {aInd, bInd, cInd} = {0, 0, 0} then
      set (my theDataSource) to NSMutableArray’s arrayWithArray:(my aDataList)
      
tView’s reloadData()
      
return
    end if
    
    
–このあたり、複数条件をハードコーディングしているのは超絶頭悪い。項目数の増減に対応できるべき
    
if aInd > 0 then
      set aTitle to (my a1Button’s title()) as string
      
set the end of prediCatesArray to "field1 contains ’" & aTitle & "’"
    end if
    
    
if bInd > 0 then
      set bTitle to (my a2Button’s title()) as string
      
set the end of prediCatesArray to "field2.integerValue < " & bTitle
    end if
    
    
if cInd > 0 then
      set cTitle to (my a3Button’s title()) as string
      
set the end of prediCatesArray to "field3 contains ’" & cTitle & "’"
    end if
    
    
–データ 抽出
    
set tmpList to filterDictArrayByLabel3((my aDataList), prediCatesArray) of me
    
    
–データ 再表示
    
set (my theDataSource) to NSMutableArray’s arrayWithArray:(tmpList)
    
tView’s reloadData()
  end filterByMultipleCondition
  
  
  
  
–リストに入れたレコードを、指定の属性ラベルの値で抽出(複数PredicatesをANDで合成)
  
on filterDictArrayByLabel3(origArray as list, aPredicateList as list)
    set aArray to NSMutableArray’s arrayWithArray:origArray
    
set predArray to NSMutableArray’s new()
    
    
repeat with i in aPredicateList
      (predArray’s addObject:(NSPredicate’s predicateWithFormat:(contents of i)))
    end repeat
    
    
set pred to current application’s NSCompoundPredicate’s andPredicateWithSubpredicates:predArray
    
set filteredArray to aArray’s filteredArrayUsingPredicate:pred
    
    
return filteredArray
  end filterDictArrayByLabel3
end script

★Click Here to Open This Script 

Posted in dialog GUI list Record search | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSAlertSecondButtonReturn NSBox NSColor NSCompoundPredicate NSIndexSet NSModalPanelWindowLevel NSMutableArray NSPopUpButton NSPredicate NSRunningApplication NSScrollView NSTableColumn NSTableView NSView | 1 Comment

ジャンル名名寄せ v2

Posted on 11月 27, 2019 by Takaaki Naganoya

iTunes/Musicのライブラリに入っている楽曲データのジャンル分けのゆらぎ吸収を行う、ジャンル名のいわゆる「名寄せ」を行うAppleScriptです。


▲1つのアルバム中でもジャンル名に表記ゆれがあるのは勘弁してほしい

iTunes/Musicライブラリ中の全楽曲の最終再生日時を24時間の各時で集計を行い、ジャンルごとに再生時間に偏りがないかどうかを分析するため、さらにジャンルごろに集計してみました。

「名寄せ」(なよせ)は昔から情報処理に見られる泥臭い地道な処理で、データ上の表記ゆれを吸収するための処理です。地名などの固有名詞で多く見られます(念のためにWikipediaで調べたら、異なる業界では割とブラックな言葉として用いられている模様)。

このジャンル名が英語で入っていたり日本語で入っていたりと、ゆらぎが発生しているので、同様のジャンル名であれば同じものとして合算して集計してみました。

また、英語で表記されたジャンル名ではなく日本語で表記されたものを採用(=すべてアルファベットで書かれたものを不採用)しています。まだ、それほどいじめ抜いていない(自分の環境でしかテストしていない)ので、ジャンル名の名寄せリストはもう少し鍛えておく必要があるものと思っています。

AppleScript名:ジャンル名名寄せ v2
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/24
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5" — El Capitan (10.11) or later
use framework "Foundation"
use scripting additions

property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSScanner : a reference to current application’s NSScanner
property NSPredicate : a reference to current application’s NSPredicate
property NSMutableCharacterSet : a reference to current application’s NSMutableCharacterSet

–ジャンル名寄せリスト(2要素から構成される2D List)
set genreNayoseList to {{"World", "ワールド"}, {"Anime", "アニメ"}, {"Electronic", "エレクトロニック"}, {"R&B/ソウル", "R&B/ソウル"}, {"Kayokyoku", "歌謡曲"}, {"Electronic", "エレクトロニック"}, {"Vocal", "ヴォーカル"}, {"Classical", "クラシック"}, {"Dance", "ダンス"}, {"Soundtrack", "サウンドトラック"}}

–名寄せ対象リスト(genreNameを名寄せ)
set aList to {{genreName:"シンガーソングライター", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 0, 0, 0, 1, 5, 0, 0, 0, 0}}, {genreName:"ロック", playingList:{2, 2, 0, 0, 0, 1, 0, 0, 4, 3, 9, 5, 11, 11, 22, 19, 48, 17, 28, 15, 2, 11, 13, 1}}, {genreName:"Soundtrack", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, {genreName:"World", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, {genreName:"演歌", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"ホリデーミュージック", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"ディズニー", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0}}, {genreName:"J-Pop", playingList:{4, 0, 1, 1, 2, 1, 5, 3, 2, 3, 27, 19, 14, 26, 17, 20, 28, 32, 40, 25, 10, 10, 6, 6}}, {genreName:"ヒップホップ/ ラップ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"Electronic", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"アニメ", playingList:{7, 1, 0, 0, 7, 2, 0, 0, 0, 9, 23, 45, 17, 10, 17, 50, 48, 65, 53, 27, 12, 16, 23, 45}}, {genreName:"ポップ", playingList:{3, 0, 0, 0, 0, 0, 0, 3, 1, 6, 2, 9, 7, 0, 11, 7, 8, 10, 7, 5, 3, 1, 0, 1}}, {genreName:"Kayokyoku", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}}, {genreName:"ヒップホップ/ラップ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"Dance", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}}, {genreName:"ダンス", playingList:{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 2, 0, 0}}, {genreName:"R&B/ソウル", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"Anime", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0}}, {genreName:"チルドレン・ミュージック", playingList:{0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"Classical", playingList:{1, 1, 0, 0, 2, 1, 8, 1, 0, 0, 11, 5, 2, 0, 4, 9, 13, 2, 2, 0, 0, 0, 0, 0}}, {genreName:"ニューエイジ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 12, 0, 0, 0, 0}}, {genreName:"Pop", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, {genreName:"ヴォーカル", playingList:{0, 0, 0, 0, 0, 1, 0, 0, 0, 6, 7, 0, 0, 1, 6, 0, 0, 3, 1, 0, 3, 0, 0, 0}}, {genreName:"サウンドトラック", playingList:{23, 31, 0, 0, 0, 2, 1, 0, 7, 7, 27, 29, 26, 25, 28, 48, 66, 76, 56, 16, 8, 31, 6, 10}}, {genreName:"歌謡曲", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 2, 4, 5, 5, 4, 6, 6, 7, 1, 0, 0, 0}}, {genreName:"ホリデー", playingList:{0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0}}, {genreName:"Folk", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}}, {genreName:"ジャズ", playingList:{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 16, 7, 3, 9, 0, 5, 10, 20, 10, 2, 1, 0, 0}}, {genreName:"エレクトロニック", playingList:{0, 1, 3, 0, 0, 0, 0, 1, 4, 13, 8, 13, 2, 18, 6, 13, 10, 16, 25, 7, 8, 0, 2, 10}}, {genreName:"ワールド", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 5, 5, 7, 6, 0, 0, 0, 0, 0}}, {genreName:"インストゥルメンタル", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}}, {genreName:"Vocal", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"クラシック", playingList:{0, 0, 1, 1, 0, 3, 2, 0, 4, 3, 13, 11, 24, 1, 21, 14, 24, 38, 21, 7, 5, 8, 4, 5}}, {genreName:"オルタナティブ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 1, 0, 0, 6, 9, 0}}, {genreName:"R&B/ソウル", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}

set bList to genreNayoseAndUnify(aList, genreNayoseList) of me
–> {{genreName:"シンガーソングライター", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 0, 0, 0, 1, 5, 0, 0, 0, 0}}, {genreName:"ロック", playingList:{2, 2, 0, 0, 0, 1, 0, 0, 4, 3, 9, 5, 11, 11, 22, 19, 48, 17, 28, 15, 2, 11, 13, 1}}, {genreName:"サウンドトラック", playingList:{23, 31, 0, 0, 0, 2, 1, 0, 7, 7, 28, 29, 26, 25, 28, 48, 66, 77, 56, 16, 8, 31, 6, 10}}, {genreName:"ワールド", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 5, 5, 8, 6, 0, 0, 0, 0, 0}}, {genreName:"演歌", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"ホリデーミュージック", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"ディズニー", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0}}, {genreName:"J-Pop", playingList:{4, 0, 1, 1, 2, 1, 5, 3, 2, 3, 27, 19, 14, 26, 17, 20, 28, 32, 40, 25, 10, 10, 6, 6}}, {genreName:"ヒップホップ/ ラップ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"エレクトロニック", playingList:{0, 1, 3, 0, 0, 0, 0, 1, 4, 13, 8, 13, 2, 19, 6, 13, 10, 16, 25, 7, 8, 0, 2, 10}}, {genreName:"アニメ", playingList:{7, 1, 0, 0, 7, 2, 0, 0, 0, 9, 23, 52, 17, 10, 17, 50, 49, 67, 54, 27, 12, 16, 23, 45}}, {genreName:"ポップ", playingList:{3, 0, 0, 0, 0, 0, 0, 3, 1, 6, 2, 9, 7, 0, 11, 7, 8, 10, 7, 5, 3, 1, 0, 1}}, {genreName:"歌謡曲", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 2, 4, 5, 5, 4, 6, 7, 7, 1, 0, 0, 0}}, {genreName:"ヒップホップ/ラップ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"ダンス", playingList:{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0}}, {genreName:"R&B/ソウル", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"チルドレン・ミュージック", playingList:{0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"クラシック", playingList:{1, 1, 1, 1, 2, 4, 10, 1, 4, 3, 24, 16, 26, 1, 25, 23, 37, 40, 23, 7, 5, 8, 4, 5}}, {genreName:"ニューエイジ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 12, 0, 0, 0, 0}}, {genreName:"Pop", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, {genreName:"ヴォーカル", playingList:{0, 0, 0, 0, 0, 1, 0, 0, 0, 6, 7, 0, 0, 1, 6, 1, 0, 3, 1, 0, 3, 0, 0, 0}}, {genreName:"ホリデー", playingList:{0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0}}, {genreName:"Folk", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}}, {genreName:"ジャズ", playingList:{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 16, 7, 3, 9, 0, 5, 10, 20, 10, 2, 1, 0, 0}}, {genreName:"インストゥルメンタル", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}}, {genreName:"オルタナティブ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 1, 0, 0, 6, 9, 0}}}

on genreNayoseAndUnify(aList as list, genreNayoseList as list)
  set gList to FlattenList(genreNayoseList) of me
  
  
set didProc to {}
  
  
set a2List to {}
  
  
repeat with i in aList
    set aGenre to genreName of i
    
    
if (aGenre is in gList) and (aGenre is not in didProc) then
      
      
repeat with ii in genreNayoseList
        set jj to contents of ii
        
        
if aGenre is in jj then
          copy jj to {g1, g2}
          
          
          
if chkAlphabet(g1) of me = true then
            set targG to g2
            
set targG2 to g1
          else
            set targG to g1
            
set targG2 to g2
          end if
          
          
set s1Res to searchByGenreName(aList, targG) of me
          
set s2Res to searchByGenreName(aList, targG2) of me
          
          
set s3Res to addMutipleLists({s1Res, s2Res}) of me
          
          
set outRec to {genreName:targG, playingList:s3Res}
          
set the end of didProc to g1
          
set the end of didProc to g2
          
          
exit repeat
        end if
        
      end repeat
      
      
set the end of a2List to outRec
    else
      if (aGenre is not in didProc) then
        set the end of a2List to contents of i
      end if
    end if
  end repeat
  
  
return a2List
end genreNayoseAndUnify

on searchByGenreName(aList as list, aGenreName as string)
  set predicatesStr to "genreName == ’" & aGenreName & "’"
  
set anArray to (NSArray’s arrayWithArray:aList)
  
set aPred to (NSPredicate’s predicateWithFormat:predicatesStr)
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred)
  
  
set bbRes to first item of bRes
  
return (playingList of bbRes) as list
end searchByGenreName

on addMutipleLists(s1List)
  script spdAdd
    property s1List : {}
    
property s3List : {}
  end script
  
  
copy s1List to (s1List of spdAdd) –init
  
  
set s1Len to length of first item of (s1List of spdAdd)
  
set (s3List of spdAdd) to makeZero1DList(s1Len, 0) of me
  
  
repeat with i in (s1List of spdAdd)
    set tmpLen to length of i
    
if tmpLen is not equal to s1Len then return false
    
    
repeat with ii from 1 to s1Len
      set tmp1 to contents of item ii of (s3List of spdAdd)
      
set tmp2 to contents of item ii of i
      
      
set item ii of (s3List of spdAdd) to (tmp1 + tmp2)
    end repeat
  end repeat
  
  
return (s3List of spdAdd)
end addMutipleLists

–指定要素を指定回数追加したリストを作成する
on makeZero1DList(itemMax, itemElem)
  set allData to {}
  
repeat itemMax times
    set the end of allData to itemElem
  end repeat
  
return allData
end makeZero1DList

–By Paul Berkowitz
–2009年1月27日 2:24:08:JST
–Re: Flattening Nested Lists
on FlattenList(aList)
  set oldDelims to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to {"????"}
  
set aString to aList as text
  
set aList to text items of aString
  
set AppleScript’s text item delimiters to oldDelims
  
return aList
end FlattenList

— アルファベットのみか調べて返す
on chkAlphabet(checkString)
  set aStr to NSString’s stringWithString:checkString
  
set allCharSet to NSMutableCharacterSet’s alloc()’s init()
  
allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "a", 26))
  
allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "A", 26))
  
set aBool to my chkCompareString:aStr baseString:allCharSet
  
return aBool as boolean
end chkAlphabet

on chkCompareString:checkString baseString:baseString
  set aScanner to NSScanner’s localizedScannerWithString:checkString
  
aScanner’s setCharactersToBeSkipped:(missing value)
  
aScanner’s scanCharactersFromSet:baseString intoString:(missing value)
  
return (aScanner’s isAtEnd()) as boolean
end chkCompareString:baseString:

★Click Here to Open This Script 

Posted in list Record | Tagged 10.13savvy 10.14savvy 10.15savvy NSArray NSMutableCharacterSet NSPredicate NSScanner NSString | Leave a comment

Safariで現在見えている表を抽出してCSV書き出しv3

Posted on 10月 8, 2019 by Takaaki Naganoya

Safariの最前面のウィンドウで表示中のページのうち、現在ウィンドウ内に表示中の表要素をCSV書き出ししてNumbersでオープンするAppleScriptの改良版です。HTMLのtable中にrowspan(複数セルを行方向に連結)とcolspan(複数セルを列方向に連結)の属性値が指定されていた場合に対応します。

–> Download table2CSV_visibleonly_v2 (Code-Signed AppleScript applet with Framework and Library in its bundle)

各DOM ElementsのWebコンテンツ中の表示座標を取得して、絞り込みを行なっています。ただし、各DOM座標はWebブラウザのスクロールにしたがって数値が変わる(相対座標)ため、少々手こずりました。また、本Scriptでは上下スクロールのみ考慮してDOM要素の抽出を行なっており、横に長いページの横方向スクロールは考慮しておりません。

このバージョンではrowspan / colspanへの対処を追加しました。

行単位で(1次元配列ベースで)表を作っていてはとても対処できなかったので、HTMLの表と同じセル数のヌル文字が入った2次元配列を作成し、そこにX座標/Y座標を指定してセルを埋めるように処理内容を変更しました。また、rowspan/colspanの属性を見つけた場合には、結合されていた複数セルを個別の(同じ値を入れた)セルに分解しています。

本バージョンでは、1つのセル(td)でrowspanとcolspanを同時に指定しないことが処理の前提条件となっています。また、一番上の行がヘッダーの場合を想定しており、一番左の列がヘッダーになっているケースには対処しておりません。

AppleScript名:Safariで現在見えている表を抽出してCSV書き出しv3.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/09/22
–  Modified on: 2019/10/07
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader
use aLib : script "arrayLib"

property NSUUID : a reference to current application’s NSUUID
property NSString : a reference to current application’s NSString
property HTMLDocument : a reference to current application’s HTMLDocument
property NSMutableArray : a reference to current application’s NSMutableArray
property NSJSONSerialization : a reference to current application’s NSJSONSerialization

set aTag to "table"

set indRes to getVisibleElementIndexList(aTag) of me
if indRes = false or indRes = {} then
  display notification "No Visible Table in Web browser"
  
return
end if

tell application "Safari"
  tell front document
    set aSource to source
  end tell
end tell

repeat with i in indRes
  set inList to filterATableAndPaseCells(aSource, i, aTag) of me
  
  
if inList = false or inList = {} then return
  
set aUUID to current application’s NSUUID’s UUID()’s UUIDString() as text
  
set aNewFile to ((path to desktop) as string) & aUUID & ".csv"
  
saveAsCSV(inList, aNewFile) of me
  
  
tell application "Numbers"
    activate
    
open (aNewFile as alias)
  end tell
end repeat

on filterATableAndPaseCells(aSource as string, targInd as integer, aTag as string)
  set aHTML to current application’s HTMLDocument’s documentWithString:(aSource as string)
  
  
–Table要素をリストアップ
  
set eList to (aHTML’s nodesMatchingSelector:aTag) as list
  
set aObj to contents of item (targInd + 1) of eList
  
  
–Count columns of Table Header (Count only)
  
set aTableHeader to (aObj’s nodesMatchingSelector:"tr")’s firstObject()
  
set hList to aTableHeader’s nodesMatchingSelector:"th"
  
set hStrList to {}
  
repeat with i1 in hList
    set hCellStr to i1’s textContent() as string
    
set the end of hStrList to (hCellStr)
  end repeat
  
set hLen to length of hStrList –count columns
  
  
  
–Acquire whole table body contents
  
set aTableBody to (aObj’s nodesMatchingSelector:"tbody")’s firstObject()
  
set bList to (aTableBody’s nodesMatchingSelector:"tr") as list
  
  
set rCount to (length of bList) –count rows
  
  
–行単位ループ
  
set yCount to 1
  
set attrList to make2DBlankArray(hLen, rCount) of aLib
  
  
repeat with i2 in bList
    set bb2List to {}
    
set i3 to (i2’s nodesMatchingSelector:"th") as list
    
if i3 = {} then
      set i3 to (i2’s nodesMatchingSelector:"td") as list
    end if
    
    
–カラム単位ループ
    
set xCount to 1
    
repeat with i4 in i3
      set anAttr to i4’s attributes()
      
set colAtr to (anAttr’s valueForKey:"colspan")
      
set rowAttr to (anAttr’s valueForKey:"rowspan")
      
set cellStr to i4’s textContent() as string
      
      
if colAtr is not equal to missing value then
        –colspan処理
        
set colNum to colAtr as integer
        
set attrList to xFill(xCount, yCount, attrList, cellStr, colNum) of aLib
        
      else if rowAttr is not equal to missing value then
        –rowspan処理
        
set rowNum to rowAttr as integer
        
set attrList to yFill(xCount, yCount, attrList, cellStr, rowNum) of aLib
        
      else if cellStr is not equal to "" then
        –通常処理
        
repeat with ii from xCount to hLen
          set aRes to getItemByXY(ii, yCount, attrList, "") of aLib
          
if aRes = "" then
            set attrList to setItemByXY(ii, yCount, attrList, cellStr) of aLib
            
exit repeat
          else
            set xCount to xCount + 1
          end if
        end repeat
        
      end if
      
      
set xCount to xCount + 1
    end repeat
    
    
set yCount to yCount + 1
  end repeat
  
  
return attrList
end filterATableAndPaseCells

–Safariのウィンドウ上で表示中のDOM Elementsを座標計算して返す
on getVisibleElementIndexList(aTag as string)
  tell application "Safari"
    set dCount to count every document
    
if dCount = 0 then return false
    
    
set jRes to do JavaScript "var winWidth = window.innerWidth,
winHeight = window.innerHeight,
winLeft = window.scrollX,
winTop = window.scrollY,
winBottom = winTop + winHeight,
winRight = winLeft + winWidth,
    elementsArray = document.body.getElementsByTagName(’" & aTag & "’),
    elemLen = elementsArray.length,
inView = [];
      
    var step;
    for (step = 0 ; step < elemLen ; step++) {
      var tmpElem = document.body.getElementsByTagName(’" & aTag & "’)[step];
      var bVar = tmpElem.getBoundingClientRect();
      if (bVar.top > 0 && bVar.top < winHeight) {
        inView.push(step);
      }
    }
    JSON.stringify(inView);"
in front document
    
    
set jList to parseJSONAsList(jRes) of me
    
return jList
    
  end tell
end getVisibleElementIndexList

on parseJSONAsList(jsRes as string)
  set jsonString to NSString’s stringWithString:jsRes
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict as list
end parseJSONAsList

–Save 2D List to CSV file
on saveAsCSV(aList as list, aPath)
  set crlfChar to (string id 13) & (string id 10)
  
set LF to (string id 10)
  
set wholeText to ""
  
  
repeat with i in aList
    set newLine to {}
    
    
–Sanitize (Double Quote)
    
repeat with ii in i
      set jj to ii as text
      
set kk to repChar(jj, string id 34, (string id 34) & (string id 34)) of me –Escape Double Quote
      
set the end of newLine to kk
    end repeat
    
    
–Change Delimiter
    
set aLineText to ""
    
set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to "\",\""
    
set aLineList to newLine as text
    
set AppleScript’s text item delimiters to curDelim
    
    
set aLineText to repChar(aLineList, return, "") of me –delete return
    
set aLineText to repChar(aLineText, LF, "") of me –delete lf
    
    
set wholeText to wholeText & "\"" & aLineText & "\"" & crlfChar –line terminator: CR+LF
  end repeat
  
  
if (aPath as string) does not end with ".csv" then
    set bPath to aPath & ".csv" as Unicode text
  else
    set bPath to aPath as Unicode text
  end if
  
  
writeToFileAsUTF8(wholeText, bPath, false) of me
  
end saveAsCSV

on writeToFileAsUTF8(this_data, target_file, append_data)
  tell current application
    try
      set the target_file to the target_file as text
      
set the open_target_file to open for access file target_file with write permission
      
if append_data is false then set eof of the open_target_file to 0
      
write this_data as «class utf8» to the open_target_file starting at eof
      
close access the open_target_file
      
return true
    on error error_message
      try
        close access file target_file
      end try
      
return error_message
    end try
  end tell
end writeToFileAsUTF8

on repChar(origText as text, targChar as text, repChar as text)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

★Click Here to Open This Script 

Posted in file JavaScript list Record Text | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSJSONSerialization NSMutableArray NSString NSUUID Numbers Safari | 4 Comments

PDFのサイズをpointで取得 v2

Posted on 9月 28, 2019 by Takaaki Naganoya

指定PDFのサイズ(幅、高さ)をPointで取得するAppleScriptです。

以前に掲載したバージョンでは、macOS 10.13以降でboundsの値の返り方が変わったことに対応できていないので(それ以前に作ったので無理もないというか、勝手にAppleが仕様を変えたのが悪い)、対処してみました。

AppleScript名:PDFのサイズをpointで取得 v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/09/28
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "Quartz"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property PDFDocument : a reference to current application’s PDFDocument

set aHFSPath to (choose file of type {"com.adobe.pdf"} with prompt "Select PDF")
set sizeRes to retPDFSizeInfo(aHFSPath) of me
–>  {​​​​​width:595.28, ​​​​​height:841.89​​​}

–PDFのサイズを取得する(単位:Point)
on retPDFSizeInfo(aHFSPath)
  set aPOSIX to POSIX path of aHFSPath
  
set aURL to (|NSURL|’s fileURLWithPath:aPOSIX)
  
  
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:aURL
  
set pCount to aPDFdoc’s pageCount()
  
set aPage to aPDFdoc’s pageAtIndex:0
  
  
set aBounds to aPage’s boundsForBox:(current application’s kPDFDisplayBoxMediaBox)
  
  
set aClass to class of aBounds
  
if aClass = record then
    set aSize to |size| of aBounds
  else if aClass = list then
    set aWidth to item 1 of item 2 of aBounds
    
set aHeight to item 2 of item 2 of aBounds
    
set aSize to {width:aWidth, height:aHeight}
  else
    error "Wrong PDF….Can not get bounds from PDF"
  end if
  
  
return aSize
end retPDFSizeInfo

★Click Here to Open This Script 

Posted in list PDF Record | Tagged 10.12savvy 10.13savvy 10.14savvy NSURL PDFDocument | Leave a comment

指定アプリケーションの指定言語のstringsファイルの内容をすべて取り出す

Posted on 9月 21, 2019 by Takaaki Naganoya

バンドルIDで指定したアプリケーションのResourcesフォルダ中の、指定ロケールのstringsファイルをすべて読み込んでkeyを取り出すAppleScriptです。

アプリケーション内の指定のローカライズしたメッセージ(テキスト)の内容を取り出すことはできますが、そのためにはキーを知っておく必要があります。そのキーを取り出してローカライズされた文字列を取り出すため、キーを調査してみました。

これをそのまま何かのツールなりScriptに使うというものではなく、いわゆる「下調べ」のためのScriptの部品です。

ほぼ、ありもののルーチンを再利用しただけのプログラムでできていますが、ありものはありもので、数千本のAppleScriptのストックからそれを探し出してくるのも一苦労です。

アプリケーションバンドル内のResourcesフォルダ以下の(各lprojフォルダ以下の)stringsファイルの中身はまんま(シリアライズした)NSDictionaryなので、そのままDictionaryに読み込んでallkey()などのメソッドを実行できます。昔のstringsファイルはテキストファイルだったような気がしますが、テキストファイルだとparseしないといけないんで、ビルド時にparseしておいてDictionaryの状態でファイルに書いておくのは正しいと思います。

Xcode 8あたりから、アプリケーションのローカライズのルールが変更になったようで、基本となる言語環境がBase.lprojになり、英語はen.lprojといった1ローカライズ言語という位置付けに変更になりました。

NSLocalizedStringFromTableInBundleを使ってアクセスしようかとも思ったのですが、こちらはまだ目的を達成できていません。


▲Xcode 11上で実験的に作成したAppleScriptアプリケーションのバンドル構造(左)。ローカライズしていない状態だとEnglishではなくBase.lprojが作成される。右はKeynote.app/Contents/Resources/ja.lprojフォルダの内容。stringsファイルが大量に存在している

AppleScript名:指定アプリケーションの指定言語のstringsファイルの内容をすべて取り出す.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/09/21
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSBundle : a reference to current application’s NSBundle
property NSPredicate : a reference to current application’s NSPredicate
property NSDictionary : a reference to current application’s NSDictionary
property NSWorkspace : a reference to current application’s NSWorkspace
property NSFileManager : a reference to current application’s NSFileManager
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey
property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles
property NSDirectoryEnumerationSkipsPackageDescendants : a reference to current application’s NSDirectoryEnumerationSkipsPackageDescendants

set targID to "com.apple.iWork.Keynote"

set bRes to getLocalizationsFromBundleID(targID) of me
–>  {"de", "he", "en_AU", "ar", "el", "ja", "en", "uk", "es_419", "zh_CN", "es", "da", "it", "sk", "pt_PT", "ms", "sv", "cs", "ko", "Base", "no", "hu", "zh_HK", "tr", "pl", "zh_TW", "en_GB", "vi", "ru", "fr_CA", "fr", "fi", "id", "nl", "th", "pt", "ro", "hr", "hi", "ca"}

set curLang to first item of (choose from list bRes)
set aPath to retPathFromBundleID(targID) of me

set aPath to aPath & "/Contents/Resources/" & curLang & ".lproj"
set sList to getFilepathListByUTI(aPath, "com.apple.xcode.strings-text", "POSIX") of me

set aMDict to NSMutableDictionary’s new()

repeat with i in sList
  set j to contents of i
  
set aDict to (NSDictionary’s alloc()’s initWithContentsOfFile:j)
  (
aMDict’s addEntriesFromDictionary:aDict)
end repeat

return aMDict’s allKeys() as list
–> {"Interactive Bubble Chart", "Rehearse Slideshow", "PMT_ARGUMENT_1", "ACCRINTM_ARGUMENT_4_MODE_0", "Truck_378",….}

on getLocalizationsFromBundleID(aBundleID)
  set aRes to retPathFromBundleID(aBundleID) of me
  
if aRes = false then error "Wrong Bundle ID."
  
return getSpecifiedAppFilesLocalizationListWithDuplication(aRes) of me
end getLocalizationsFromBundleID

–指定アプリケーションファイルの、指定Localeにおけるローカライズ言語リストを求める。重複を許容
on getSpecifiedAppFilesLocalizationListWithDuplication(appPOSIXpath)
  set aURL to (|NSURL|’s fileURLWithPath:appPOSIXpath)
  
set aBundle to NSBundle’s bundleWithURL:aURL
  
set locList to aBundle’s localizations()
  
return locList as list
end getSpecifiedAppFilesLocalizationListWithDuplication

on retPathFromBundleID(aBundleID)
  set aURL to NSWorkspace’s sharedWorkspace()’s URLForApplicationWithBundleIdentifier:aBundleID
  
if aURL = missing value then return false –Error
  
return aURL’s |path|() as string
end retPathFromBundleID

on getFilepathListByUTI(aFolPOSIX, aUTI as string, aFileType as string)
  script spdFile
    property urlList : {}
  end script
  
  
if aFileType is not in {"file", "POSIX"} then return {}
  
  
set aFM to NSFileManager’s defaultManager()
  
set aFolExt to (aFM’s fileExistsAtPath:aFolPOSIX isDirectory:true) as boolean
  
if aFolExt = false then return {} –フォルダ自体が存在しなければヌルリストを返す
  
  
set aURL to |NSURL|’s fileURLWithPath:aFolPOSIX
  
set theOptions to ((NSDirectoryEnumerationSkipsPackageDescendants) as integer) + ((NSDirectoryEnumerationSkipsHiddenFiles) as integer)
  
set urlArray to (aFM’s contentsOfDirectoryAtURL:aURL includingPropertiesForKeys:{} options:theOptions |error|:(missing value))
  
if urlArray = missing value then return {}
  
  
set (urlList of spdFile) to urlArray as list
  
set newList to {}
  
  
repeat with i in (urlList of spdFile)
    set j to POSIX path of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, aUTI)
    
    
if utiRes is not equal to {} then
      if aFileType = "POSIX" then
        set the end of newList to j
      else if aFileType = "file" then
        set the end of newList to POSIX file j
      end if
    end if
    
  end repeat
  
  
return newList
end getFilepathListByUTI

–指定のPOSIX pathのファイルのUTIを求める
on retUTIfromPath(aPOSIXPath)
  set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath
  
set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value)
  
  
if theResult = true then
    return theValue as string
  else
    return theResult
  end if
end retUTIfromPath

–UTIリストが指定UTIに含まれているかどうか演算を行う
on filterUTIList(aUTIList, aUTIstr)
  set anArray to NSArray’s arrayWithArray:aUTIList
  
set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr)
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list
  
return bRes
end filterUTIList

★Click Here to Open This Script 

Posted in file Record URL UTI | Tagged 10.12savvy 10.13savvy 10.14savvy NSArray NSBundle NSDictionary NSDirectoryEnumerationSkipsHiddenFiles NSDirectoryEnumerationSkipsPackageDescendants NSFileManager NSMutableDictionary NSPredicate NSURL NSURLTypeIdentifierKey NSWorkspace | Leave a comment

2つのレコードのキーの重複を計算

Posted on 9月 7, 2019 by Takaaki Naganoya

2つのレコードのキーの重複を検出するAppleScriptです。

こういう処理がお手軽にできるようになったので、macOS 10.10以降のAppleScriptでないとプログラムが組めなくなっている今日このごろ。死ぬほど努力してOld Style AppleScript(Cocoaの機能を使わない)だけで組めないこともないですが、それだけで半日は費やして数百行のプログラムになってしまいそうです。

というわけで、Cocoaの機能を利用した「ありもの」のルーチンを組み合わせるだけでほぼ完成。2つのレコードのキーの重複計算を行います。

どういう用途で使うかといえば、パラメータつきのURLに対して追加パラメータを付加したい場合です。URLからレコード形式でパラメータを分離し、追加パラメータ(レコード形式)を足し算する「前」に、2つのレコード間で重複キーがないかチェックする、という用途です。

では、2つのレコードの加算はどーするのか? という話になりますが、それは単に&演算子で加算するだけです。

set aRec to {abc:"1", bcd:"2"}
set bRec to {ccc:"0", ddd:"9"}
set cRec to aRec & bRec
–> {abc:"1", bcd:"2", ccc:"0", ddd:"9"}

★Click Here to Open This Script 

AppleScript名:2つのレコードのキーの重複を計算.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/09/06
—
–  Copyright © 2019 jp.piyomarusoft, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property NSSet : a reference to current application’s NSSet
property NSCountedSet : a reference to current application’s NSCountedSet
property NSMutableDictionary : a reference to current application’s NSMutableDictionary

set aRec to {autoplay:"1", hd:"9"}
set bRec to {v:"GP_tVXTYdmY", t:"120", hd:"3"}

set dupKeys to detectDuplicateKeysInTwoRecords(aRec, bRec) of me
–> {"hd"}

on detectDuplicateKeysInTwoRecords(aRec, bRec)
  set aDict to NSMutableDictionary’s dictionaryWithDictionary:aRec
  
set bDict to NSMutableDictionary’s dictionaryWithDictionary:bRec
  
  
set aKeyList to (aDict’s allKeys()) as list
  
set bKeyList to (bDict’s allKeys()) as list
  
  
set allKeyList to aKeyList & bKeyList
  
  
set aRes to returnDuplicatesOnly(allKeyList) of me
  
return aRes
end detectDuplicateKeysInTwoRecords

–1D Listから重複項目のみ返す
on returnDuplicatesOnly(aList as list)
  set aSet to NSCountedSet’s alloc()’s initWithArray:aList
  
set bList to (aSet’s allObjects()) as list
  
  
set dupList to {}
  
repeat with i in bList
    set aRes to (aSet’s countForObject:i)
    
if aRes > 1 then
      set the end of dupList to (contents of i)
    end if
  end repeat
  
  
return dupList
end returnDuplicatesOnly

★Click Here to Open This Script 

Posted in list Record | Tagged 10.12savvy 10.13savvy 10.14savvy NSCountedSet NSMutableDictionary NSSet | Leave a comment

recordの値をラベルを指定して変更

Posted on 7月 23, 2019 by Takaaki Naganoya

record型変数に対して、ラベルを指定して変更するAppleScriptです。各種データ型に対応しています。

AppleScriptの属性値ラベル付きデータであるrecord型変数は、さまざまな操作のための方法が(まっとうな手段では)存在せず、使いこなすためにはまっとうでない方法がよく使われてきました(動的にrecordを生成するAppleScriptのテキストを作成してrun scriptで実行するとか。提唱者本人が書いているので間違いない)。

特定のラベルを指定してデータを取り出したり、設定したりはできますが、ラベルを動的に生成して設定するようなことはできませんし、指定のラベルが存在するかどうかを確認する機能もありません(エラートラップを仕掛けて値の取り出しを確認するぐらい?)。

macOS 10.10で全面的にCocoaの機能が利用できるようになってからは、recordを操作するにはCocoaのオブジェクト(NSDictionary, NSMutableDictionary)に変換し、Cocoaの機能を使って加工することが一般的になってきました。

CocoaのNSDictionary/NSMutableDictionaryにはAppleScriptのGUIアプリケーションのオブジェクトは格納できませんが、アプリケーションのオブジェクトを扱わない用途には問題ありません。

本Scriptは、そんな中で(巨大なAppleScriptのプログラムを書く中で)些細なサブルーチンを整備する必要があったために書いたものです。こういう細かい部品を積み重ねていくと、いろいろと巨大な概念を積み上げていくのに便利なもので。

数値に足し算しかできないの? という指摘はあるかもしれませんが、そこはマイナスの数を指定することで引き算は実現できます。

もちろん、この処理はPure AppleScriptだけで書くこともできます。

set aRec to {columnAdr:2, rowAdr:2, tableName:"table1", sheetName:"Sheet1", docName:"numbTest", cellValue:"AAA"}
set tmpVal to aRec’s rowAdr
set tmpVal to tmpVal – 1
set aRec’s rowAdr to tmpVal

return aRec
–> {columnAdr:2, rowAdr:1, tableName:"table1", sheetName:"Sheet1", docName:"numbTest", cellValue:"AAA"}

★Click Here to Open This Script 

本ルーチン(↓)では、記述性を高め、取り出したり入れたりといった記述を省略することが目的です。

# 本ルーチンを実戦投入してみたら、意外と使えなかったというオチが(^ー^;;;

AppleScript名:recordの値をラベルを指定して変更.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/23
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set aRec to {columnAdr:2, rowAdr:2, tableName:"table1", sheetName:"Sheet1", docName:"numbTest", cellValue:{"AAA"}}

–Number
set bRes to changeRecByKeyAndOperator(aRec, "rowAdr", 2) of me
–> {rowAdr:4, docName:"numbTest", cellValue:"AAA", tableName:"table1", sheetName:"Sheet1", columnAdr:2}

–String
set cRes to changeRecByKeyAndOperator(aRec, "docName", ".numbers") of me
–> {rowAdr:2, docName:"numbTest.numbers", cellValue:"AAA", tableName:"table1", sheetName:"Sheet1", columnAdr:2}

–List
set dRes to changeRecByKeyAndOperator(aRec, "cellValue", {".numbers"}) of me
–> {rowAdr:2, docName:"numbTest", cellValue:{"AAA", ".numbers"}, tableName:"table1", sheetName:"Sheet1", columnAdr:2}

–Date (Date value is localized in each locale (This is Japanese locale format). Change Date format in your locale format. It depends on System Preferences > International)
set bRec to {columnAdr:2, rowAdr:2, theTime:date "2019年1月1日 火曜日 0:00:00", sheetName:"Sheet1", docName:"numbTest", cellValue:{"AAA"}}
set eRes to changeRecByKeyAndOperator(bRec, "theTime", 10) of me
–> {theTime:date "2019年1月1日 火曜日 0:00:10", rowAdr:2, docName:"numbTest", cellValue:{"AAA"}, sheetName:"Sheet1", columnAdr:2}

on changeRecByKeyAndOperator(aRec as record, aKey as string, aVal as {date, list, number, string})
  set aDict to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
set tmpVal to aDict’s valueForKey:aKey
  
  
–指定キーの存在チェック。存在しない場合には元の値をそのまま返す
  
set tmpKeyList to (aDict’s allKeys()) as list
  
if aKey is not in tmpKeyList then return aRec
  
  
set tmpVal to tmpVal as {date, list, number, string}
  
set tmpClass to class of tmpVal
  
  
if tmpClass = integer then
    aDict’s setValue:(tmpVal + aVal) forKey:aKey
  else if tmpClass = string then
    aDict’s setValue:(tmpVal & aVal) forKey:aKey
  else if tmpClass = list then
    aDict’s setValue:(tmpVal & aVal) forKey:aKey
  else if tmpClass = date then
    aDict’s setValue:(tmpVal + aVal) forKey:aKey
  end if
  
  
return aDict as record
end changeRecByKeyAndOperator

★Click Here to Open This Script 

Posted in Record | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy | Leave a comment

アラートダイアログ上にTable Viewを表示 v4

Posted on 7月 11, 2019 by Takaaki Naganoya

アラートダイアログ上にTable Viewを表示するAppleScriptです。

データを表UIで表示する部品としては、Shane Stanleyの「Myriad Tables Lib」が定番ですが、高機能なぶんライブラリ中にFrameworkが含まれていたりして、場合によっては困ることもあります。また、見た目をカスタマイズしたい場合にも、あまりいじくれなくて困ることもあります(とくにデータの文字サイズを変更できなくて困ること多し)。

そのため、AppleScriptだけで書いた表UI表示用の部品も、たまに必要になることがあります。


▲スクリプトエディタで実行@macOS 10.14.5(左:Light Mode、右:Dark Mode)


▲Script Debuggerで実行@macOS 10.14.5(左:Light Mode、右:Dark Mode)


▲AppleScriptアプレットで実行@macOS 10.14.5(左:Light Mode、右:Dark Mode)

AppleScript名:アラートダイアログ上にTable Viewを表示 v4
— Created 2019-02-21 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSIndexSet : a reference to current application’s NSIndexSet
property NSScrollView : a reference to current application’s NSScrollView
property NSTableView : a reference to current application’s NSTableView
property NSTableColumn : a reference to current application’s NSTableColumn
property NSMutableArray : a reference to current application’s NSMutableArray
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSModalPanelWindowLevel : a reference to current application’s NSModalPanelWindowLevel
property NSAlertSecondButtonReturn : a reference to current application’s NSAlertSecondButtonReturn

property theResult : 0
property returnCode : 0
property theDataSource : {}

on run
  set (my theResult) to 0 –initialize
  
  
set paramObj to {myMessage:"項目の選択", mySubMessage:"適切なものを以下からえらんでください", aTableList:{{field1:"MacBook Air", field2:"119,800円", field3:"1.6GHzデュアルコアIntel Core i5(Turbo Boost使用時最大3.6GHz)、4MB L3キャッシュ"}, {field1:"MacBook Pro 13", field2:"139,800円", field3:"1.4GHzクアッドコアIntel Core i5(Turbo Boost使用時最大3.9GHz)、128MB eDRAM"}, {field1:"MacBook Pro 15", field2:"258,800円", field3:"2.6GHz 6コアIntel Core i7(Turbo Boost使用時最大4.5GHz)、12MB共有L3キャッシュ"}, {field1:"Mac mini", field2:"122,800円", field3:"3.0GHz 6コアIntel Core i5 Turbo Boost使用時最大4.1GHz 9MB共有L3キャッシュ"}, {field1:"iMac 21.5", field2:"120,800円", field3:"2.3GHzデュアルコアIntel Core i5(Turbo Boost使用時最大3.6GHz)"}, {field1:"iMac 4K 21.5", field2:"142,800円", field3:"3.6GHzクアッドコアIntel Core i3"}, {field1:"iMac 5K 27", field2:"198,800円", field3:"3.0GHz 6コア Intel Core i5(Turbo Boost使用時最大4.1GHz)"}, {field1:"iMac Pro", field2:"558,800円", field3:"3.2GHz Intel Xeon W Turbo Boost使用時最大4.2GHz 19MBキャッシュ"}}, aSortOrder:{"field1", "field2", "field3"}}
  
  
–my chooseItemByTableView:paramObj–for debug
  
my performSelectorOnMainThread:"chooseItemByTableView:" withObject:paramObj waitUntilDone:true
  
return (my theResult)
end run

on chooseItemByTableView:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set aTList to (aTableList of paramObj) as list
  
set labelSortList to (aSortOrder of paramObj) as list
  
  
set aWidth to 600
  
set aHeight to 200
  
  
set aScroll to makeTableView(aTList, aWidth, aHeight, labelSortList) of me
  
  
–Detect Dark Mode
  
set dMode to retLIghtOrDark() of me
  
if dMode = true then
    set tvCol to 1
    
set tvAlpha to 0.8
    
set bCol to 0.1
    
set bAlpha to 0.8
    
set contentCol to (NSColor’s cyanColor())
  else
    set tvCol to 0
    
set tvAlpha to 0.1
    
set bCol to 1
    
set bAlpha to 0.8
    
set contentCol to (NSColor’s blackColor())
  end if
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aScroll
    
    
set myWindow to its |window|
  end tell
  
  
myWindow’s setOpaque:(false)
  
myWindow’s setBackgroundColor:(NSColor’s colorWithCalibratedWhite:(bCol) alpha:(bAlpha))
  
myWindow’s setLevel:(NSModalPanelWindowLevel)
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode) = 1001 then error number -128
  
  
set (my theResult) to (aScroll’s documentView’s selectedRow()) + 1
end chooseItemByTableView:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

–TableView Event Handlers
on numberOfRowsInTableView:aView
  return my theDataSource’s |count|()
end numberOfRowsInTableView:

on tableView:aView objectValueForTableColumn:aColumn row:aRow
  set aRec to (my theDataSource)’s objectAtIndex:(aRow as number)
  
set aTitle to (aColumn’s headerCell()’s title()) as string
  
set aRes to (aRec’s valueForKey:aTitle)
  
return aRes
end tableView:objectValueForTableColumn:row:

on makeTableView(aDicList, aWidth, aHeight, labelSortList)
  set aOffset to 40
  
set theDataSource to current application’s NSMutableArray’s alloc()’s init()
  
theDataSource’s addObjectsFromArray:aDicList
  
  
set aScroll to current application’s NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aOffset, aWidth, aHeight))
  
set aView to current application’s NSTableView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aOffset, aWidth, aHeight))
  
  
set aLen to length of labelSortList
  
  
repeat with i in labelSortList
    set j to contents of i
    
set aColumn to (current application’s NSTableColumn’s alloc()’s initWithIdentifier:j)
    (
aColumn’s setWidth:(aWidth div aLen))
    (
aColumn’s headerCell()’s setStringValue:j)
    (
aView’s addTableColumn:aColumn)
  end repeat
  
  
aView’s setDelegate:me
  
aView’s setDataSource:me
  
aView’s reloadData()
  
  
aScroll’s setDocumentView:aView
  
aView’s enclosingScrollView()’s setHasVerticalScroller:true
  
aScroll’s setVerticalLineScroll:(30.0 as real)
  
  
–1行目を選択
  
set aIndexSet to current application’s NSIndexSet’s indexSetWithIndex:0
  
aView’s selectRowIndexes:aIndexSet byExtendingSelection:false
  
  
–強制的にトップにスクロール
  
set aDBounds to aScroll’s documentView()’s |bounds|()
  
if class of aDBounds = list then
    –macOS 10.13 or later
    
set maxHeight to item 2 of item 1 of aDBounds
  else
    –macOS 10.10….10.12
    
set maxHeight to height of |size| of aDBounds
  end if
  
  
set aPT to current application’s NSMakePoint(0.0, -1 * (maxHeight as real))
  
aScroll’s documentView()’s scrollPoint:aPT
  
  
return aScroll
end makeTableView

on alertShowHelp:aNotification
  display dialog "Help Me!" buttons {"OK"} default button 1 with icon 1
  
return false –trueを返すと親ウィンドウ(アラートダイアログ)がクローズする
end alertShowHelp:

–ダークモードの判定。ダークモード時:true、ライトモード時:falseが返る。System Eventsを使っていないのは、macOS 10.14以降対策(承認を取得しなくてもいいように)
on retLIghtOrDark()
  set curMode to (current application’s NSUserDefaults’s standardUserDefaults()’s stringForKey:"AppleInterfaceStyle") as string
  
return (curMode = "Dark") as boolean
end retLIghtOrDark

★Click Here to Open This Script 

Posted in Color GUI list Record | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSAlert NSAlertSecondButtonReturn NSColor NSIndexSet NSModalPanelWindowLevel NSMutableArray NSRunningApplication NSScrollView NSTableColumn NSTableView | 1 Comment

Cocoa ObjectをキーにしたDictionaryから合致するObjectを取得

Posted on 7月 7, 2019 by Takaaki Naganoya

Cocoa ObjectをキーにしたDictionaryから、Cocoa Objectでキー検索を行い、キーが合致する要素に定義されているオブジェクトを取得するAppleScriptです。

AppleScriptのrecord型変数は、本当に基本的な機能しか用意されておらず、

{keyLabel1:value1, keyLabel2:value2, keyLabel3:value3 } 

のような、キーとなるラベルには「空白文字や使用禁止文字を含まない」文字しか使えませんし、キーに何らかのオブジェクトを指定することはできません。

そんな中、macOS 10.10でCocoa Scriptingが標準搭載されたため、CocoaのNSDictionaryを調べて「へー、キーにオブジェクトが使えるのか!」などと喜んでいました(macOS 10.10が出た頃)。

{Cocoa Object 1:value1, Cocoa Object 2:value2, Cocoa Object 3:value3 } 
{Cocoa Object 1:some object 1, Cocoa Object 2:some object 2, Cocoa Object 3:some object 3 } 

ちょうどそういう(CocoaオブジェクトをキーにしたDictionaryの検索)プログラムを組もうとして、Dictionaryから「valueForKey:」でvalueを取り出そうとして(エラーに遭遇して)試行錯誤していました。

(NSDictionary) {
	NSCalibratedRGBColorSpace 0 1 0 1:"Green",
	NSCalibratedRGBColorSpace 0 0 1 1:"Blue",
	NSCalibratedRGBColorSpace 1 0 0 1:"Red"
}

実際にはこれは「objectForKey:」で取り出さないとエラーになってしまうんですね。その確認のために書いた基礎確認用のAppleScriptです。やっぱり、基礎の再確認はとても大事です。

AppleScript名:Cocoa ObjectをキーにしたDictionaryから合致するObjectを取得
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/06
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

set aCol to current application’s NSColor’s redColor()
set bCol to current application’s NSColor’s greenColor()
set cCol to current application’s NSColor’s blueColor()

set aDict to current application’s NSMutableDictionary’s new()
aDict’s addObject:"Red" forKey:aCol
aDict’s addObject:"Green" forKey:bCol
aDict’s addObject:"Blue" forKey:cCol

set dCol to current application’s NSColor’s blueColor()

set aRes to (aDict’s objectForKey:dCol) as string
–> "Blue"

★Click Here to Open This Script 

Posted in Color Record | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSColor NSMutableDictionary | Leave a comment

構文色分け情報を取得(Color Spaceを考慮)

Posted on 7月 4, 2019 by Takaaki Naganoya

macOS標準搭載のスクリプトエディタで定義している、AppleScriptの構文要素ごとの色分け情報。これを設定ファイルから取り出してレコード型データ(を入れた配列)に変換するAppleScriptの、カラースペースを考慮したデータの取り出しを行う改修版です。

AppleScriptの構文色分け情報は、ユーザーごとに異なります。一応、OSデフォルトの趣味の悪い配色なんかもありますが、

 (1)美的センスがなく見た目に気持ち悪い(ほら変更したいでしょ? 自分の好きなように変えてね、というメッセージだと受け止めました)

 (2)重複した色が設定されている構文要素がたくさんある(構文要素ごとの見分けがしにくいので、デフォルトのままだと無意味。ほら変更したくなったでしょ、というメッセージだと受け止めました)

ということから、AppleScript入門初日に設定色を変更。何度か細かい変更を行いつつも、今日までだいたい同じ感じの設定を使い続けています。

他のScripterがどのような配色にしているかはあまり知りません。Scripterごとに違うんだろうな、ぐらいの感じです。

ところが、蓋を開けてみたらこの構文色分け設定に「RGB以外の色」が設定できることが判明。けっこう長い間、この処理系使い続けてきましたけれど、昨日はじめて知りました。

具体的に言えば、RGB以外の「CMYK色」と「グレースケール色」の2つを設定可能なことが判明。CMYK色は、何度かアクセスしているうちに勝手にRGB色に置き換わってしまうようですが、グレースケールで指定した色はそのまま色種別がグレースケールのまま保持される(RGBに変換されたりしない)ようです。そのため、NSColorからredValue()などのメソッドで数値を取り出そうとするとエラーになる事例が発生したのでした。

そこで、RGBの各チャンネルの値を取り出す前にNSColorの色空間(グレースケール色空間というのはないので、種別ぐらい?)をチェックし、RGB以外であれば変換処理を行うようにしてみました。

ただし、この色空間(色モデル)の確認にNSColorのcolorSpaceNameというメソッドを使っている点に注意が必要です。これはmacOS 10.13で非推奨(deprecated)になっています。ヘッダーファイル上の説明を読むかぎりだと、Color Space(色空間)といいながら実際には色空間に該当する(HSBとかL*a*b*とか)ものを指定しているわけではないので、色タイプと言い換えることにした、という説明が行われていました。

このため、macOS 10.15betaでは未確認ではあるものの、このNSColorからRGB値を取り出すという処理自体を書き換える必要が出てくるため、本ルーチンだけ別のライブラリに分離しておくとか、メンテナンス時にわかるように書いておくとよいでしょう(NSColorのtypeを取得してみたものの、いまひとつサンプルなどもなく不明。macOS 10.14上で全部一律で0が返ってくるし)。

AppleにOS内部の機能修正リクエストを出す場合、「実際に機能不全を起こしているんだから直してほしい」と依頼してもなかなか直らない一方で、「学術的に正しくない」という指摘をされるととっとと変更するんだなーという発見をしたような気がします。

AppleScript名:構文色分け情報を取得(Color Spaceを考慮).scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/04
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSDictionary : a reference to current application’s NSDictionary
property NSUnarchiver : a reference to current application’s NSUnarchiver

set cList to getAppleScriptSourceColors() of me

–AppleScriptの構文色分けのカラー値をRGBで取得する
on getAppleScriptSourceColors()
  — get the plist info as a dictionary
  
set thePath to NSString’s stringWithString:"~/Library/Preferences/com.apple.applescript.plist"
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theInfo to NSDictionary’s dictionaryWithContentsOfFile:thePath
  
  
— extract relevant part and loop through
  
set theArray to (theInfo’s valueForKey:"AppleScriptSourceAttributes") as list
  
  
set colList to {}
  
  
repeat with i from 1 to count of theArray
    set anEntry to item i of theArray
    
    
set colorData to NSColor of anEntry
    
set theColor to (NSUnarchiver’s unarchiveObjectWithData:colorData)
    
    
set {rVal, gVal, bVal} to retColListFromNSColor(theColor, 255) of me
    
    
set fontData to NSFont of anEntry
    
set theFont to (NSUnarchiver’s unarchiveObjectWithData:fontData)
    
    
set aFontName to theFont’s displayName() as text
    
set aFontSize to theFont’s pointSize()
    
    
set aColRec to {redValue:rVal, greenValue:gVal, blueValue:bVal, fontName:aFontName, fontSize:aFontSize}
    
    
set the end of colList to aColRec
  end repeat
  
  
return colList
end getAppleScriptSourceColors

–NSColorからRGBの値を取り出す
on retColListFromNSColor(aCol, aMAX as integer)
  set aSpace to (aCol’s colorSpaceName()) as string
  
  
if aSpace is in {"NSDeviceRGBColorSpace", "NSCalibratedRGBColorSpace"} then
    –do nothing
  else
    –RGB以外の色空間の色は、RGBに変換
    
–CMYKとグレースケールは同一メソッドでRGBに変換できることを確認済み
    
set cCol to aCol’s colorUsingColorSpaceName:"NSCalibratedRGBColorSpace"
    
if cCol = missing value then error "Color Space Conversion Error (" & aSpace & " to NSCalibratedRGBColorSpace)"
    
copy cCol to aCol
  end if
  
  
set aRed to round ((aCol’s redComponent()) * aMAX) rounding as taught in school
  
set aGreen to round ((aCol’s greenComponent()) * aMAX) rounding as taught in school
  
set aBlue to round ((aCol’s blueComponent()) * aMAX) rounding as taught in school
  
  
if aRed > aMAX then set aRed to aMAX
  
if aGreen > aMAX then set aGreen to aMAX
  
if aBlue > aMAX then set aBlue to aMAX
  
  
return {aRed, aGreen, aBlue}
end retColListFromNSColor

★Click Here to Open This Script 

Posted in Color list Record System | Tagged 10.12savvy 10.13savvy 10.14savvy NSArray NSColor NSDictionary NSString NSUnarchiver | Leave a comment

Handle diff v2

Posted on 7月 3, 2019 by Takaaki Naganoya

Script Debugger上でオープン中の2つのAppleScript書類のうち、名称が同じハンドラ(サブルーチン)の内容同士を比較して、お互いに合っているかどうかをチェックするAppleScriptです。

アプリケーション書き出しして、Script Debuggerのスクリプトメニューに入れて実行します(AppleScript書類のままだと、Myriad Tables Lib内のフレームワークが呼べないため)。


▲本Scriptはスクリプトエディタの環境設定で行うAppleScriptの構文色分け設定色が「RGBカラー」でないとエラーになります。CMYKとかグレースケールカラーで指定して、そのままRGBに変換されずに保持される(CMYK色はアクセスしているうちにRGBに変換されるが、グレースケールは保持される)ため、色空間の判定を行ってRGB色に変換してから処理する必要があります(自分用メモ)

スクリプトエディタ上で設定する構文色分け設定をもとに、AppleScriptの構文要素を考慮したハンドラ一覧を作成し、2つのAppleScript書類の間に共通して存在するハンドラ名のハンドラ(サブルーチン)のAppleScriptソースを取得。インデント(tab)を削除したのちに比較を実行。

共通名称のハンドラすべてをチェックして、結果を表インタフェースで表示します。初版(v1)では実行するたびに1つのハンドラをチェックしていたのですが、あまりにかったるいので即座にループですべて調べてまとめて結果を表示するようにしました(v2)。

–> download executable archive (mainly for macOS 10.14 or later)

ただし、1つのAppleScript書類内にScript Object(JavaScriptでいうところのClosureみたいなもの)で論理分割された同名のハンドラが複数回登場するパターンは想定していません。複数検出するとエラーになります。

とくにScript Debuggerを対象にせずスクリプトエディタを対象にしてもよいのですが、些細な変更で実現できるため、興味のある方はやってみてください。あと、本Scriptは必要に迫られまくって作ったものなので、動作でおかしい箇所があったらぜひぜひご指摘を。

個人的には、ハンドラ名称を構文要素を考慮しつつ取得している一方で、ハンドラの内容は単なる文字列検索で取り出しているというあたりにアンバランスさを感じます。ただ、趣味のScriptではないので若干の手抜きを(^ー^;;

macOS 10.14.5上のスクリプトエディタで、構文色分け情報を何回設定しても「黒」になるという現象に遭遇したのですが、他のユーザー環境上での再現性については未知数であるため、まだレポートできない状況です。

→ その後、本ツールは強化されて、構文色分け設定にRGB以外の色が設定してあってもRGBに変換して処理する機能や、構文色分け設定を参照したコメント除去機能や、各種書式情報の取得を3倍高速化するカラーキャッシュなどの機能を実装したプログラムに(必要に迫られて)成長しました。

AppleScript名:Handle diff v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/02
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5" — Sierra (10.12) or later (maybe 10.11 is OK but not confirmed)
use framework "Foundation"
use scripting additions
use framework "OSAKit"
use script "Myriad Tables Lib" version "1.0.9" –https://www.macosxautomation.com/applescript/apps/Script_Libs.html

property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property OSAScript : a reference to current application’s OSAScript
property NSPredicate : a reference to current application’s NSPredicate
property NSDictionary : a reference to current application’s NSDictionary
property NSUnarchiver : a reference to current application’s NSUnarchiver
property NSCountedSet : a reference to current application’s NSCountedSet

–構文色分け設定に重複色がないかチェック
set cList to getAppleScriptSourceColors() of me
set cRes to chkASLexicalFormatColorConfliction(cList) of me –構文色分けの重複色チェック
if cRes = false then error "There is some duplicate(s) color among AppleScript’s lexical color settings"

–Script Debugger上でオープン中の2つのAppleScript書類のパスを取得
set dList to retTwoPathList() of me
if dList = false then return

copy dList to {d1Path, d2Path}

–各AppleScript書類のハンドラ名称一覧を取得する
set hList1 to retHandlerNamesFromAppleScriptSource(d1Path as alias) of me
set hList2 to retHandlerNamesFromAppleScriptSource(d2Path as alias) of me

–2つのAppleScript書類のハンドラの共通項目(名称のみ)を抽出する
set resList to returnDuplicatesOnly(hList1 & hList2) of me
if resList = {} then
  –共通のハンドラ(サブルーチン)が指定の2つのScriptに存在していなかった
  
display dialog "There is no common handler between the scripts." buttons {"OK"} default button 1
  
return
end if

–各AppleScript書類のソースを取得して、指定のハンドラのテキストを取得する
set s1Source to getASsourceFor(d1Path as alias) of me
set s2Source to getASsourceFor(d2Path as alias) of me

if (s1Source = false) or (s2Source = false) then
  display dialog "Error occured in getteing AS source" buttons {"OK"} default button 1
  
return
end if

set outList to {}
repeat with i in resList
  set resHandler to contents of i
  
set s1Source to extractHandlerSourceOnly(s1Source, resHandler) of me
  
set s2Source to extractHandlerSourceOnly(s2Source, resHandler) of me
  
set compareF to (s1Source is equal to s2Source) as boolean
  
set the end of outList to {resHandler, compareF}
end repeat

–結果表示
tell me to activate
display table with data outList with prompt "Handler contents compare results" column headings {"Handler name", "Match?"} with title "Handler Diff Results"

–指定のハンドラの内容を抽出する(コメントぐらいは結果から削除してもいいような気もする)
–Script Objectの使用は考慮していない。1つのAppleScript書類からScript Objectで論理分割された同名のハンドラが複数検出されるケースは想定していない
on extractHandlerSourceOnly(wholeScript as string, handlerName as string)
  –インデント文字(Tab)をすべて削除
  
set targScript to repChar(wholeScript, tab, "") of me
  
  
–"on"ではじまるハンドラと仮定して抽出
  
set handlerStr to extractStrFromTo(targScript, "on " & handlerName, "end " & handlerName) of me
  
if handlerStr = false then
    –"to"ではじまるハンドラと仮定して抽出
    
set handlerStr to extractStrFromTo(targScript, "to " & handlerName, "end " & handlerName) of me
    
if handlerStr = false then return false
  else
    return handlerStr
  end if
end extractHandlerSourceOnly

on retHandlerNamesFromAppleScriptSource(aFile)
  set aRec to getAttrRecFromASPath(aFile) of me
  
set cList to getAppleScriptSourceColors() of me
  
  
set targAttr to contents of item 7 of cList –ハンドラあるいは変数
  
set tmpCoStr to ((redValue of targAttr) as string) & " " & ((greenValue of targAttr) as string) & " " & ((blueValue of targAttr) as string)
  
  
set ontoColItem to contents of item 3 of cList –スクリプティング予約語(on/to)
  
set ontoCoStr to ((redValue of ontoColItem) as string) & " " & ((greenValue of ontoColItem) as string) & " " & ((blueValue of ontoColItem) as string)
  
  
  
–変数あるいはハンドラ名称をリストアップ(variables & handler)
  
set tmp1Array to NSArray’s arrayWithArray:aRec
  
set thePred0 to NSPredicate’s predicateWithFormat_("colorStr == %@", tmpCoStr)
  
set dArray to (tmp1Array’s filteredArrayUsingPredicate:thePred0) as list
  
  
–改行を含むデータをリストアップ(text data contains return)
  
set thePred1 to NSPredicate’s predicateWithFormat_("stringVal CONTAINS %@", return)
  
set eArray to ((tmp1Array’s filteredArrayUsingPredicate:thePred1)’s valueForKeyPath:"itemIndex") as list
  
  
set the beginning of eArray to 0 –ハンドラ宣言部がTopに来る場合に備える
  
  
–"on"(ハンドラ宣言)の項目をリストアップ 文字と色で抽出
  
set thePred2 to NSPredicate’s predicateWithFormat_("stringVal == %@ && colorStr == %@ ", "on", ontoCoStr)
  
set fArray to ((tmp1Array’s filteredArrayUsingPredicate:thePred2)’s valueForKeyPath:"itemIndex") as list
  
  
–"to"(ハンドラ宣言ないしは代入対象指定) の項目をリストアップ文字と色で抽出
  
set thePred3 to NSPredicate’s predicateWithFormat_("stringVal == %@ && colorStr == %@ ", "to", ontoCoStr)
  
set gArray to ((tmp1Array’s filteredArrayUsingPredicate:thePred3)’s valueForKeyPath:"itemIndex") as list
  
  
  
set handlerList to {}
  
  
–on ではじまるハンドラの抽出
  
repeat with i in eArray –改行を含むテキストのアイテム番号リスト
    set j to (contents of i) as integer
    
repeat with ii in fArray –"on"の項目リスト
      set jj to (contents of ii) as integer
      
      
set handlerStr to missing value
      
      
if (j + 1) = jj then
        set handlerStr to stringVal of (item (jj + 2) of (aRec as list))
      else if (j + 2) = jj then
        set handlerStr to stringVal of (item (jj + 2) of (aRec as list))
      end if
      
      
if handlerStr is not in {"error", missing value} and handlerStr is not in handlerList then
        set the end of handlerList to handlerStr
      end if
      
    end repeat
  end repeat
  
  
  
–to ではじまるハンドラの抽出
  
repeat with i in eArray –改行を含むテキストのアイテム番号リスト
    set j to (contents of i) as integer
    
repeat with ii in gArray –"to"の項目リスト
      set jj to (contents of ii) as integer
      
      
set handlerStr to missing value
      
      
if (j + 1) = jj then
        set handlerStr to stringVal of (item (jj + 2) of (aRec as list))
      else if (j + 2) = jj then
        set handlerStr to stringVal of (item (jj + 2) of (aRec as list))
      end if
      
      
if handlerStr is not in {"error", missing value} and handlerStr is not in handlerList then
        set the end of handlerList to handlerStr
      end if
      
    end repeat
  end repeat
  
  
return handlerList
end retHandlerNamesFromAppleScriptSource

–ソースを取得してコンパイル(構文確認)する方式から、URL(fileURL)を指定してコンパイル(構文確認)する方式に変更した
on getAttrRecFromASPath(aFile)
  set aURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of aFile)
  
set theScript to OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
  
if theScript is equal to missing value then
    — handle error
    
error "Compile Error"
  else
    –set sourceText to theScript’s source() –No Use
    
set styledSourceText to theScript’s richTextSource()
  end if
  
  
set attrRes to getAttributeRunsFromAttrString(styledSourceText) of me
  
return attrRes
end getAttrRecFromASPath

–指定AppleScriptファイルのソースコードを取得する(実行専用Scriptからは取得できない)
— Original Created 2014-02-23 Shane Stanley
on getASsourceFor(anAlias as {alias, string})
  set aURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of anAlias)
  
set theScript to OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
  
if theScript is equal to missing value then
    — handle error
    
error "Compile Error"
  else
    set sourceText to theScript’s source()
  end if
  
  
return sourceText as string
end getASsourceFor

–Attributed StringをDictionary化
on getAttributeRunsFromAttrString(theStyledText)
  script aSpd
    property styleList : {}
  end script
  
  
set (styleList of aSpd) to {} —for output
  
  
set thePureString to theStyledText’s |string|() –pure string from theStyledText
  
  
set theLength to theStyledText’s |length|()
  
set startIndex to 0
  
set itemCount to 1
  
  
repeat until (startIndex = theLength)
    set {theAtts, theRange} to theStyledText’s attributesAtIndex:startIndex longestEffectiveRange:(specifier) inRange:{startIndex, theLength – startIndex}
    
    
–String  
    
set aText to (thePureString’s substringWithRange:theRange) as string
    
    
–Color
    
set aColor to (theAtts’s valueForKeyPath:"NSColor")
    
if aColor is not equal to missing value then
      set aSpace to aColor’s colorSpace()
      
      
set aRed to (aColor’s redComponent()) * 255
      
set aGreen to (aColor’s greenComponent()) * 255
      
set aBlue to (aColor’s blueComponent()) * 255
      
      
set colList to {aRed as integer, aGreen as integer, aBlue as integer} –for comparison
      
set colStrForFind to (aRed as integer as string) & " " & (aGreen as integer as string) & " " & (aBlue as integer as string) –for filtering
    else
      set colList to {0, 0, 0}
      
set colStrForFind to "0 0 0"
    end if
    
    
–Font
    
set aFont to (theAtts’s valueForKeyPath:"NSFont")
    
if aFont is not equal to missing value then
      set aDFontName to aFont’s displayName()
      
set aDFontSize to aFont’s pointSize()
    end if
    
    
set the end of (styleList of aSpd) to {stringVal:aText, colorStr:colStrForFind, colorVal:colList, fontName:aDFontName as string, fontSize:aDFontSize, itemIndex:itemCount}
    
set startIndex to current application’s NSMaxRange(theRange)
    
    
set itemCount to itemCount + 1
  end repeat
  
  
return (styleList of aSpd)
  
end getAttributeRunsFromAttrString

–AppleScriptの構文色分けのカラー値をRGBで取得する
on getAppleScriptSourceColors()
  
  
— get the plist info as a dictionary
  
set thePath to NSString’s stringWithString:"~/Library/Preferences/com.apple.applescript.plist"
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theInfo to NSDictionary’s dictionaryWithContentsOfFile:thePath
  
  
— extract relevant part and loop through
  
set theArray to (theInfo’s valueForKey:"AppleScriptSourceAttributes") as list
  
  
set colList to {}
  
  
repeat with i from 1 to count of theArray
    set anEntry to item i of theArray
    
    
set colorData to NSColor of anEntry
    
set theColor to (NSUnarchiver’s unarchiveObjectWithData:colorData)
    
    
set {rVal, gVal, bVal} to retColListFromNSColor(theColor, 255) of me
    
    
set fontData to NSFont of anEntry
    
set theFont to (NSUnarchiver’s unarchiveObjectWithData:fontData)
    
    
set aFontName to theFont’s displayName() as text
    
set aFontSize to theFont’s pointSize()
    
    
set aColRec to {redValue:rVal, greenValue:gVal, blueValue:bVal, fontName:aFontName, fontSize:aFontSize}
    
    
set the end of colList to aColRec
  end repeat
  
  
return colList
end getAppleScriptSourceColors

–NSColorからRGBの値を取り出す
on retColListFromNSColor(aCol, aMAX as integer)
  set aRed to round ((aCol’s redComponent()) * aMAX) rounding as taught in school
  
set aGreen to round ((aCol’s greenComponent()) * aMAX) rounding as taught in school
  
set aBlue to round ((aCol’s blueComponent()) * aMAX) rounding as taught in school
  
  
if aRed > aMAX then set aRed to aMAX
  
if aGreen > aMAX then set aGreen to aMAX
  
if aBlue > aMAX then set aBlue to aMAX
  
  
return {aRed, aGreen, aBlue}
end retColListFromNSColor

–AS書式で配色に重複がないかどうかチェック
on chkASLexicalFormatColorConfliction(aList)
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set bList to (anArray’s valueForKeyPath:"redValue.stringValue") as list
  
set cList to (anArray’s valueForKeyPath:"greenValue.stringValue") as list
  
set dList to (anArray’s valueForKeyPath:"blueValue.stringValue") as list
  
  
set colStrList to {}
  
repeat with i from 1 to (length of bList)
    set bItem to contents of item i of bList
    
set cItem to contents of item i of cList
    
set dItem to contents of item i of dList
    
set the end of colStrList to bItem & " " & cItem & " " & dItem
  end repeat
  
  
set aRes to returnDuplicatesOnly(colStrList) of me
  
log aRes
  
if aRes is equal to {} then
    return true –重複が存在しなかった場合
  else
    return false –重複があった場合
  end if
end chkASLexicalFormatColorConfliction

on returnDuplicatesOnly(aList as list)
  set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bList to (aSet’s allObjects()) as list
  
  
set dupList to {}
  
repeat with i in bList
    set aRes to (aSet’s countForObject:i)
    
if aRes > 1 then
      set the end of dupList to (contents of i)
    end if
  end repeat
  
  
return dupList
end returnDuplicatesOnly

on retTwoPathList()
  tell application "Script Debugger"
    set dList to name of every document
    
set dResList to choose from list dList with prompt "Select two documents" with multiple selections allowed
    
if dResList = false then return false
    
if length of dResList is not equal to 2 then
      display dialog "Please Select two documents to compare handler contents" buttons {"OK"} default button 1 with icon 1 with title "Selection Error"
      
return false
    end if
    
    
set dPathList to {}
    
repeat with i in dResList
      set j to contents of i
      
tell document j
        set tmpPath to (file spec) as string –HFS path string
      end tell
      
      
set the end of dPathList to tmpPath
    end repeat
  end tell
  
  
return dPathList
end retTwoPathList

–Written By Philip Aker
–文字置換ルーチン
on repChar(origText as string, targStr as string, repStr as string)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

–指定文字と終了文字に囲まれた内容を抽出
on extractStrFromTo(aParamStr, fromStr, toStr)
  set theScanner to current application’s NSScanner’s scannerWithString:aParamStr
  
set anArray to current application’s NSMutableArray’s array()
  
  
repeat until (theScanner’s isAtEnd as boolean)
    set {theResult, theKey} to theScanner’s scanUpToString:fromStr intoString:(specifier)
    
theScanner’s scanString:fromStr intoString:(missing value)
    
set {theResult, theValue} to theScanner’s scanUpToString:toStr intoString:(specifier)
    
if theValue is missing value then set theValue to "" –>追加
    
theScanner’s scanString:toStr intoString:(missing value)
    
anArray’s addObject:theValue
  end repeat
  
  
if anArray’s |count|() is not equal to 1 then return false
  
  
return first item of (anArray as list)
end extractStrFromTo

★Click Here to Open This Script 

Posted in Color OSA Record Text | Tagged 10.12savvy 10.13savvy 10.14savvy NSArray NSCountedSet NSDictionary NSPredicate NSString NSUnarchiver OSAScript Script Debugger | Leave a comment

テキストから指定桁数の数値を抽出して度数分布集計

Posted on 6月 28, 2019 by Takaaki Naganoya

CotEditorで編集中の最前面の書類の本文中から指定桁の数値を抽出して登場回数で度数分布の集計を行うAppleScriptです。

CotEditorのアプリケーション内のスクリプトメニューに入れて実行できることを確認してあります(@macOS 10.14.5)。

たまたま、テキストで集計していた情報のうち、数値部分の度数分布を計算したいと考え、ありもののルーチンを組み合わせて作ったものです。

実行すると、集計対象の数値の桁数を聞いてくるため、適当なものを選択してださい。

CotEditorのScriptingの要注意点で、オブジェクト階層を素直に書いて、当該階層のオブジェクトの属性値を取りたいような場合に、そのまま属性を書いても取得できないケースが見られます。そのため、明示的にオブジェクト階層を指定するために「of it」を書いています。Xcodeが同じような挙動を行うため、注意が必要です。

本Scriptについていえば、正規表現でテキストから情報を抽出したりと、一応最低限のレベルはクリアしているものの、いまひとつ満足できません。

数字が連続して登場している箇所を抽出し、どれを集計対象にするのかといった分析を冒頭で行ってユーザーに問い合わせしたいところです。現段階では、「桁数を聞く」という頭の悪い実装になっていますが、そのうちどうにかしたいと考えるところです。

AppleScript名:テキストから指定桁数の数値を抽出して度数分布集計.scptd
— Created 2019-06-28 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property graphStr : "絆" –グラフに出力する文字

tell application "CotEditor"
  –最前面の書類からテキスト本文を取得
  
tell front document
    set aText to contents of it –本文
    
set lineTerm to (line ending) –改行コード
  end tell
  
  
–改行コードの選択(ドキュメントの状態から取得)
  
if lineTerm = LF then
    set aRet to ASCII character 10 –To avoid keyword conflict (string)
  else if lineTerm = CR then
    set aRet to ASCII character 13
  else if lineTerm = CRLF then
    set aRet to (ASCII character 13) & (ASCII character 10)
  else
    set aRet to ASCII character 10
  end if
end tell

–桁数選択
set digiList to {"2", "3", "4", "5"}
set digitRes to first item of (choose from list digiList with prompt "Choose the digit to extract as numbers")

–正規表現で数字部分のみ抽出
set theList to my findPattern:("[0-9]{" & digitRes & "}") inString:aText

–検出した数字部分の度数分布を計算
set theCountedSet to current application’s NSCountedSet’s alloc()’s initWithArray:theList
set newArray to current application’s NSMutableArray’s new()
set kList to uniquifyAndSort1DList(theList, false) of me –降順ソート

repeat with i in kList
  (newArray’s addObject:{theKey:i, theCount:(theCountedSet’s countForObject:i)})
end repeat

–出力用のテキストを作成
set outStr to ""
repeat with i in newArray as list
  set outStr to (outStr & (theKey of i) as string) & ":"
  
set aNum to (theCount of i) as integer
  
  
repeat aNum times
    set outStr to outStr & graphStr
  end repeat
  
  
set outStr to outStr & aRet
end repeat

–最前面のテキスト末尾に集計結果を出力
tell application "CotEditor"
  tell front document
    set contents of it to (aText & aRet & aRet & "集計結果:" & aRet & aRet & outStr & aRet)
  end tell
end tell

–正規表現でテキスト中から指定パターンに該当する箇所を抽出してリストで返す
on findPattern:thePattern inString:theString
  set theOptions to ((current application’s NSRegularExpressionDotMatchesLineSeparators) as integer) + ((current application’s NSRegularExpressionAnchorsMatchLines) as integer)
  
set theRegEx to current application’s NSRegularExpression’s regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value)
  
set theFinds to theRegEx’s matchesInString:theString options:0 range:{location:0, |length|:length of theString}
  
set theFinds to theFinds as list — so we can loop through
  
set theResult to {} — we will add to this
  
set theNSString to current application’s NSString’s stringWithString:theString
  
repeat with i from 1 to count of items of theFinds
    set theRange to (item i of theFinds)’s range()
    
set end of theResult to (theNSString’s substringWithRange:theRange) as integer
  end repeat
  
return theResult
end findPattern:inString:

–1D Listをユニーク化してソート
on uniquifyAndSort1DList(theList as list, aBool as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:theList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
set aDdesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:"self" ascending:aBool selector:"compare:"
  
set cArray to bArray’s sortedArrayUsingDescriptors:{aDdesc}
  
  
set bList to cArray as list
  
return bList
end uniquifyAndSort1DList

★Click Here to Open This Script 

Posted in list Record regexp Sort Text | Tagged 10.12savvy 10.13savvy 10.14savvy CotEditor NSArray NSCountedSet NSMutableArray NSRegularExpression NSRegularExpressionDotMatchesLineSeparators NSSortDescriptor NSString | Leave a comment

Post navigation

  • Older posts

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

Google Search

Popular Posts

  • 画面上の指定座標にマウスカーソルを強制移動させてクリック
  • Numbersで選択範囲のセルのデータを取得して重複データを抽出
  • フルパスからファイル名を取得する
  • 【基礎】AppleScriptの実行を(操作により)中断する
  • macOS 11.0, Big Sur AppleScript関連の変更点
  • フォルダの存在確認
  • ディスプレイを回転させる
  • AppleScriptでキースキャン
  • 指定した文字で囲まれたキーワードの色を置換する
  • 文字列の長さを求める
  • mouseClickを用いて指定座標をクリック
  • CSVデータを読み込んで表インタフェースで表示確認 v2
  • DSCaptureで画面キャプチャ
  • アラートダイアログの背景色を指定してTable Viewを表示
  • 文字種類変換(ASOC)
  • Dynamic Menu Clicker
  • 指定フォルダ以下のすべてのファイルとフォルダ名から絵文字を除去する v2
  • AVFAudioでオーディオ再生のじっけん
  • SMCkitで各種センサー値を取得する
  • macOS 10.14で新設されたエラーコード-1743を確認する

Tags

10.11savvy (1109)