AppleScript名:指定リストから、Regexpで要素を抽出 |
— Created 2017-10-29 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set stringArray to current application’s NSArray’s arrayWithArray:{"adobe", "22", "microsoft", "99"} set thePred to current application’s NSPredicate’s predicateWithFormat:"self MATCHES ’\\\\d\\\\d’" set bList to (stringArray’s filteredArrayUsingPredicate:thePred) as list –> {"22", "99"} |
カテゴリー: list
指定リストから、文字数で要素を抽出
AppleScript名:指定リストから、文字数で要素を抽出 |
— Created 2017-10-29 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set stringArray to current application’s NSArray’s arrayWithArray:{"adobe", "22", "microsoft", "99"} set thePred to current application’s NSPredicate’s predicateWithFormat:"self.length > 5" set bList to (stringArray’s filteredArrayUsingPredicate:thePred) as list –> {"microsoft"} |
配列を逆順に(OLD Style AS)
AppleScriptネイティブの配列変数であるlist型変数を逆順にするAppleScriptです。
配列(list)の要素数が5,000以下ぐらいだと普通に変数に保持して、このように逆順に変換して配列に代入するのが一番速いでしょう。
配列(list)の要素数が5,000以上ぐらいだとscriptオブジェクト内に格納したpropertyに保持して、このように逆順に変換してpropertyに代入するのが一番速いでしょう。
Cocoaの配列変数(NSArray、NSMutableArray)に格納して速度面での優位性が生まれてくるのは、要素数が1万とか数十万アイテムぐらいになった場合です。
Cocoa Scriptingで予想外にパフォーマンスが出ないケースというのは、たいてい配列処理で件数が少なすぎて逆効果だったという場合が多いので、ネイティブのAppleScriptのlist型変数の各種処理も重要です。
AppleScript名:配列を逆順に(OLD Style AS) |
— Created 2017-07-30 by Takaaki Naganoya — 2017 Piyomaru Software set aList to {1, 2, 3, 4, 5, 6} set revArray to reverse of aList –> {6, 5, 4, 3, 2, 1} |
複数キーによるソートテスト3.1(OLD Style AppleScript)
OLD Style AppleScriptによる2D Listの複数キーによるソートを行うAppleScriptです。
以前掲載したソートルーチンの速度比較で、2D ArrayのソートでOLD Style AppleScript版はSingle Keyのルーチンでしたが、本来であればこのMulti-Keyのルーチンで比較を行うべきでした。
ASOC版はMulti-Keyのソートルーチンなので、2.0 vs 0.3 secondsというところ。
AppleScript名:複数キーによるソートテスト3.1 |
–複数キーによるソートテスト3(複数キーを許容。キー数無制限) script orig property aList : {} end script –テストデータ作成 set aList of orig to {} repeat 10000 times –3次まですべてのキーを使ったソートが発生するよう、1次、2次キーは乱数範囲をわざと狭くしてある set the end of aList of orig to {"a", random number from 1 to 10, random number from 1 to 10, random number from 1 to 100} end repeat set sDat to current date –ソート時間計測(開始時刻) –item 2をPrimary key、item 3とitem 4をサブキーにして降順ソート set resList to multiKeySortDescending(aList of orig, {2, 3, 4}) of multiKeySort set eDat to current date –ソート時間計測(終了時刻) return (eDat – sDat) –複数キーによるソート script multiKeySort script spd property bList : {} –1次キーでソートした結果が入る property cList : {} –1次キーでソートした結果のうち、1次キーで同じ値が連続する範囲が入る {{1,3},{10,20}} property dList : {} –2次キーで再ソートする対象の一部のリストが入る(ワーク用) property eList : {} –2次キーで再ソートした結果のリストが入る(ワーク用) end script –複数キー(Primary, Secondary……)による降順ソート。キーは指定用のリストに入れる –falseが返ってきたらエラー on multiKeySortDescending(aList, keyList) –Initialize –set aList of spd to {} set bList of spd to {} –■■■■ ここからパラメータのチェック ■■■■ –型チェック set aLen to length of keyList if class of keyList is not equal to list then return false –キー値のリストがlistではなかった場合error end if –ソート対象の2D Listの要素数を取得 set tmpLen to length of first item of aList repeat with i in keyList if i > tmpLen then return false –キー値として指定した内容が、ソート対象のリストの要素数よりも大きかった場合error end if end repeat –キー指定内容で重複がないかチェック set dupList to detectDuplicates(keyList) of me if dupList is not equal to {} then return false –指定したキーで重複があったらerror end if –キー指定内容に0が入っていないかチェック if 0 is in keyList then return false –■■■■ パラメータのチェックここまで ■■■■ set firstKeyNo to first item of keyList –1次キーで2D Listをソート(降順) set bList of spd to shellSortListDescending(aList, firstKeyNo) of me –複数キーによるソート検証および実行ループ repeat with iii from 1 to aLen – 1 set cList of spd to {} set dList of spd to {} set eList of spd to {} –n次キーの値が連続する箇所を探す set curData to missing value set sucF to false –データ連続箇所検出中フラグ(false=非連続、true=連続中) set biginItem to 0 set endItem to 0 set itemC to 0 repeat with i in bList of spd set thisData to item (item iii of keyList) of i –n次キー –現在の値と前の値が等しい(連続箇所を検出した、あるいは連続箇所の中にいる) if curData = thisData then if sucF = false then set biginItem to itemC set sucF to true else if sucF = true then –連続箇所の検索継続中、何もしない end if else –現在の値と前の値が等しくない(連続していない、あるいは連続箇所の末尾を検出した) if sucF = true then set the end of cList of spd to {biginItem, itemC} set sucF to false end if set curData to thisData end if set itemC to itemC + 1 end repeat –n次キーの連続状態の検出中のままリスト末尾に来た場合には、最終データを出力する if sucF = true and curData = thisData then set the end of cList of spd to {biginItem, itemC} end if –n次キーによる重複箇所がない場合には、n次キーによるソート結果をそのまま返す if cList of spd = {} then return bList of spd end if –n+1次キーによる部分ソートし直し repeat with i in cList of spd set {tmpB, tmpE} to i copy items tmpB thru tmpE of (bList of spd) to (dList of spd) set (eList of spd) to shellSortListDescending((dList of spd), (item (iii + 1) of keyList)) of me set tmpCounter to 1 repeat with ii from tmpB to tmpE copy item tmpCounter of (eList of spd) to item ii of (bList of spd) set tmpCounter to tmpCounter + 1 end repeat end repeat end repeat return (bList of spd) end multiKeySortDescending –リスト中から重複項目をリストアップする on detectDuplicates(aList) set aCount to length of aList set duplicationList to {} repeat aCount times set anItem to contents of (first item of aList) set aList to rest of aList if anItem is in aList then set the end of duplicationList to anItem end if end repeat return duplicationList end detectDuplicates –シェルソートで入れ子のリストを降順ソート on shellSortListDescending(aSortList, aKeyItem) script oBj property list : aSortList end script set len to count oBj’s list’s items set gap to 1 repeat while (gap ≤ len) set gap to ((gap * 3) + 1) end repeat repeat while (gap > 0) set gap to (gap div 3) if (gap < len) then repeat with i from gap to (len – 1) set temp to oBj’s list’s item (i + 1) set j to i repeat while ((j ≥ gap) and (contents of item aKeyItem of (oBj’s list’s item (j – gap + 1)) < item aKeyItem of temp)) set oBj’s list’s item (j + 1) to oBj’s list’s item (j – gap + 1) set j to j – gap end repeat set oBj’s list’s item (j + 1) to temp end repeat end if end repeat return oBj’s list end shellSortListDescending end script |
iTunesライブラリの曲のアーティスト名を集計
iTunesライブラリ中の曲のアーティスト名を集計して、曲数が多い順に集計するAppleScriptです。
アーティスト名のFirst NameとLast Nameの間にスペースが存在している場合としていない場合が(iTunes Music Storeからダウンロード購入した曲でも)混在していたので、こうしたデータのゆらぎに対処しています。
6,827曲のライブラリの集計が、筆者の開発環境(MacBook Pro Retina 2012 Core i7 2.66GHz)で2.7秒ぐらいです。
AppleScript名:iTunesライブラリの曲のアーティスト名を集計 |
— Created 2017-01-07 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "iTunesLibrary" set library to current application’s ITLibrary’s libraryWithAPIVersion:"1.0" |error|:(missing value) if library is equal to missing value then return set allTracks to library’s allMediaItems() set allCount to allTracks’s |count|() set anEnu to allTracks’s objectEnumerator() set newArray to current application’s NSMutableArray’s alloc()’s init() repeat set aPL to anEnu’s nextObject() if aPL = missing value then exit repeat try set aKind to (aPL’s mediaKind) as integer if (aKind as integer) is equal to 2 then –Music, Song set plName to aPL’s artist’s |name| as string set pl2Name to (my changeThis:" " toThat:"" inString:plName) –日本語アーティスト名で姓と名の間にスペースが入っているものがある(表記ゆらぎ)ので対策 newArray’s addObject:(pl2Name) end if on error set aLoc to (aPL’s location’s |path|()) as string –log aLoc end try end repeat set aRes to countItemsByItsAppearance(newArray) of me –> {{theName:"浜田省吾", numberOfTimes:442}, {theName:"B’z", numberOfTimes:379}, {theName:"渡辺岳夫・松山祐士", numberOfTimes:199}, {theName:"VariousArtists", numberOfTimes:192}, {theName:"菅野よう子", numberOfTimes:108}, {theName:"布袋寅泰", numberOfTimes:100}, {theName:"三枝成彰", numberOfTimes:95}, {theName:"宇多田ヒカル", numberOfTimes:94}, {theName:"宮川泰", numberOfTimes:81}, {theName:"MichaelJackson", numberOfTimes:78}, {theName:"稲葉浩志", numberOfTimes:73}, … –出現回数で集計 on countItemsByItsAppearance(aList) set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList set bArray to current application’s NSMutableArray’s array() set theEnumerator to aSet’s objectEnumerator() repeat set aValue to theEnumerator’s nextObject() if aValue is missing value then exit repeat bArray’s addObject:(current application’s NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{"theName", "numberOfTimes"}) end repeat –出現回数(numberOfTimes)で降順ソート set theDesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:"numberOfTimes" ascending:false bArray’s sortUsingDescriptors:{theDesc} return bArray as list end countItemsByItsAppearance on changeThis:findString toThat:repString inString:someText set theString to current application’s NSString’s stringWithString:someText set theString to theString’s stringByReplacingOccurrencesOfString:findString withString:repString options:(current application’s NSRegularExpressionSearch) range:{location:0, |length|:length of someText} return theString as text end changeThis:toThat:inString: |
MatRによる行列計算テスト v4
–> download sample data ”matrix.txt”
AppleScript名:MatRによる行列計算テスト v4 |
— Created 2017-05-15 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "DCMatrix" –https://github.com/davidcox95/MatR –タブ区切りテキストファイルからMatrixを作る set aPosixFile to POSIX path of (choose file) set aMatrix to current application’s |Matrix|’s alloc()’s initWithContentsFromFile:aPosixFile aMatrix’s |print|() (* 5 6 7 8 3 4 5 6 1 2 3 4 *) |
MatRによる行列計算テスト v3
AppleScript名:MatRによる行列計算テスト v3 |
— Created 2017-05-15 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "DCMatrix" –https://github.com/davidcox95/MatR –listからMatrixを作る set mList to {{1, 2, 3, 4}, {11, 12, 13, 14}, {21, 22, 23, 24}} set aMatrix to current application’s |Matrix|’s alloc()’s initWithArray:mList andRows:3 byColumns:4 aMatrix’s |print|() (* 1 2 3 4 11 12 13 14 21 22 23 24 *) set a1Res to aMatrix’s |transpose|() (a1Res’s |print|()) (* 1 11 21 2 12 22 3 13 23 4 14 24 *) |
MatRによる行列計算テスト v2
AppleScript名:MatRによる行列計算テスト v2 |
— Created 2017-05-15 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "DCMatrix" –https://github.com/davidcox95/MatR –行列データをdoubleのListに set aMatrix to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:5) andRows:3 byColumns:4 set aList to doubleListFromMatrix(aMatrix) of me –> {{5.0, 5.0, 5.0, 5.0}, {5.0, 5.0, 5.0, 5.0}, {5.0, 5.0, 5.0, 5.0}} –行列データをintegerのListに set bList to intListFromMatrix(aMatrix) of me –> {{5, 5, 5, 5}, {5, 5, 5, 5}, {5, 5, 5, 5}} –行列データをstringのListに set cList to strListFromMatrix(aMatrix) of me –> {{"5", "5", "5", "5"}, {"5", "5", "5", "5"}, {"5", "5", "5", "5"}} set bMatrix to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:3) andRows:4 byColumns:3 set bScalar to current application’s NSNumber’s numberWithDouble:2 set bRes to bMatrix’s addScalar:bScalar set bbRes to intListFromMatrix(bRes) of me –> {{5, 5, 5}, {5, 5, 5}, {5, 5, 5}, {5, 5, 5}} set cScalar to current application’s NSNumber’s numberWithDouble:2 set cRes to bMatrix’s subtractScalar:cScalar set ccRes to intListFromMatrix(cRes) of me –> {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}} set dScalar to current application’s NSNumber’s numberWithDouble:2 set eRes to bMatrix’s multiplyScalar:dScalar set eeRes to intListFromMatrix(eRes) of me –> {{6, 6, 6}, {6, 6, 6}, {6, 6, 6}, {6, 6, 6}} set fScalar to current application’s NSNumber’s numberWithDouble:2 set fRes to bMatrix’s divideScalar:fScalar set ffRes to doubleListFromMatrix(fRes) of me –> {{1.5, 1.5, 1.5}, {1.5, 1.5, 1.5}, {1.5, 1.5, 1.5}, {1.5, 1.5, 1.5}} set m4 to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:4) andRows:3 byColumns:3 set m2 to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:2) andRows:3 byColumns:3 set gRes to m4’s addMatrix:m2 set ggRes to intListFromMatrix(gRes) of me –> {{6, 6, 6}, {6, 6, 6}, {6, 6, 6}} set hRes to m4’s subtractMatrix:m2 set hhRes to intListFromMatrix(hRes) of me –> {{2, 2, 2}, {2, 2, 2}, {2, 2, 2}} set iRes to m4’s multiplyMatrix:m2 set iiRes to intListFromMatrix(iRes) of me –> {{24, 24, 24}, {24, 24, 24}, {24, 24, 24 on doubleListFromMatrix(aMatrix) set aList to {} set aRows to aMatrix’s rows() set aColumns to aMatrix’s columns() repeat with rowC from 0 to (aRows – 1) set colList to {} repeat with colC from 0 to (aColumns – 1) set the end of colList to (aMatrix’s getElementAtRow:rowC andColumn:colC) as real end repeat set the end of aList to colList end repeat return aList end doubleListFromMatrix on intListFromMatrix(aMatrix) set aList to {} set aRows to aMatrix’s rows() set aColumns to aMatrix’s columns() repeat with rowC from 0 to (aRows – 1) set colList to {} repeat with colC from 0 to (aColumns – 1) set the end of colList to (aMatrix’s getElementAtRow:rowC andColumn:colC) as integer end repeat set the end of aList to colList end repeat return aList end intListFromMatrix on strListFromMatrix(aMatrix) set aList to {} set aRows to aMatrix’s rows() set aColumns to aMatrix’s columns() repeat with rowC from 0 to (aRows – 1) set colList to {} repeat with colC from 0 to (aColumns – 1) set the end of colList to (aMatrix’s getElementAtRow:rowC andColumn:colC) as string end repeat set the end of aList to colList end repeat return aList end strListFromMatrix |
MatRによる行列計算テスト v1
AppleScript名:MatRによる行列計算テスト v1 |
— Created 2017-05-15 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "DCMatrix" –https://github.com/davidcox95/MatR –指定数値、指定サイズ(行、列)で行列データを作成する set aMatrix to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:5) andRows:3 byColumns:4 (aMatrix’s |print|()) (* 5 5 5 5 5 5 5 5 5 5 5 5 *) –行列データに数値を加算する set bMatrix to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:7) andRows:4 byColumns:3 set bScalar to current application’s NSNumber’s numberWithDouble:2 set bRes to bMatrix’s addScalar:bScalar bRes’s |print|() (* 9 9 9 9 9 9 9 9 9 9 9 9 *) –行列データから数値を減算する set cScalar to current application’s NSNumber’s numberWithDouble:3 set cRes to bMatrix’s subtractScalar:cScalar cRes’s |print|() (* 4 4 4 4 4 4 4 4 4 4 4 4 *) –行列データに数値を乗算する set dScalar to current application’s NSNumber’s numberWithDouble:2 set eRes to bMatrix’s multiplyScalar:dScalar eRes’s |print|() (* 14 14 14 14 14 14 14 14 14 14 14 14 *) –行列データに数値を除算する set fScalar to current application’s NSNumber’s numberWithDouble:2 set fRes to bMatrix’s divideScalar:fScalar fRes’s |print|() (* 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 *) –行列同士の加算 set m4 to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:4) andRows:3 byColumns:3 set m2 to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:2) andRows:3 byColumns:3 set gRes to m4’s addMatrix:m2 gRes’s |print|() (* 6 6 6 6 6 6 6 6 6 *) –行列同士の減算 set hRes to m4’s subtractMatrix:m2 hRes’s |print|() (* 2 2 2 2 2 2 2 2 2 *) –行列同士の乗算 set iRes to m4’s multiplyMatrix:m2 iRes’s |print|() (* 24 24 24 24 24 24 24 24 24 *) |
与えられたデータのうちIPアドレスとして妥当なもののみを抽出
AppleScript名:与えられたデータのうちIPアドレスとして妥当なもののみを抽出 |
— Created 2018-01-03 by Takaaki Naganoya — 2018 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" property NSPredicate : a reference to current application’s NSPredicate property NSArray : a reference to current application’s NSArray set aaList to {"112.4.208.194", "17.20.30..12"} set aResList to {} repeat with i in aaList set j to contents of i set the end of aResList to chkIPAddressFormat(j) of me end repeat aResList on chkIPAddressFormat(aStr as string) set aList to {aStr} set anArray to NSArray’s arrayWithArray:aList set aPred to NSPredicate’s predicateWithFormat:"SELF MATCHES ’[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}’" set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list return (length of bRes = 1) as boolean end chkIPAddressFormat |
指定リストから、Regexpで要素を抽出(NSPredicate)
AppleScript名:指定リストから、Regexpで要素を抽出(NSPredicate) |
— Created 2017-10-29 by Takaaki Naganoya — 2017 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set stringArray to current application’s NSArray’s arrayWithArray:{"adobe", "22", "microsoft", "99"} set thePred to current application’s NSPredicate’s predicateWithFormat:"self MATCHES ’\\\\d\\\\d’" set bList to (stringArray’s filteredArrayUsingPredicate:thePred) as list –> {"22", "99"} |
同スコアを考慮した順位決定(汎用ルーチン)
AppleScript名:同スコアを考慮した順位決定(汎用ルーチン) |
use AppleScript version "2.4" use scripting additions set rList to {{"近 装甲強化型ジム COST: 200", 60}, {"遠 ジム・キャノン COST: 160", 39}, {"近 ジム・コマンド COST: 200", 32}, {"近 ジム(WD隊) COST: 160", 26}, {"近 陸戦型ガンダム COST: 220", 23}, {"近 ジム改 COST: 240", 22}, {"遠 ガンタンク COST: 200", 21}, {"格 ジム(指揮官機) COST: 160", 20}, {"近 ジム COST: 120", 19}, {"格 陸戦型ジム COST: 120", 10}, {"近 ジム・トレーナー COST: 120", 9}, {"射 ジム・スナイパーII(WD隊) COST: 220", 8}, {"射 陸戦型ガンダム(ジム頭) COST: 200", 7}, {"格 ガンダム COST: 280", 6}, {"近 ザクII(F2) COST: 160", 6}, {"格 ジム・ストライカー COST: 180", 4}, {"近 ジム・寒冷地仕様 COST: 200", 4}, {"狙 ジム・スナイパーカスタム COST: 200", 3}, {"近 アクア・ジム COST: 160", 2}, {"遠 量産型ガンタンク COST: 160", 2}, {"格 ガンキャノン重装型 COST: 160", 1}, {"近 ジム・コマンドライトアーマー COST: 160", 1}, {"射 ガンキャノン COST: 200", 1}, {"格 ボールK型 COST: 120", 0}, {"射 デザート・ジム COST: 160", 0}} set rRes to retRankingList(rList) of me –> {{rank:1, aCon:"近 装甲強化型ジム COST: 200", aTimes:60}, {rank:2, aCon:"遠 ジム・キャノン COST: 160", aTimes:39}, {rank:3, aCon:"近 ジム・コマンド COST: 200", aTimes:32}, {rank:4, aCon:"近 ジム(WD隊) COST: 160", aTimes:26}, {rank:5, aCon:"近 陸戦型ガンダム COST: 220", aTimes:23}, {rank:6, aCon:"近 ジム改 COST: 240", aTimes:22}, {rank:7, aCon:"遠 ガンタンク COST: 200", aTimes:21}, {rank:8, aCon:"格 ジム(指揮官機) COST: 160", aTimes:20}, {rank:9, aCon:"近 ジム COST: 120", aTimes:19}, {rank:10, aCon:"格 陸戦型ジム COST: 120", aTimes:10}, {rank:11, aCon:"近 ジム・トレーナー COST: 120", aTimes:9}, {rank:12, aCon:"射 ジム・スナイパーII(WD隊) COST: 220", aTimes:8}, {rank:13, aCon:"射 陸戦型ガンダム(ジム頭) COST: 200", aTimes:7}, {rank:14, aCon:"格 ガンダム COST: 280", aTimes:6}, {rank:14, aCon:"近 ザクII(F2) COST: 160", aTimes:6}, {rank:16, aCon:"格 ジム・ストライカー COST: 180", aTimes:4}, {rank:16, aCon:"近 ジム・寒冷地仕様 COST: 200", aTimes:4}, {rank:18, aCon:"狙 ジム・スナイパーカスタム COST: 200", aTimes:3}, {rank:19, aCon:"近 アクア・ジム COST: 160", aTimes:2}, {rank:19, aCon:"遠 量産型ガンタンク COST: 160", aTimes:2}, {rank:21, aCon:"格 ガンキャノン重装型 COST: 160", aTimes:1}, {rank:21, aCon:"近 ジム・コマンドライトアーマー COST: 160", aTimes:1}, {rank:21, aCon:"射 ガンキャノン COST: 200", aTimes:1}, {rank:24, aCon:"格 ボールK型 COST: 120", aTimes:0}, {rank:24, aCon:"射 デザート・ジム COST: 160", aTimes:0}} on retRankingList(rList) set aText to {} –出力用リスト set aCount to 0 set prevPoint to -1 set buffCount to 0 repeat with i in rList copy i to {j, bCount} if prevPoint = bCount then –同じポイントが続いた場合 if buffCount is not equal to 0 then –同じポイントが複数回(2回以上)続いている場合 set buffCount to buffCount + 1 log {"case A:", buffCount, aCount, bCount, prevPoint} else –同じポイントが続いている場合(2回目) set buffCount to 1 log {"case B:", buffCount, aCount, bCount, prevPoint} end if else –同じポイントが続いていない場合 if buffCount is not equal to 0 then –直前まで同じポイントが続いていた場合 set aCount to aCount + buffCount + 1 –バッファしておいたカウントを出力する set buffCount to 0 log {"case C:", buffCount, aCount, bCount, prevPoint} else –通常パターン(直前まで同じポイントが続いていたりしない) set buffCount to 0 set aCount to aCount + 1 –ランキング順位を+1 log {"case D:", buffCount, aCount, bCount, prevPoint} end if end if set the end of aText to {rank:aCount, aCon:j as string, aTimes:bCount} copy bCount to prevPoint end repeat return aText end retRankingList –リストを任意のデリミタ付きでテキストに 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 |
AppleScript sorting performance comparison
Pure AppleScriptからAppleScriptObjCに部品を書き換えて、どの程度パフォーマンスが向上するかを調べてまとめてみました。グラフ内の単位は秒(seconds)です。
1D Array(list)では、Pure AppleScriptを使う意義はほとんど感じません。
2D Arrayで思ったよりもASOCが速いように見えませんが、Pure AppleScript側は指定できるキー数が1つのみのルーチンで、ASOC側は複数キーで個別にAscending/Descendingの指定ができるため、複数キー対応ソートルーチンで比較するべきなのかもしれません。
ただし、各GUIアプリケーションのオブジェクトはNSArrayに入れることはできないため、Pure AppleScript版の2D listのソーティングルーチンには利用価値があります。
今回のテストで予想外の結果が出たのがコレです。思ったよりもdictionary in array(record in list)のソートでパフォーマンス向上が見られない、といったところでしょうか。大量のデータをソートする場合に、dictionary in arrayよりも2D Arrayでデータを保持したほうが高速、ということは確実にいえるでしょう。
ファイルパスの階層とリストとの相互変換
AppleScript名:ファイルパスの階層とリストとの相互変換 |
— Created 2016-11-07 by Takaaki Naganoya — 2016 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set aStr to current application’s NSString’s stringWithString:"/Users/maro/Desktop/aTEST.scpt" set aList to aStr’s pathComponents() as list –> {"/", "Users", "maro", "Desktop", "aTEST.scpt"} set bList to {"/", "Users", "maro", "Desktop", "aTEST.scpt"} set bStr to (current application’s NSString’s pathWithComponents:bList) as string –> "/Users/maro/Desktop/aTEST.scpt" |
RTFを読み込んで書式をDictionary化 v3.0
指定のRTF書類の内容を読み取って、書式情報をNSDictionaryに変換するAppleScriptです。
stringVal:文字列データ
colorStr:RGBの色データを文字列化したもの
colorVal:RGBの色データの数値list
colorDomainName:おおまかな色名称
fontName:フォント名
fontSize:フォントサイズ
書式情報で抽出しやすくしてあります。複数要素(例:フォント名+色)を一緒にまとめて格納しておくことで、検索パフォーマンスを稼げるはずです。
AppleScript名:RTFを読み込んで書式をDictionary化 v3.0 |
— Created 2017-12-10 by Takaaki Naganoya — Modified 2017-12-11 by Shane Stanley — Modified 2017-12-11 by Nigel Garvey — Modified 2017-12-12 by Takaaki Naganoya use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "AppKit" property NSData : a reference to current application’s NSData property NSString : a reference to current application’s NSString property NSAttributedString : a reference to current application’s NSAttributedString set fRes to choose file of type {"public.rtf"} set aFilePath to NSString’s stringWithString:(POSIX path of fRes) set aData to NSData’s dataWithContentsOfFile:aFilePath options:0 |error|:(missing value) set theStyledText to NSAttributedString’s alloc()’s initWithData:aData options:(missing value) documentAttributes:(missing value) |error|:(missing value) set attrRes to getAttributeRunsFromAttrString(theStyledText) of me (* –> {{stringVal:"■■■■■■■", colorStr:"0 0 0", colorVal:{0, 0, 0}, colorDomainName:"black", fontName:"ヒラギノ角ゴ ProN W6", fontSize:12.0}, {stringVal:"Xxxxxxx", colorStr:"217 11 0", colorVal:{217, 11, 0}, colorDomainName:"red", fontName:"ヒラギノ角ゴ ProN W6", fontSize:12.0}, … *) 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 repeat until (startIndex = theLength) set {theAtts, theRange} to theStyledText’s attributesAtIndex:startIndex longestEffectiveRange:(reference) 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 –Color domain name set cdnStr to retColorDomainNameFromNSColor(aColor) of me –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, colorDomainName:cdnStr, fontName:aDFontName as string, fontSize:aDFontSize} set startIndex to current application’s NSMaxRange(theRange) end repeat return (styleList of aSpd) end getAttributeRunsFromAttrString on retColorDomainNameFromNSColor(aCol) set hueVal to aCol’s hueComponent() set satVal to aCol’s saturationComponent() set brightVal to aCol’s brightnessComponent() if satVal ≤ 0.01 then set satVal to 0.0 set colName to "" if satVal = 0.0 then if brightVal ≤ 0.2 then set colName to "black" else if (brightVal > 0.95) then set colName to "white" else set colName to "gray" end if else if hueVal ≤ (15.0 / 360) or hueVal ≥ (330 / 360) then set colName to "red" else if hueVal ≤ (45.0 / 360) then set colName to "orange" else if hueVal < (70.0 / 360) then set colName to "yellow" else if hueVal < (150.0 / 360) then set colName to "green" else if hueVal < (190.0 / 360) then set colName to "cyan" else if (hueVal < 250.0 / 360.0) then set colName to "blue" else if (hueVal < 290.0 / 360.0) then set colName to "purple" else set colName to "magenta" end if end if return colName end retColorDomainNameFromNSColor |
リストから選択してアイテム番号を返す
AppleScriptの配列変数であるリスト型の変数(ただし、1次元)から選択し、選択した要素のアイテム番号(1はじまり)を数値で返すAppleScriptです。
AppleScriptに標準で用意されている「choose from list」コマンドは、選択した項目の文字列を返してきますが、その仕様だと困るケースがけっこうあります。
選択された要素の内容(文字列)ではなく、何項目(インデックス、アイテム番号)が選択されたかという情報を返してきてほしいところです。
そこで、ないなら作ってしまえばよいわけで、そういう仕様のルーチンを自分で作っておいたわけです。
AppleScript名:リストから選択してアイテム番号を返す |
set aList to {"red", "blue", "green", "white"} set aMes to "項目を選択してください" set aRes to retItemFromListByItemNo(aList, aMes) of me –> 3 (選択したアイテムの番号(1はじまり)が返る –リストから選択してアイテム番号を返す on retItemFromListByItemNo(aList, aMes) set aRes to choose from list aList with prompt aMes if aRes = false then return 0 set aRes to contents of item 1 of aRes set hitNum to 1 repeat with i in aList set j to contents of i if j is equal to aRes then exit repeat end if set hitNum to hitNum + 1 end repeat return hitNum end retItemFromListByItemNo |
都道府県リストから隣接都道府県を含む該当のコードを抽出する
膨大な位置情報の距離を計算するような場合に、対象の都道府県と隣接する都道府県に限定して距離計算を行うことで計算量を削減するためのAppleScriptです。
ある1点の位置情報に対して大量の地点との距離計算を行う処理は割とよくあります。自宅からの最寄駅の計算や、日本全国に点在している施設の最寄駅の計算などなどです。
たいていは、総当たりですべての計算対象との距離計算を行い、近い順でソートすることになります。自分の場合では日本国内の700か所ぐらいの(「戦場の絆」が設置されている)ゲームセンターの位置と日本全国の鉄道の駅(8,000か所程度)を比較して最寄駅を計算しました。
700 x 8,000 = 5,600,000回の距離計算を行うわけで、あまりに時間がかかるのでめまいがします(90分ぐらいかかりました)。1か所あたりの距離計算の所用時間は0.086秒程度なのでいちがいに遅いとはいえません(CocoaのCoreLocationの機能を使わないで、地球を球としてみなして近似的な距離計算を行えば速くなることでしょう)。
ここで、脳みそが頭に入っている人間であれば考えるわけです。もっと速く計算できる方法があるんじゃないか? と。
だいたい、北海道にある地点の最寄駅を求めるのに九州の最果てにある駅との距離計算を行う必要はありません。8,000箇所のすべての駅との距離計算を行う中には、膨大な「無意味な計算」が含まれています。この、「無意味な計算」を除外してあげれば、計算量が半分で済む場合には計算時間は半分になります。
そうやって考えていくと、都道府県レベルで隣接している地点については計算を行う必要がありますが、隣接していない都道府県にある駅との計算は行う意味がないことに気づきます。
そして実際に本テーブルを作成して計算に導入したところ、当初の90分が10分に短縮されました。さらに、データの持ち方を変えて最終的には5分ぐらいまで短縮できました。
「都道府県レベルで計算対象の除外ができて、高速処理を実現できたんだから、市区町村レベルの隣接情報を作って計算すれば、さらに高速化できるのでは?」
と考える人がいるかもしれません。ただ、その処理を実際に頭の中でシミュレーションしてみると、市区町村レベルでは「駅」が存在していないものもあったりで、日本国内に3,0000程度あるとみられるそのレベルの地方公共団体の隣接データの作成は大変です。たしかに高速化できるかもしれませんが、その成果は微々たるものになることでしょう(東京、名古屋、大阪などの大都市にかぎっては効果があるかも? その他の地域ではさほど効果はありません)。
対象は日本国内の都道府県。海外の住所情報でも同様に都道府県にコードを振って隣接情報をデータ化すれば同様の処理は可能です。
# BridgePlus Script Libraryを併用しなくてもすむ v2を追加掲載しておきました
AppleScript名:都道府県リストから隣接都道府県を含む該当のコードを抽出する |
— Created 2015-12-06 by Takaaki Naganoya — 2015 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use BridgePlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html property prefList : {{prefCode:1, prefName:"北海道", neighbors:{}}, {prefCode:2, prefName:"青森県", neighbors:{3, 5}}, {prefCode:3, prefName:"岩手県", neighbors:{2, 4, 5}}, {prefCode:4, prefName:"宮城県", neighbors:{3, 5, 6, 7}}, {prefCode:5, prefName:"秋田県", neighbors:{2, 3, 4, 6}}, {prefCode:6, prefName:"山形県", neighbors:{3, 4, 5, 7, 15}}, {prefCode:7, prefName:"福島県", neighbors:{4, 6, 8, 9, 10, 15}}, {prefCode:8, prefName:"茨城県", neighbors:{7, 9, 10, 11, 12}}, {prefCode:9, prefName:"栃木県", neighbors:{7, 8, 10, 11, 12}}, {prefCode:10, prefName:"群馬県", neighbors:{7, 9, 11, 15, 20}}, {prefCode:11, prefName:"埼玉県", neighbors:{8, 9, 10, 12, 13, 19, 20}}, {prefCode:12, prefName:"千葉県", neighbors:{8, 11, 13}}, {prefCode:13, prefName:"東京都", neighbors:{11, 12, 19, 14}}, {prefCode:14, prefName:"神奈川県", neighbors:{13, 19, 22}}, {prefCode:15, prefName:"新潟県", neighbors:{6, 7, 10, 16, 20}}, {prefCode:16, prefName:"富山県", neighbors:{15, 17, 20, 21}}, {prefCode:17, prefName:"石川県", neighbors:{16, 18, 21}}, {prefCode:18, prefName:"福井県", neighbors:{17, 21, 25, 26}}, {prefCode:19, prefName:"山梨県", neighbors:{11, 13, 14, 20, 22}}, {prefCode:20, prefName:"長野県", neighbors:{10, 11, 15, 16, 19, 21, 22, 23}}, {prefCode:21, prefName:"岐阜県", neighbors:{16, 17, 18, 20, 23, 24, 25}}, {prefCode:22, prefName:"静岡県", neighbors:{14, 19, 20, 23}}, {prefCode:23, prefName:"愛知県", neighbors:{20, 21, 22, 24}}, {prefCode:24, prefName:"三重県", neighbors:{21, 23, 25, 26, 29}}, {prefCode:25, prefName:"滋賀県", neighbors:{18, 21, 24, 26}}, {prefCode:26, prefName:"京都府", neighbors:{18, 24, 25, 27, 28, 29}}, {prefCode:27, prefName:"大阪府", neighbors:{26, 29, 28, 30}}, {prefCode:28, prefName:"兵庫県", neighbors:{26, 27, 31, 33}}, {prefCode:29, prefName:"奈良県", neighbors:{24, 25, 26, 27, 30}}, {prefCode:30, prefName:"和歌山県", neighbors:{24, 27, 29}}, {prefCode:31, prefName:"鳥取県", neighbors:{28, 33, 32, 34}}, {prefCode:32, prefName:"島根県", neighbors:{31, 34, 35}}, {prefCode:33, prefName:"岡山県", neighbors:{28, 31, 34}}, {prefCode:34, prefName:"広島県", neighbors:{33, 31, 32, 35}}, {prefCode:35, prefName:"山口県", neighbors:{32, 34}}, {prefCode:36, prefName:"徳島県", neighbors:{37, 39}}, {prefCode:37, prefName:"香川県", neighbors:{36, 38, 39}}, {prefCode:38, prefName:"愛媛県", neighbors:{37, 39}}, {prefCode:39, prefName:"高知県", neighbors:{36, 37, 38}}, {prefCode:40, prefName:"福岡県", neighbors:{44, 43, 41}}, {prefCode:41, prefName:"佐賀県", neighbors:{40, 42}}, {prefCode:42, prefName:"長崎県", neighbors:{41}}, {prefCode:43, prefName:"熊本県", neighbors:{40, 42, 44, 45, 46}}, {prefCode:44, prefName:"大分県", neighbors:{40, 43, 45}}, {prefCode:45, prefName:"宮崎県", neighbors:{43, 44, 46}}, {prefCode:46, prefName:"鹿児島県", neighbors:{43, 45}}, {prefCode:47, prefName:"沖縄県", neighbors:{}}} set aPref to 13 –Tokyo set aRes to my filterRecListByLabel2(prefList, "prefCode == [c]%@", {aPref}) set targList to neighbors of aRes & aPref –> {11, 12, 19, 14, 13}–Saitama, Chiba, yamanashi, Kanagawa, Tokyo –リストに入れたレコードを、指定の属性ラベルの値で抽出(predicateとパラメータを分離)し、1つのアイテムだけを返す on filterRecListByLabel2(aRecList as list, aPredicate as string, aParam) set aArray to current application’s NSArray’s arrayWithArray:aRecList set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate argumentArray:aParam set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate set bList to ASify from filteredArray as list set cList to first item of bList return cList end filterRecListByLabel2 |
AppleScript名:都道府県リストから隣接都道府県を含む該当のコードを抽出する v2.scpt |
— Created 2015-12-06 by Takaaki Naganoya — 2015 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" —BridgePlusを使わなくていいように書き換え property prefList : {{prefCode:1, prefName:"北海道", neighbors:{}}, {prefCode:2, prefName:"青森県", neighbors:{3, 5}}, {prefCode:3, prefName:"岩手県", neighbors:{2, 4, 5}}, {prefCode:4, prefName:"宮城県", neighbors:{3, 5, 6, 7}}, {prefCode:5, prefName:"秋田県", neighbors:{2, 3, 4, 6}}, {prefCode:6, prefName:"山形県", neighbors:{3, 4, 5, 7, 15}}, {prefCode:7, prefName:"福島県", neighbors:{4, 6, 8, 9, 10, 15}}, {prefCode:8, prefName:"茨城県", neighbors:{7, 9, 10, 11, 12}}, {prefCode:9, prefName:"栃木県", neighbors:{7, 8, 10, 11, 12}}, {prefCode:10, prefName:"群馬県", neighbors:{7, 9, 11, 15, 20}}, {prefCode:11, prefName:"埼玉県", neighbors:{8, 9, 10, 12, 13, 19, 20}}, {prefCode:12, prefName:"千葉県", neighbors:{8, 11, 13}}, {prefCode:13, prefName:"東京都", neighbors:{11, 12, 19, 14}}, {prefCode:14, prefName:"神奈川県", neighbors:{13, 19, 22}}, {prefCode:15, prefName:"新潟県", neighbors:{6, 7, 10, 16, 20}}, {prefCode:16, prefName:"富山県", neighbors:{15, 17, 20, 21}}, {prefCode:17, prefName:"石川県", neighbors:{16, 18, 21}}, {prefCode:18, prefName:"福井県", neighbors:{17, 21, 25, 26}}, {prefCode:19, prefName:"山梨県", neighbors:{11, 13, 14, 20, 22}}, {prefCode:20, prefName:"長野県", neighbors:{10, 11, 15, 16, 19, 21, 22, 23}}, {prefCode:21, prefName:"岐阜県", neighbors:{16, 17, 18, 20, 23, 24, 25}}, {prefCode:22, prefName:"静岡県", neighbors:{14, 19, 20, 23}}, {prefCode:23, prefName:"愛知県", neighbors:{20, 21, 22, 24}}, {prefCode:24, prefName:"三重県", neighbors:{21, 23, 25, 26, 29}}, {prefCode:25, prefName:"滋賀県", neighbors:{18, 21, 24, 26}}, {prefCode:26, prefName:"京都府", neighbors:{18, 24, 25, 27, 28, 29}}, {prefCode:27, prefName:"大阪府", neighbors:{26, 29, 28, 30}}, {prefCode:28, prefName:"兵庫県", neighbors:{26, 27, 31, 33}}, {prefCode:29, prefName:"奈良県", neighbors:{24, 25, 26, 27, 30}}, {prefCode:30, prefName:"和歌山県", neighbors:{24, 27, 29}}, {prefCode:31, prefName:"鳥取県", neighbors:{28, 33, 32, 34}}, {prefCode:32, prefName:"島根県", neighbors:{31, 34, 35}}, {prefCode:33, prefName:"岡山県", neighbors:{28, 31, 34}}, {prefCode:34, prefName:"広島県", neighbors:{33, 31, 32, 35}}, {prefCode:35, prefName:"山口県", neighbors:{32, 34}}, {prefCode:36, prefName:"徳島県", neighbors:{37, 39}}, {prefCode:37, prefName:"香川県", neighbors:{36, 38, 39}}, {prefCode:38, prefName:"愛媛県", neighbors:{37, 39}}, {prefCode:39, prefName:"高知県", neighbors:{36, 37, 38}}, {prefCode:40, prefName:"福岡県", neighbors:{44, 43, 41}}, {prefCode:41, prefName:"佐賀県", neighbors:{40, 42}}, {prefCode:42, prefName:"長崎県", neighbors:{41}}, {prefCode:43, prefName:"熊本県", neighbors:{40, 42, 44, 45, 46}}, {prefCode:44, prefName:"大分県", neighbors:{40, 43, 45}}, {prefCode:45, prefName:"宮崎県", neighbors:{43, 44, 46}}, {prefCode:46, prefName:"鹿児島県", neighbors:{43, 45}}, {prefCode:47, prefName:"沖縄県", neighbors:{}}} set aPref to 13 –Tokyo set aRes to my filterRecListByLabel2(prefList, "prefCode == [c]%@", {aPref}) set targList to neighbors of aRes & aPref –> {11, 12, 19, 14, 13}–Saitama, Chiba, yamanashi, Kanagawa, Tokyo –リストに入れたレコードを、指定の属性ラベルの値で抽出(predicateとパラメータを分離)し、1つのアイテムだけを返す on filterRecListByLabel2(aRecList as list, aPredicate as string, aParam) set aArray to current application’s NSArray’s arrayWithArray:aRecList set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate argumentArray:aParam set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate set bList to filteredArray as list set cList to first item of bList return cList end filterRecListByLabel2 |
2D ListをCSVに v3(サニタイズ処理つき)
AppleScript名:2D ListをCSVに v3(サニタイズ処理つき) |
— Created 2015-10-01 by Takaaki Naganoya — 2015 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set aNewFile to choose file name set dataList to {{"0010", "ひよこタオルギフト", "200", "手に取ったとき、\"使うとき\"、ちょっと楽しくてかわいいひよこのタオル。", "●サイズ/H200㎜×W200㎜●素材/ひよこ羽毛100%●重量/170g●内容/5枚入り"}, {"0020", "ひよこホイッスル", "250", "今までにないデザインの、ひよこ型のホイッスル。ぴよ〜音を音階で吹き分けます。", "●サイズ/H60㎜×W40㎜×D10㎜●素材/プラスチック ●色/ひよこ色●重量/10g●付属品/首かけロープ付き ●型番/PIYO1"}} saveAsCSV(dataList, aNewFile) of me –2D List to CSV file on saveAsCSV(aList, aPath) –set crlfChar to (ASCII character 13) & (ASCII character 10) 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 write_to_file(wholeText, bPath, false) of me end saveAsCSV on write_to_file(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 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 write_to_file 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 |
CSVのParse 5(ASOC)
AppleScript名:CSVのParse 5(ASOC) |
–Created By Shane Stanley 2015/03/12 –Commented & Arranged By Takaaki Naganoya 2015/03/12 use scripting additions use framework "Foundation" set theString to "cust1,\"prod,1\",season 1, cust1,prod1,season2, cust2,prod1,event1,season1 cust2,prod3,event1,season 1" its makeListsFromCSV:theString commaIs:"," –> {{"cust1", "prod,1", "season 1"}, {"cust1", "prod1", "season2"}, {"cust2", "prod1", "event1", "season1"}, {"cust2", "prod3", "event1", "season 1"}} –CSV Parser ASOC ver (Translated from "ASObjCExtras.framework" Objective-C version) on makeListsFromCSV:theString commaIs:theComma set theRows to {} –最終的に出力するデータ(2D Listになる) set newLineCharSet to current application’s NSCharacterSet’s newlineCharacterSet() –改行キャラクタ set importantCharSet to current application’s NSMutableCharacterSet’s characterSetWithCharactersInString:("\"" & theComma) –カンマ importantCharSet’s formUnionWithCharacterSet:newLineCharSet set theNSScanner to current application’s NSScanner’s scannerWithString:theString theNSScanner’s setCharactersToBeSkipped:(missing value) –データ末尾を検出するまでループ repeat while (theNSScanner’s isAtEnd() as integer = 0) set insideQuotes to false set finishedRow to false set theColumns to {} set currentColumn to "" –すべての行を処理終了するまでループ(行内部の処理) repeat while (not finishedRow) set {theResult, tempString} to theNSScanner’s scanUpToCharactersFromSet:importantCharSet intoString:(reference) –log {"theResult", theResult, "tempString", tempString} if theResult as integer = 1 then set currentColumn to currentColumn & (tempString as text) –log {"currentColumn", currentColumn} –データ末尾検出 if theNSScanner’s isAtEnd() as integer = 1 then if currentColumn is not "" then set end of theColumns to currentColumn set finishedRow to true else –データ末尾ではない場合 set {theResult, tempString} to theNSScanner’s scanCharactersFromSet:newLineCharSet intoString:(reference) if theResult as integer = 1 then if insideQuotes then –ダブルクォート文字内の場合 set currentColumn to currentColumn & (tempString as text) else –ダブルクォート内ではない場合 if currentColumn is not "" then set end of theColumns to currentColumn set finishedRow to true end if else –行末文字が見つからない場合 set theResult to theNSScanner’s scanString:"\"" intoString:(missing value) if theResult as integer = 1 then –ダブルクォート文字が見つかった場合 if insideQuotes then –ダブルクォート文字内の場合 set theResult to theNSScanner’s scanString:"\"" intoString:(missing value) if theResult as integer = 1 then set currentColumn to currentColumn & "\"" else set insideQuotes to (not insideQuotes) end if else –ダブルクォート文字内ではない場合 set insideQuotes to (not insideQuotes) end if else –ダブルクォート文字が見つからなかった場合 set theResult to theNSScanner’s scanString:theComma intoString:(missing value) –カンマの検索 if theResult as integer = 1 then if insideQuotes then set currentColumn to currentColumn & theComma else set end of theColumns to currentColumn set currentColumn to "" theNSScanner’s scanCharactersFromSet:(current application’s NSCharacterSet’s whitespaceCharacterSet()) intoString:(missing value) end if end if end if end if end if end repeat if (count of theColumns) > 0 then set end of theRows to theColumns –行データ(1D List)をtheRowsに追加(2D List) end repeat return theRows end makeListsFromCSV:commaIs: |
CSVのParse 4a(ASOC)
AppleScript名:CSVのParse 4a(ASOC) |
— Created 2015-03-11 by Shane Stanley use AppleScript version "2.4" use scripting additions use framework "Foundation" use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html load framework set someString to read (choose file of type {"public.comma-separated-values-text"}) set theData to current application’s SMSForder’s arrayFromCSV:someString commaIs:"," set theData to (current application’s SMSForder’s subarraysIn:theData paddedWith:"" |error|:(missing value)) as list –> {{"cust1", "prod,1", "season 1", ""}, {"cust1", "prod1", "season 2", ""}, {"cust2", "prod1", "event1", "season 1"}, {"cust2", "prod2", "event1", "season 2"}, {"cust2", "prod3", "event1", "season 1"}} |