Archive for the 'リスト処理(list)' Category

2017/10/12 リストの連結(Cocoa版やや高速版)

リスト(配列)の連結を行うAppleScriptのCocoa版の高速版です。

自分でも実験してCocoa版の実行速度が遅すぎたので不思議に思っていましたが、Shane Stanleyからツッコミがあって、「こう書くと速いよ」と教えてもらいました。

自分の環境で実行してみたところ、0.5 Sec前後。Pure AppleScriptの限界チューニング版(0.069 Sec)よりは10倍ぐらい遅いですが、arrayByAddingObjectsFromArray:で連結したときよりは10倍高速。このぐらいだと(Cocoa呼び出しで余計にかかる処理時間も)納得できる感じでしょうか。

AppleScript名:リストの連結(addObjectsFromArray)
– Created 2017-10-12 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4893

property NSMutableArray : a reference to current application’s NSMutableArray

set anArray to NSMutableArray’s new()

repeat 10000 times
  anArray’s addObjectsFromArray:{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
end repeat

return anArray

★Click Here to Open This Script 

2017/10/11 リストの連結

リスト(配列)の連結を行うAppleScriptのCocoa版です。

1Dリスト(1次元配列)同士の連結を行うのは、Pure AppleScriptだと、

set aList to {}
set bList to {1, 2, 3}
set cList to {4, 5, 6}

set the end of aList to bList
set the end of aList to cList
aList
–> {{1, 2, 3}, {4, 5, 6}}

★Click Here to Open This Script 

こういうやり方と、

set aList to {2, 3, 4, 5, 6}
set bList to {1, 2, 3, 4, 5}

aList & bList
–> {2, 3, 4, 5, 6, 1, 2, 3, 4, 5}

★Click Here to Open This Script 

というやり方があるわけですが、Cocoaの機能を用いたAppleScriptObjCだとリストの要素連結だと、

use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set anArray to current application’s NSMutableArray’s new()
anArray’s addObject:{1, 2, 3}
anArray’s addObject:{4, 5, 6}
anArray as list
–>  {{1, 2, 3}, {4, 5, 6}}

★Click Here to Open This Script 

これを使うことが多かったのですが、リストごと連結するパターンを試していなかったので、調べてみました。

AppleScript名:リストの連結(arrayByAddingObjectsFromArray)
– Created 2017-10-10 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4892

property NSMutableArray : a reference to current application’s NSMutableArray

set anArray to NSMutableArray’s new()

repeat 10000 times
  set anArray to anArray’s arrayByAddingObjectsFromArray:{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
end repeat

return (anArray as list)
–>  {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10…….}
–4.89sec

★Click Here to Open This Script 

ただし、小さいデータをこまかく連結する程度だとPure AppleScriptの方が速いので、巨大なデータを扱うとかXcode上でCocoa AppleScriptアプレットを作るためにサブルーチン間でCocoaオブジェクトをやりとりするような用途の場合に意識する程度でしょうか。

同じ要素数(10万アイテムの連結)でもPure AppleScriptで限界までチューニングして高速化すると0.069秒で処理終了します。

2017/10/10 なろう小説APIで各カテゴリごとの集計を実行

「小説家になろう」サイトのAPI「なろう小説API」を呼び出して、カテゴリごとの該当件数を集計するAppleScriptです。

「なろう小説API」は事前にAPI Keyの取得も不要で、簡単に呼び出せるのでお手軽に使えます。

本AppleScriptは、「小説家になろう」掲載作品を、大カテゴリと小カテゴリでコードを指定して、ループで存在件数の集計を行います。カテゴリごとに分布が偏っているようなので、該当件数が0件のカテゴリは結果出力しないようにしています。筆者の環境では集計に22〜25秒ぐらいかかっています(インターネット接続回線速度に依存)。

http headerにgzip転送リクエスト要求を書きつつ、実際のデータ自体もgzipで圧縮されているので、二重に圧縮している状態です。実測したところ、http headerでgzip指定を行なったほうがトータルで1秒程度速かったので「そんなもんかな」と思いつつ、そのままにしています。

Web APIからのデータ受信時のNSDataからのZip展開にオープンソースのフレームワーク「GZIP」(By Nick Lockwood)を利用しています。同プロジェクトはGithub上のXcodeプロジェクトをXcodeでビルドするとFrameworkが得られるので、ビルドして~/Library/FrameworksフォルダにGZIP.frameworkを入れてください。

ジャンルは数値で指定するようになっていますが、その数値が何を示しているかという情報はAPI側からの出力にはないので、Webサイト上から文字情報をコピペで取得し、AppleScript内に記載して(ハードコーディング)カテゴリコードリストと照合して出力しています。

実際に集計してみると、ノンカテゴリが53%ということで、カテゴリ分けの機能が有効に活用されていないことが見てとれます。

そのことについては運営側も重々承知しているようで、APIの検索オプションに「キーワードに異世界転生があるものを含む」といったものがあるなど、ジャンルよりもキーワード重視するようにしているようです。

そういいつつも、使われているキーワードについては若干の表記ゆらぎがあるようで、単純にこのオプションを指定しても「異世界転生もの」をすべて抽出できていないように見えます。キーワード自体にどの程度「表記揺れ」が存在しているのかを調べてみるとよいのかもしれません。

APIの仕様上、2,000件しか詳細データを取得できないように見えるので、そのあたりがちょっと気になります(どうも全数調査を行いにくい仕様)。

分析するまでもなく、異世界転生ものが多く、ノンジャンル作品でも異世界転生ものばっかりという印象です。掘り出しもので「ソ連の宇宙技術は最強過ぎたのだが、それを西側諸国が完全に理解したのはつい最近だった」という作品に行き当たり、これが強烈に面白いです。

AppleScript名:なろう小説APIで各カテゴリごとの集計を実行
– Created 2017-10-10 by Takaaki Naganoya
– 2017 Piyomaru Software
–http://piyocast.com/as/archives/4891
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “GZIP”
–https://github.com/nicklockwood/GZIP
–http://dev.syosetu.com/man/api/
–1日の利用上限は80,000または転送量上限400MByte???

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSArray : a reference to current application’s NSArray
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSURLQueryItem : a reference to current application’s NSURLQueryItem
property NSURLComponents : a reference to current application’s NSURLComponents
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSURLConnection : a reference to current application’s NSURLConnection
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSNumber : a reference to current application’s NSNumber
property NSNumberFormatter : a reference to current application’s NSNumberFormatter
property NSNumberFormatterRoundUp : a reference to current application’s NSNumberFormatterRoundUp
property NSNumberFormatterRoundDown : a reference to current application’s NSNumberFormatterRoundDown

set invList to {}

set bgList to {1, 2, 3, 4, 99, 98}
set bigGnereLabel to {“恋愛”, “ファンタジー”, “文芸”, “SF”, “その他”, “ノンジャンル”}

set gList to {101, 102, 201, 202, 301, 302, 303, 304, 305, 306, 307, 401, 402, 403, 404, 9901, 9902, 9903, 9904, 9999, 9801}
set smlGenreLabel to {“異世界〔恋愛〕”, “現実世界〔恋愛〕”, “ハイファンタジー〔ファンタジー〕”, “ローファンタジー〔ファンタジー〕”, “純文学〔文芸〕”, “ヒューマンドラマ〔文芸〕”, “歴史〔文芸〕”, “推理〔文芸〕”, “ホラー〔文芸〕”, “アクション〔文芸〕”, “コメディー〔文芸〕”, “VRゲーム〔SF〕”, “宇宙〔SF〕”, “空想科学〔SF〕”, “パニック〔SF〕”, “童話〔その他〕”, “詩〔その他〕”, “エッセイ〔その他〕”, “リプレイ〔その他〕”, “その他〔その他〕”, “ノンジャンル〔ノンジャンル〕”}

–全体の件数取得
set aRec to {gzip:“5″, out:“json”, lim:“1″}
set aRESTres to callNarouAPI(aRec, “1″, “1″) of me
set wholeCount to (allCount of first item of aRESTres)

–カテゴリごとの集計
repeat with i in bgList
  repeat with ii in gList
    set aRec to {gzip:“5″, biggenre:i as string, genre:ii as string, out:“json”, lim:“1″}
    
set aRESTres to callNarouAPI(aRec, “1″, “1″) of me
    
set aTotal to allCount of first item of aRESTres
    
    
if aTotal is not equal to 0 then
      set big to contents of i
      
set small to contents of ii
      
set bigLabel to getLabelFromNum(bgList, bigGnereLabel, big) of me
      
set smlLabel to getLabelFromNum(gList, smlGenreLabel, small) of me
      
set aPerCentatge to roundingDownNumStr(((aTotal / wholeCount) * 100), 1) of me
      
set the end of invList to {biggenre:bigLabel, genre:smlLabel, totalNum:aTotal, percentage:aPerCentatge}
    end if
  end repeat
end repeat

set bList to sortRecListByLabel(invList, “totalNum”, false) of me –降順ソート
–> {{totalNum:274072, biggenre:”ノンジャンル”, percentage:53.1, genre:”ノンジャンル〔ノンジャンル〕”}, {totalNum:47121, biggenre:”ファンタジー”, percentage:9.1, genre:”ハイファンタジー〔ファンタジー〕”}, {totalNum:28883, biggenre:”恋愛”, percentage:5.6, genre:”現実世界〔恋愛〕”}, {totalNum:23217, biggenre:”文芸”, percentage:4.5, genre:”ヒューマンドラマ〔文芸〕”}, {totalNum:21320, biggenre:”ファンタジー”, percentage:4.1, genre:”ローファンタジー〔ファンタジー〕”}, {totalNum:17079, biggenre:”恋愛”, percentage:3.3, genre:”異世界〔恋愛〕”}, {totalNum:16798, biggenre:”その他”, percentage:3.2, genre:”その他〔その他〕”}, {totalNum:13892, biggenre:”その他”, percentage:2.6, genre:”詩〔その他〕”}, {totalNum:13341, biggenre:”文芸”, percentage:2.5, genre:”コメディー〔文芸〕”}, {totalNum:10120, biggenre:”文芸”, percentage:1.9, genre:”ホラー〔文芸〕”}, {totalNum:9502, biggenre:”その他”, percentage:1.8, genre:”エッセイ〔その他〕”}, {totalNum:8486, biggenre:”文芸”, percentage:1.6, genre:”純文学〔文芸〕”}, {totalNum:7211, biggenre:”文芸”, percentage:1.3, genre:”アクション〔文芸〕”}, {totalNum:6199, biggenre:”SF”, percentage:1.2, genre:”空想科学〔SF〕”}, {totalNum:5780, biggenre:”その他”, percentage:1.1, genre:”童話〔その他〕”}, {totalNum:3295, biggenre:”文芸”, percentage:0.6, genre:”推理〔文芸〕”}, {totalNum:3217, biggenre:”文芸”, percentage:0.6, genre:”歴史〔文芸〕”}, {totalNum:2606, biggenre:”SF”, percentage:0.5, genre:”VRゲーム〔SF〕”}, {totalNum:1471, biggenre:”SF”, percentage:0.2, genre:”パニック〔SF〕”}, {totalNum:1454, biggenre:”SF”, percentage:0.2, genre:”宇宙〔SF〕”}, {totalNum:190, biggenre:”その他”, percentage:0.0, genre:”リプレイ〔その他〕”}}

on callNarouAPI(aRec, callFrom, callNum)
  set reqURLStr to “http://api.syosetu.com/novelapi/api/” –通常API
  
  
–set aRec to {gzip:”5″, |st|:callFrom as string, out:”json”, lim:callNum as string}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
set aRes to callRestGETAPIAndParseResults(aURL) of me
  
  
set aRESCode to (responseCode of aRes) as integer
  
if aRESCode is not equal to 200 then return false
  
  
set aRESHeader to responseHeader of aRes
  
set aRESTres to (json of aRes) as list
  
end callNarouAPI

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to NSMutableURLRequest’s requestWithURL:(|NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setValue:“gzip” forHTTPHeaderField:“Content-Encoding”
  
  
set aRes to NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
  
set rRes to bRes’s gunzippedData() –From GZIP.framework
  
  
set resStr to NSString’s alloc()’s initWithData:rRes encoding:(NSUTF8StringEncoding)
  
  
set jsonString to NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

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

on getLabelFromNum(aList, labelLIst, aNum)
  set aInd to offsetOf(aList, aNum) of me
  
set anItem to contents of item aInd of labelLIst
  
return anItem
end getLabelFromNum

on offsetOf(aList as list, aTarg)
  set aArray to current application’s NSArray’s arrayWithArray:aList
  
set aIndex to aArray’s indexOfObjectIdenticalTo:aTarg
  
return (aIndex + 1)
end offsetOf

on roundingDownNumStr(aNum as string, aDigit as integer)
  set a to NSString’s stringWithString:aNum
  
set aa to a’s doubleValue()
  
set aFormatter to NSNumberFormatter’s alloc()’s init()
  
aFormatter’s setMaximumFractionDigits:aDigit
  
aFormatter’s setRoundingMode:(NSNumberFormatterRoundDown)
  
set aStr to aFormatter’s stringFromNumber:aa
  
return (aStr as text) as real
end roundingDownNumStr

on roundingUpNumStr(aNum as string, aDigit as integer)
  set a to NSString’s stringWithString:aNum
  
set aa to a’s doubleValue()
  
set aFormatter to NSNumberFormatter’s alloc()’s init()
  
aFormatter’s setMaximumFractionDigits:aDigit
  
aFormatter’s setRoundingMode:(NSNumberFormatterRoundUp)
  
set aStr to aFormatter’s stringFromNumber:aa
  
return (aStr as text) as real
end roundingUpNumStr

★Click Here to Open This Script 

2017/10/07 なろう小説APIを呼び出す v2(Zip展開つき)

「小説家になろう」サイトのAPI「なろう小説API」を呼び出してデータを取得するAppleScriptです。

「なろう小説API」は事前にAPI Keyの取得も不要で、簡単に呼び出せるのでお手軽に使えます。用意されているのはデータ取得のメソッドであり、結果の保持や集計、しぼりこみについてはローカル側で勝手に行う放任仕様です条件抽出のパラメータもあります。

ただし、本APIが用意しているZip圧縮を利用するのに少々骨が折れました。

http header中でContent-Encodingに「gzip」を指定する程度では対応できませんでした。Zip圧縮転送指定時(パラメータにgzipを指定)APIから返ってくるデータそのものがZip圧縮されており、APIから返ってきたデータそのもの(NSData)を展開する必要がありました。

そこで、NSDataをそのままZip展開できるオープンソースのフレームワーク「GZIP」(By Nick Lockwood)を利用してみました。同プロジェクトはGithub上のXcodeプロジェクトをXcodeでビルドするとFrameworkが得られるので、ビルドして~/Library/FrameworksフォルダにGZIP.frameworkを入れてください。

とりあえず呼び出して500件のデータを取得していますが、500件ずつ取得してループするように書き換えるとよいでしょう。

AppleScript名:なろう小説API v2(Zip展開つき)
– Created 2017-10-03 by Takaaki Naganoya
– 2017 Piyomaru Software
–http://piyocast.com/as/archives/4890
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “GZIP”
–https://github.com/nicklockwood/GZIP
–http://dev.syosetu.com/man/api/
–1日の利用上限は80,000または転送量上限400MByte???

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSURLQueryItem : a reference to current application’s NSURLQueryItem
property NSURLComponents : a reference to current application’s NSURLComponents
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSURLConnection : a reference to current application’s NSURLConnection

set reqURLStr to “http://api.syosetu.com/novelapi/api/” –通常API
–set reqURLStr to “http://api.syosetu.com/novel18api/api/”–18禁API

set aRec to {gzip:“5″, out:“json”, lim:“500″}

set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESCode to (responseCode of aRes) as integer
if aRESCode is not equal to 200 then return false

set aRESHeader to responseHeader of aRes
set aRESTres to (json of aRes) as list

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to NSMutableURLRequest’s requestWithURL:(|NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setValue:“gzip” forHTTPHeaderField:“Content-Encoding”
  
  
set aRes to NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
  
set rRes to bRes’s gunzippedData() –From GZIP.framework
  
  
set resStr to NSString’s alloc()’s initWithData:rRes encoding:(NSUTF8StringEncoding)
  
  
set jsonString to NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

★Click Here to Open This Script 

2017/10/01 横書きテキストを縦書きに変換 v4

指定のテキストを強制的に擬似的な縦書きテキストに変換するAppleScriptです。

Twitter投稿時に縦書きで投稿する用途に向けて書いてみたものです。1行あたりの文字数を指定して擬似縦書きテキストに変換します。

vertical.png

ただ、行間に空白文字の行を入れるため、オリジナルの横書きテキストよりも情報密度が下がります。140文字の制限を超過しやすくもなるので、縦書きテキスト作成後に文字数をカウントして超過時にエラーを返す処理も必要になることでしょう。

original_horizontal.png

converted_vertial.png

一応、とりあえずレベルで横書き用の記号類を縦書き用の記号類に置き換えています。禁則処理は一切行なっていないので、それっぽい禁則処理を行なってみるとよいのではないでしょうか?

また、数値についても「日本語数値表現エンコーダー」を使えば2000→2千とエンコードすることも可能ですが、形態素解析を行なって対象の数値が何であるか、桁数が4桁以内で西暦を示していたら日本語数値エンコーディングを適用しないなどの対処が必要に見えます。

AppleScript名:横書きテキストを縦書きに変換 v4
– Created 2017-09-30 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4864

property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSStringTransformFullwidthToHalfwidth : a reference to current application’s NSStringTransformFullwidthToHalfwidth

set lineMax to 9
set aText to “やせがへる
負けるな一茶
これにあり”

set sRes to makeTategakiStr(lineMax, aText) of me

–縦行数を指定しつつ指定テキストを縦書き化
on makeTategakiStr(lineMax, aText)
  set curMax to 0
  
set sList to paragraphs of aText –途中で強制改行が入っているケースに対処
  
set aList to {}
  
  
repeat with i in sList
    set outList to strToTategakiList(lineMax, i) of me
    
set aList to aList & outList
  end repeat
  
  
set curLen to length of aList
  
set curMax to getMaxItemCountFrom2DArray(aList) of me
  
  
set tmpList to {}
  
  
set twoDList to make2DBlankArray(curLen, curMax) of me
  
  
set curY to 1
  
repeat with x from 1 to curMax
    
    
set curX to 1
    
repeat with y from curLen to 1 by -1
      set aCon to getItemByXY(x, y, aList, “ ”) of me
      
set twoDList to setItemByXY(curX, curY, twoDList, aCon as string) of me
      
set curX to curX + 1
    end repeat
    
    
set curY to curY + 1
  end repeat
  
  

  
set aRes to list2dToStringByUsingDelimiters(twoDList, “ ”, return) of me
  
set zRes to hanToZen(aRes) of me
  
  
return zRes
end makeTategakiStr

–与えた文字列を縦書き2Dリストに変換
on strToTategakiList(lineMax, aText)
  set zText to hanToZen(aText) of me
  
  
set outList to {}
  
set oneLine to {}
  
set aCount to 1
  
set curMax to 0
  
  
repeat with i from 1 to (length of aText)
    set aChar to character i of aText
    
    
set aChar to retTateChar(aChar) of me
    
    
set the end of oneLine to aChar
    
    
set aCount to aCount + 1
    
if aCount > lineMax then
      set aCount to 1
      
set the end of outList to oneLine
      
set oneLine to {}
    end if
  end repeat
  
  
if oneLine is not equal to {} then
    set the end of outList to oneLine
  end if
  
  
return outList
end strToTategakiList

–半角→全角変換
on hanToZen(aStr)
  set aString to NSString’s stringWithString:aStr
  
return (aString’s stringByApplyingTransform:(NSStringTransformFullwidthToHalfwidth) |reverse|:true) as string
end hanToZen

–2D Listに配列の添字的なアクセスを行なってデータを取得
on getItemByXY(aX, aY, aList, aBlankItem) –1 based index
  try
    set aContents to contents of (item aX of item aY of aList)
  on error
    set aContents to aBlankItem
  end try
  
return aContents
end getItemByXY

–2D Listに配列の添字的なアクセスを行なってデータを設定
on setItemByXY(aX, aY, tmpList, aContents) –1 based index
  set (item aX of item aY of tmpList) to aContents
  
return tmpList
end setItemByXY

–空白の2D Array を出力する
on make2DBlankArray(curLen, curMax)
  set outArray to {}
  
repeat curMax times
    set tmpList to {}
    
repeat curLen times
      set the end of tmpList to “”
    end repeat
    
set the end of outArray to tmpList
  end repeat
  
return outArray
end make2DBlankArray

–2D Listをアイテム間デリミタ、および行間デリミタを指定しつつテキスト化
on list2dToStringByUsingDelimiters(aList, itemDelimiter, lineDelimiter)
  set outList to {}
  
repeat with i in aList
    set aStr to listToStringUsingTextItemDelimiter(i, itemDelimiter) of me
    
set the end of outList to aStr
  end repeat
  
  
return listToStringUsingTextItemDelimiter(outList, lineDelimiter) of me
end list2dToStringByUsingDelimiters

–1D Listをアイテム間デリミタ、および行間デリミタを指定しつつテキスト化
on listToStringUsingTextItemDelimiter(sourceList, textItemDelimiter)
  set anArray to NSArray’s arrayWithArray:sourceList
  
return (anArray’s componentsJoinedByString:textItemDelimiter) as string
end listToStringUsingTextItemDelimiter

–2D Listの各要素のアイテム数のうち最多のものを返す
on getMaxItemCountFrom2DArray(aList)
  set anArray to NSArray’s arrayWithArray:aList
  
set bArray to (anArray’s valueForKeyPath:“@unionOfObjects.@count”)
  
return (bArray’s valueForKeyPath:“@max.self”) as integer
end getMaxItemCountFrom2DArray

on retTateChar(aChar)
  if aChar = then return “︿”
  
if aChar = then return “﹀”
  

  
if aChar = then return “︽”
  
if aChar = then return “︾”
  

  
if aChar = “「” then return “﹁”
  
if aChar = “」” then return “﹂”
  

  
if aChar = “『” then return “﹃”
  
if aChar = “』” then return “﹄”
  

  
if aChar = “【” then return “︻”
  
if aChar = “】” then return “︼”
  

  
if aChar = “[” then return
  
if aChar = “]” then return
  

  
if aChar = “{” then return “︷”
  
if aChar = “}” then return “︸”
  

  
if aChar = “(” then return “︵”
  
if aChar = “)” then return “︶”
  

  
if aChar = “、” then return
  
if aChar = “。” then return
  
if aChar = “ー” then return “︱”
  
if aChar = “〜” then return
  
if aChar = “=” then return “‖”
  

  
if aChar = “1” then return “一”
  
if aChar = “2” then return “二”
  
if aChar = “3” then return “三”
  
if aChar = “4” then return “四”
  
if aChar = “5” then return “五”
  
if aChar = “6” then return “六”
  
if aChar = “7” then return “七”
  
if aChar = “8” then return “八”
  
if aChar = “9” then return “九”
  
if aChar = “0” then return “〇”
  
  
return aChar
end retTateChar

★Click Here to Open This Script 

2017/09/06 ツイ4のページで新規連載マンガの画像を取得してPDF化(新規連載のPDF化)v3

Safariで表示中のWebマンガサイト「ツイ4」(更新情報をTwitterに投稿)のマンガを全エピソードダウンロードしてPDFにまとめるAppleScriptです。

実行にあたってはShane StanleyのAppleScript Libraries「BridgePlus」のインストールを必要とします(~/ibrary/Script Librariesフォルダに入れるだけ)。

実行開始時にはSafariでツイ4の特定のマンガのページをオープンしている必要があります。

tui4.png

Safariの最前面のウィンドウからURLやTitle、リンクされている画像の詳細情報を取得し、条件チェックなどを行なったのちに詳細なデータの抽出を行います。

次に、PDFの保存先を選択するダイアログを表示。このさい、デフォルトの保存先を「ピクチャ」フォルダ、ファイル名をマンガのタイトルに指定。

ページにリンクされていた画像(ツイではファイル名はシーケンシャル番号)から番号の情報だけを抽出して最大値、最小値を計算。この範囲で画像のダウンロード、PDFへの追記を行います。ただし、実運用してみたところ、Safariからすべての画像を取得できないようで(非同期表示しているようなので)、とりあえず1〜9999までの番号の画像を順次ダウンロードし、画像が存在しなければ処理を終了しています。

画像をダウンロードするたびにPDFに追記していますが、このあたりは途中でエラーが出て停止してもそれまでの処理内容が保存されることを意図してのことです。SSD搭載機では問題のない処理ですが、HDD搭載機では若干遅く感じるかもしれません(もはやHDD搭載機が身の回りにないので不明)。

これまでは、マンガの新規連載がはじまるとcurlコマンドで画像をダウンロードしてPDFに連結する作業を手で行なっていたのですが(誰も頼んでねえよ)、新規連載が増えたので自動化してみました。それでもありあわせの部品を組み合わせただけなので、それほど手間はかかっていません。

本Scriptとは別に更新された差分をPDFに連結するAppleScriptを作って日々実行し、大きな画面でブラウズするのに役立てています。割とこういう、ごくごく私的なScriptで野心的な処理を先行してテストしているものです。

AppleScript名:ツイ4のページで新規連載マンガの画像を取得してPDF化(新規連載のPDF化)v3
– Created 2016-09-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “QuartzCore”
use BridgePlus : script “BridgePlus”
–http://piyocast.com/as/archives/4808

property SMSForder : a reference to current application’s SMSForder
property |NSURL| : a reference to current application’s |NSURL|
property NSURLRequest : a reference to current application’s NSURLRequest
property NSURLConnection : a reference to current application’s NSURLConnection
property NSArray : a reference to current application’s NSArray
property NSFileManager : a reference to current application’s NSFileManager
property NSNumberFormatter : a reference to current application’s NSNumberFormatter
property NSPredicate : a reference to current application’s NSPredicate
property PDFPage : a reference to current application’s PDFPage
property PDFDocument : a reference to current application’s PDFDocument
property NSURLRequestUseProtocolCachePolicy : a reference to current application’s NSURLRequestUseProtocolCachePolicy
property NSNumberFormatterPadBeforePrefix : a reference to current application’s NSNumberFormatterPadBeforePrefix
property NSImage : a reference to current application’s NSImage
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSNumber : a reference to current application’s NSNumber
property NSRegularExpressionDotMatchesLineSeparators : a reference to current application’s NSRegularExpressionDotMatchesLineSeparators
property NSRegularExpressionAnchorsMatchLines : a reference to current application’s NSRegularExpressionAnchorsMatchLines
property NSRegularExpression : a reference to current application’s NSRegularExpression
property NSString : a reference to current application’s NSString

property theTargetSite : “http://sai-zen-sen.jp/”

tell application “Safari”
  if (count every document) = 0 then
    display notification “Safari does not open web page”
    
return
  end if
  
  
set docTitle to (do JavaScript “document.title” in front document) –Title
  
  
tell front document –URL
    set aURL to URL
  end tell
end tell

if aURL does not start with theTargetSite then
  display notification “This site is not the target”
  
return
end if

–Safariの最前面のウィンドウから画像リンクをすべて取得(Height, Width, URL)
set aList to getImageSizeAndURLOfFrontSafariDocument() of me

–取得した画像情報の2D Listをサイズで降順ソート
load framework –Force loading BridgePlus framework
set sortIndexes to {0, 1} –Key Item id: begin from 0
set sortOrders to {false, false}
set sortTypes to {“compare:”, “compare:”}
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:sortIndexes ascending:sortOrders sortTypes:sortTypes |error|:(missing value))

–画像が取得できなかったら処理終了
if (resList as list) = {} then
  display notification “There is no images on this page”
  
return –No Result
end if

–最大サイズの画像情報を取得する(おそらくマンガ)
set {maxHeight, maxWidth, maxURL} to contents of first item of (resList as list)

set aNSURL to |NSURL|’s URLWithString:maxURL
set aNSURLfilename to (aNSURL’s lastPathComponent())
set aNSURLpure to aNSURL’s URLByDeletingLastPathComponent()
set aNSURLextension to aNSURLfilename’s pathExtension() as string
set aNSURLfilenameLen to (aNSURLfilename’s stringByDeletingPathExtension())’s |length|() as integer –画像ファイル名から拡張子を除去した部分の文字列長

–画像情報リストを画像サイズで抽出
set maxHeightStr to (maxHeight as integer) as string
set maxWidthStr to (maxWidth as integer) as string
set thePred to NSPredicate’s predicateWithFormat:(“(self[0] == “ & maxHeightStr & “) AND (self[1] == “ & maxWidthStr & “)”)
set bArray to (resList’s filteredArrayUsingPredicate:thePred) as list

–URLからファイル名の数値部分のみ抽出
set imageArray to current application’s NSMutableArray’s new()
repeat with i in bArray
  set j to contents of last item of i –(Image URL)
  
set aTmpURL to (|NSURL|’s URLWithString:j)
  
set aTmpfilename to (aTmpURL’s lastPathComponent()) as string
  
set numStr to first item of (my findPattern:(“^\\d{1,” & (aNSURLfilenameLen as string) & “}”) inString:aTmpfilename)
  
set jj2 to (SMSForder’s transformedFrom:numStr ICUTransform:“Fullwidth-Halfwidth” inverse:false) as integer
  (
imageArray’s addObject:jj2)
end repeat

–ファイル名から抽出した数値の最小値と最大値を求める。ただ、実運用したらWeb側から画像をすべて取得されない(非同期読み込みを行なっているらしい)ケースがあったため、ここの値は参考値程度にしか使えなかった
set maxRes to (imageArray’s valueForKeyPath:“@max.self”)’s intValue() –最大値
set minRes to (imageArray’s valueForKeyPath:“@min.self”)’s intValue() –最小値
log {minRes, maxRes}

–PDFのファイル名と場所をユーザーに確認
set pdfFile to (choose file name with prompt “Select PDF Name & Location” default location (path to pictures folder) default name (docTitle & “.pdf”))
set pdfFilePOSIX to POSIX path of pdfFile
set newFilePath to current application’s NSString’s stringWithString:pdfFilePOSIX

–Make Blank PDF
set aPDFdoc to PDFDocument’s alloc()’s init()

–Download each image and append to blank PDF
set insCount to 1 –画像ダウンロード用のページ数(Loop Counter)とPDF連結用のページ番号(insCount)を分離

–repeat with i from minRes as integer to maxRes as integer
repeat with i from 1 to 9999
  –URL部品の連結
  
set aFILENAME to numToZeroPaddingStr(i, aNSURLfilenameLen, “0″) of me
  
set aFULLURL to (aNSURLpure’s absoluteString() as string) & (aFILENAME as string) & “.” & (aNSURLextension as string)
  
set aURL to (|NSURL|’s URLWithString:aFULLURL)
  
  
–URL(画像)をダウンロード
  
set {uRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me
  
  
if uRes = true then
    display notification “Episode “ & (i as string) & ” exists…”
    
set bImage to (NSImage’s alloc()’s initWithData:aData)
    (
aPDFdoc’s insertPage:(PDFPage’s alloc()’s initWithImage:bImage) atIndex:(insCount - 1))
    (
aPDFdoc’s writeToFile:newFilePath) –1Page更新するたびにファイル保存
    
set changedF to true –PDFにページが追記されたことを検出
  else
    display notification “No more new episode….”
    
exit repeat
  end if
  
  
set insCount to insCount + 1
end repeat

–FinderコメントにURLを記入
tell application “Finder”
  set comment of (pdfFile as alias) to (aNSURLpure’s absoluteString() as string)
end tell

–生成したPDFをオープン。ビューワー経由ではなくFinder経由でopen命令を送って表示
tell application “Finder”
  open (pdfFile as alias)
end tell
–ここで処理終了

—————

on getImageSizeAndURLOfFrontSafariDocument()
  set aList to {}
  
  
tell application “Safari”
    if its running then
      if (count every document) = 0 then return {}
      
set aRes to (do JavaScript “document.images.length” in front document)
      
      
repeat with i from 0 to (aRes - 1)
        set aHeight to do JavaScript ((“document.images[” & i as string) & “].height”) in front document
        
set aWidth to do JavaScript ((“document.images[” & i as string) & “].width”) in front document
        
set aSRC to do JavaScript ((“document.images[” & i as string) & “].src”) in front document
        
set the end of aList to {aHeight, aWidth, aSRC}
      end repeat
    end if
  end tell
  
  
return aList
end getImageSizeAndURLOfFrontSafariDocument

on findPattern:thePattern inString:theString
  set theOptions to ((NSRegularExpressionDotMatchesLineSeparators) as integer) + ((NSRegularExpressionAnchorsMatchLines) as integer)
  
set theRegEx to 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
  
set theResult to {}
  
set theNSString to NSString’s stringWithString:theString
  
  
repeat with i in theFinds
    set theRange to (contents of i)’s range()
    
set end of theResult to (theNSString’s substringWithRange:theRange) as string
  end repeat
  
return theResult
end findPattern:inString:

–1D List(文字)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DList:theList ascOrder:aBool
  set aDdesc to NSSortDescriptor’s sortDescriptorWithKey:“self” ascending:aBool selector:“localizedCaseInsensitiveCompare:”
  
set theArray to NSArray’s arrayWithArray:theList
  
return (theArray’s sortedArrayUsingDescriptors:{aDdesc}) as list
end sort1DList:ascOrder:

–整数の値に指定桁数ゼロパディングして文字列で返す
on numToZeroPaddingStr(aNum as integer, aDigit as integer, paddingChar as text)
  set aNumForm to NSNumberFormatter’s alloc()’s init()
  
aNumForm’s setPaddingPosition:(NSNumberFormatterPadBeforePrefix)
  
aNumForm’s setPaddingCharacter:paddingChar
  
aNumForm’s setMinimumIntegerDigits:aDigit
  
  
set bNum to NSNumber’s numberWithInt:aNum
  
set aStr to aNumForm’s stringFromNumber:bNum
  
  
return aStr as text
end numToZeroPaddingStr

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (NSURLRequest’s requestWithURL:aURL cachePolicy:(NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to 404
  end if
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

–指定PDFのページ数をかぞえる(10.9対応。普通にPDFpageから取得)
–返り値:PDFファイルのページ数(整数値)
on pdfPageCount(aFile)
  set aFile to POSIX path of aFile
  
set theURL to |NSURL|’s fileURLWithPath:aFile
  
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:theURL
  
set aRes to aPDFdoc’s pageCount()
  
return aRes as integer
end pdfPageCount

★Click Here to Open This Script 

2017/08/17 japaneseTokenizeのじっけん

macOSの日本語形態素解析の機能を呼び出して日本語テキストをParseするCocoa Framework「japaneseTokenize.framework」を作成しました。それを呼び出すAppleScriptです。

「japaneseTokenize.framework」はゼロから書いたはじめてのObjective-Cのプログラムでもあります(ほぼコピペで作成してありますが)。Header Fileなんて書かないので、見よう見真似&XcodeのWarning Messageのいいなりで試行錯誤していました。

CFStringTokenizer経由で形態素解析してふりがな、元テキスト、ローマ字ふりがなを取得する「parseString:」と、NSLinguisticTagger経由で形態素解析して元テキスト、品詞を取得する「parseStringWithLinguisticTag:」の2つのメソッドを用意してみました。

これら2つの形態素解析機能のparseの結果が矛盾しているかどうかは未確認です(短い文章では同じことを確認してありますが、長い文章でも同じかどうかは未確認。多分同じだとは思いますけれども)。

(CFStringTokenizer)parseString:
(*これ, ら, 2, つ, の, 形態, 素, 解析, 機能, の, parse, の, 結果, が, 矛盾, し, て, いる, か, どう, か, は, 未, 確認, です, 。, 短い, 文章, で, は, 同じ, こと, を, 確認, し, て, あり, ます, が, 、, 長い, 文章, で, も, 同じ, か, どう, か, は, 未, 確認, 。, 多分, 同じ, だ, と, は, 思い, ます, けれど, も, 。*)

(NSLinguisticTagger) parseStringWithLinguisticTag:
(*これら, 2つ, の, 形態素, 解析, 機能, の, parse, の, 結果, が, 矛盾, し, て, いる, か, どう, か, は, 未, 確認, です, 。, 短い, 文章, で, は, 同じ, こと, を, 確認, し, て, あり, ます, が, 、, 長い, 文章, で, も, 同じ, か, どう, か, は, 未, 確認, 。, 多分, 同じ, だ, と, は, 思い, ます, けれど, も, 。*)

(ご参考) AppleScriptの「words of」の実行結果
(*これ, ら, 2, つ, の, 形態, 素, 解析, 機能, の, parse, の, 結果, が, 矛盾, し, て, いる, か, どう, か, は, 未, 確認, です, 短い, 文章, で, は, 同じ, こと, を, 確認, し, て, あり, ます, が, 長い, 文章, で, も, 同じ, か, どう, か, は, 未, 確認, 多分, 同じ, だ, と, は, 思い, ます, けれど, も*)

# うわ、まさかの「微妙に形態素解析結果が違っている」パターンが来た、、、(ーー; macOS 10.13 Betaで試してみたところ、CFStringTokenizer側の形態素解析結果に合わせてNSLinguisticTagger側の出力結果を修正している模様

NSLinguisticTaggerが返す品詞については、いまひとつしっくりこないですし、ユーザーが定義したユーザー定義辞書を考慮して形態素解析したりしないので、実用性についてはさっぱりな印象です。さまざまなWeb APIをAppleScriptから呼び出してみた印象からいえば、Apitoreの形態素解析APIが一番納得できる内容に見えます(Googleの形態素解析APIはまだ呼んでいません)。

jparsers.png

Yahoo!日本語形態素解析Web APIによる解析結果:
–> {ResultSet:{attributes:{xmlns:”urn:yahoo:jp:jlp”, |xsi:schemalocation|:”urn:yahoo:jp:jlp https://jlp.yahooapis.jp/MAService/V1/parseResponse.xsd”, |xmlns:xsi|:”http://www.w3.org/2001/XMLSchema-instance”}, ma_result:{total_count:{|contents|:”8″}, filtered_count:{|contents|:”8″}, word_list:{|word|:{{surface:{|contents|:”来週”}, reading:{|contents|:”らいしゅう”}, pos:{|contents|:”名詞”}}, {surface:{|contents|:”の”}, reading:{|contents|:”の”}, pos:{|contents|:”助詞”}}, {surface:{|contents|:”水曜日”}, reading:{|contents|:”すいようび”}, pos:{|contents|:”名詞”}}, {surface:{|contents|:”に”}, reading:{|contents|:”に”}, pos:{|contents|:”助詞”}}, {surface:{|contents|:”会議”}, reading:{|contents|:”かいぎ”}, pos:{|contents|:”名詞”}}, {surface:{|contents|:”を”}, reading:{|contents|:”を”}, pos:{|contents|:”助詞”}}, {surface:{|contents|:”予約”}, reading:{|contents|:”よやく”}, pos:{|contents|:”名詞”}}, {surface:{|contents|:”。”}, reading:{|contents|:”。”}, pos:{|contents|:”特殊”}}}}}}}

Apitore 日本語形態素解析【新語対応】 ipadic neologdによる解析結果:
–> {startTime:”1502971949537″, tokens:{{partOfSpeechLevel1:”名詞”, baseForm:”来週”, pronunciation:”ライシュー”, position:0, partOfSpeechLevel3:”*”, reading:”ライシュウ”, surface:”来週”, known:true, allFeatures:”名詞,副詞可能,*,*,*,*,来週,ライシュウ,ライシュー”, conjugationType:”*”, partOfSpeechLevel2:”副詞可能”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “副詞可能”, “*”, “*”, “*”, “*”, “来週”, “ライシュウ”, “ライシュー”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助詞”, baseForm:”の”, pronunciation:”ノ”, position:2, partOfSpeechLevel3:”*”, reading:”ノ”, surface:”の”, known:true, allFeatures:”助詞,連体化,*,*,*,*,の,ノ,ノ”, conjugationType:”*”, partOfSpeechLevel2:”連体化”, conjugationForm:”*”, allFeaturesArray:{”助詞”, “連体化”, “*”, “*”, “*”, “*”, “の”, “ノ”, “ノ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”水曜日”, pronunciation:”スイヨービ”, position:3, partOfSpeechLevel3:”*”, reading:”スイヨウビ”, surface:”水曜日”, known:true, allFeatures:”名詞,副詞可能,*,*,*,*,水曜日,スイヨウビ,スイヨービ”, conjugationType:”*”, partOfSpeechLevel2:”副詞可能”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “副詞可能”, “*”, “*”, “*”, “*”, “水曜日”, “スイヨウビ”, “スイヨービ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助詞”, baseForm:”に”, pronunciation:”ニ”, position:6, partOfSpeechLevel3:”一般”, reading:”ニ”, surface:”に”, known:true, allFeatures:”助詞,格助詞,一般,*,*,*,に,ニ,ニ”, conjugationType:”*”, partOfSpeechLevel2:”格助詞”, conjugationForm:”*”, allFeaturesArray:{”助詞”, “格助詞”, “一般”, “*”, “*”, “*”, “に”, “ニ”, “ニ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”会議”, pronunciation:”カイギ”, position:7, partOfSpeechLevel3:”*”, reading:”カイギ”, surface:”会議”, known:true, allFeatures:”名詞,サ変接続,*,*,*,*,会議,カイギ,カイギ”, conjugationType:”*”, partOfSpeechLevel2:”サ変接続”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “サ変接続”, “*”, “*”, “*”, “*”, “会議”, “カイギ”, “カイギ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助詞”, baseForm:”を”, pronunciation:”ヲ”, position:9, partOfSpeechLevel3:”一般”, reading:”ヲ”, surface:”を”, known:true, allFeatures:”助詞,格助詞,一般,*,*,*,を,ヲ,ヲ”, conjugationType:”*”, partOfSpeechLevel2:”格助詞”, conjugationForm:”*”, allFeaturesArray:{”助詞”, “格助詞”, “一般”, “*”, “*”, “*”, “を”, “ヲ”, “ヲ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”予約”, pronunciation:”ヨヤク”, position:10, partOfSpeechLevel3:”*”, reading:”ヨヤク”, surface:”予約”, known:true, allFeatures:”名詞,サ変接続,*,*,*,*,予約,ヨヤク,ヨヤク”, conjugationType:”*”, partOfSpeechLevel2:”サ変接続”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “サ変接続”, “*”, “*”, “*”, “*”, “予約”, “ヨヤク”, “ヨヤク”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”記号”, baseForm:”。”, pronunciation:”。”, position:12, partOfSpeechLevel3:”*”, reading:”。”, surface:”。”, known:true, allFeatures:”記号,句点,*,*,*,*,。,。,。”, conjugationType:”*”, partOfSpeechLevel2:”句点”, conjugationForm:”*”, allFeaturesArray:{”記号”, “句点”, “*”, “*”, “*”, “*”, “。”, “。”, “。”}, partOfSpeechLevel4:”*”}}, endTime:”1502971949537″, |log|:”", processTime:”0″}

japaneseTokenize.frameworkをmacOS 10.10以降用にビルドしたバイナリを用意しましたので、自己責任で~/Library/Frameworksフォルダに入れて使ってみてください。

→ Download japaneseTokenize framework Binary

AppleScript名:japaneseTokenizeのじっけん
– Created 2017-08-17 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “japaneseTokenize”
–https://github.com/murakami/workbook/tree/master/mac/Ruby
–http://d.hatena.ne.jp/shu223/20130318/1363566717

–http://piyocast.com/as/archives/4778

set targString to “来週の水曜日に会議を予約。” –”Make a meeting on next Wednesday.” in Japanese

set aRes to current application’s jTokenize’s parseString:targString
–> {{token:”来週”, romaji:”raishuu”, hurigana:”らいしゅう”}, {token:”の”, romaji:”no”, hurigana:”の”}, {token:”水曜”, romaji:”suiyou”, hurigana:”すいよう”}, {token:”日”, romaji:”hi”, hurigana:”ひ”}, {token:”に”, romaji:”ni”, hurigana:”に”}, {token:”会議”, romaji:”kaigi”, hurigana:”かいぎ”}, {token:”を”, romaji:”wo”, hurigana:”を”}, {token:”予約”, romaji:”yoyaku”, hurigana:”よやく”}, {token:”。”, romaji:”。”, hurigana:”。”}}

set aList to (aRes’s valueForKeyPath:“hurigana”) as list –ふりがな
–>  {”らいしゅう”, “の”, “すいよう”, “ひ”, “に”, “かいぎ”, “を”, “よやく”, “。”}

set bList to (aRes’s valueForKeyPath:“token”) as list –元のテキスト
–>  {”来週”, “の”, “水曜”, “日”, “に”, “会議”, “を”, “予約”, “。”}

set cList to (aRes’s valueForKeyPath:“romaji”) as list –hurigana (romaji)
–>  {”raishuu”, “no”, “suiyou”, “hi”, “ni”, “kaigi”, “wo”, “yoyaku”, “。”}

set bRes to current application’s jTokenize’s parseStringWithLinguisticTag:targString
set dList to (bRes’s valueForKeyPath:“scheme”) as list
–>  {”Noun”, “Particle”, “Noun”, “Noun”, “Particle”, “Noun”, “Particle”, “Noun”, “SentenceTerminator”}

return bRes as list
–> {{token:”来週”, |scheme|:”Noun”}, {token:”の”, |scheme|:”Particle”}, {token:”水曜”, |scheme|:”Noun”}, {token:”日”, |scheme|:”Noun”}, {token:”に”, |scheme|:”Particle”}, {token:”会議”, |scheme|:”Noun”}, {token:”を”, |scheme|:”Particle”}, {token:”予約”, |scheme|:”Noun”}, {token:”。”, |scheme|:”SentenceTerminator”}}

★Click Here to Open This Script 

2017/08/01 JTHistogramでArrayのヒストグラムを計算

オープンソースの「JTHistogram」(By Kinokoo)をフレームワーク化したJTHistogramKitを呼び出して、NSArrayのヒストグラムを計算するAppleScriptです。

テスト用のランダム配列データの作成には、オープンソースの「objc-classes-dc-randomize」(By masakihirokawa)をフレームワーク化した「ArrayRandomize」を利用しています。

JTHistogramには該当要素数をかぞえる|histogram|()というメソッドと、構成比率を計算して求めるrelativeHistogram()というメソッドがあり、場合に応じて使い分けるとよいでしょう。

大量のデータのヒストグラム処理は割と見かけるものなので、このように高速に処理できる道具を揃えておくことには意義があります。

■乱数リスト作成+ヒストグラム(度数分布)計算 所要時間(@MacBook Pro Retina 2012 Core i7 2.66GHz, 8GB RAM)

 千項目(1,000 items):0.002 sec
 1万項目(10,000 items):0.019 sec
 10万項目(100,000 items):0.25 sec
 100万項目(1,000,000 items):3.6 sec
 1000万項目(10,000,000 items):41 sec

NSArrayの状態であれば(listに変換していない状態ならば)RAM 8GBのMacBook Proでも1000万項目の配列を扱えることに驚かされます。ASの常識的な10万項目程度なら0.25秒と非常に高速にヒストグラム計算が行えます。

ただし、得られたデータをそのままrecordに変換できないケースもあるので(ラベル値がAppleScriptのrecordで許容されないものだったりで)、値を取り出すにはCocoaのmethodを用いる必要があります。

1〜10万件程度の、AppleScriptにはやや手のかかる規模のデータの度数分布計算を行なっても、高速に処理できています(そりゃ、Objective-Cのプログラムを呼び出しているだけなので)。

JTHistogram.frameworkおよびArrayRandomize.frameworkをmacOS 10.10以降用にビルドしたバイナリを用意しましたので、自己責任で~/Library/Frameworksフォルダに入れて使って使ってみてください。

→ JTHistogramKit framework Binary

→ ArrayRandomize Framework Binary

AppleScript名:JTHistogramでArrayのヒストグラムを計算
– Created 2017-08-01 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “JTHistogramKit” –https://github.com/Kinokoo/JTHistogram
–http://piyocast.com/as/archives/4757

set anArray to current application’s NSMutableArray’s arrayWithArray:{1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 3}
set histObj to current application’s JTHistogram’s alloc()’s initWithArray:anArray

set histDict to histObj’s |histogram|()
–>  (NSDictionary) {0:0, 3:4, 2:2, 1:6}

set relativeHistogramDict to histObj’s relativeHistogram()
–>  (NSDictionary) {0:0, 3:66.66667, 2:33.33334, 1:100}

★Click Here to Open This Script 

AppleScript名:JTHistogramでArrayのヒストグラムを計算(100,000項目)
– Created 2017-08-01 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ArrayRandomize” –https://github.com/masakihirokawa/objc-classes-dc-randomize
use framework “JTHistogramKit” –https://github.com/Kinokoo/JTHistogram
–http://piyocast.com/as/archives/4757

set anArray to (current application’s DCRandomize’s shuffle:1 max:999999)
set histObj to current application’s JTHistogram’s alloc()’s initWithArray:anArray

set histDict to histObj’s |histogram|()
–>  (NSDictionary) {0:0, 67423:1, 61298:1, 55173:1, 49048:1, 42923:1,….

★Click Here to Open This Script 

2017/04/17 リストをクラス名でフィルタする v0

リストをクラス名でフィルタするAppleScriptです。指定クラスに合致するデータをリスト中から抽出します。

Charanさんから先日掲載したリストに対して「もっと簡単に書けるよ」と指摘があって、試してみたらそのとおり! ひととおり動作確認して掲載しておくことにしました。

一応、対応OSを10.9からと記載してありますが、この内容だとおそらくもっと古いOSでも問題なく動作することでしょう。

as137.png
▲Classic Mac OS 8.6上のAppleScript J1-1.3.7で動作することを確認

AppleScript名:リストをクラス名でフィルタする v0
–http://piyocast.com/as/archives/4588

set theList to {1, 2, 2.0, “aaa”, “bbb”, {a:1}, {1, 3, 4, 5, 6}, false, true}

lists of theList
–>{{1, 3, 4, 5, 6}}
text of theList
–> {”aaa”, “bbb”}
strings of theList
–> {”aaa”, “bbb”}
–unicode texts of theList
–> error
records of theList
–> {{a:1}}
booleans of theList
–> {false, true}
reals of theList
–> {2.0}
integers of theList
–> {1, 2}
numbers of theList
–> {1, 2, 2.0}

★Click Here to Open This Script 

「integers」ということは「every integer」と書き換えることが可能なので、そのとおりに書き換えてみたら、予想通り動きました。

AppleScript名:リストをクラス名でフィルタする v0a
–http://piyocast.com/as/archives/4588

set theList to {1, 2, 2.0, "aaa", "bbb", {a:1}, {1, 3, 4, 5, 6}, false, true}

set bList to every integer of theList
–> {1, 2}
set cList to every real of theList
–> {2.0}
set dList to every string of theList
–> {"aaa", "bbb"}
set eList to every list of theList
–> {{1, 3, 4, 5, 6}}
set fList to every record of theList
–> {{a:1}}
set gList to every boolean of theList
–> {false, true}

★Click Here to Open This Script 

2017/04/15 リストをクラス名でフィルタする v2

リストをクラス名でフィルタするAppleScriptです。指定クラスに合致するデータをリスト中から抽出します。

修正:listに対して簡単に直接フィルターする方法については別途記述しておきます。本Scriptは他の用途に転用するような場合の記述例として掲載しておきます

NSArrayに入れてNSPredicateで抽出を行う方法があります。ただし、これだとクラス名がCocoaとAppleScriptで合わないので、いまひとつ使えません。

そこで、ひたすら原始的ではありますが、リストをループで回してクラス名を照合して別リストに追加、という処理を回してみました。超高級言語のAppleScriptですが、たまーにこういう泥くさいチェック処理を書く瞬間があります。

そのままだと知性のカケラもなんにもないので、せめてクラス名の同義語辞書を定義して、クラス名の表記ゆらぎ(というよりも、クラス間の内包関係。integerとrealはnumberに含まれるなど)に対応させてみました。

AppleScript名:リストをクラス名でフィルタする v2
– Created 2017-04-15 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aList to {1, “ABC”, 0.3, 5, {1, 2, 3}, {abc:“record”}, false}
set bList to filterListByClass(aList, “integer”)
–> {1, 5}
set cList to filterListByClass(aList, “number”)
–> {1, 0.3, 5}
set dList to filterListByClass(aList, “real”)
–> {0.3}
set eList to filterListByClass(aList, “string”)
–> {”ABC”}
set fList to filterListByClass(aList, “record”)
–> {{abc:”record”}}
set gList to filterListByClass(aList, “boolean”)
–> {false}

on filterListByClass(aList as list, aClass as string)
  set classNameList to getClassNameConsideringSynonyms(aClass) of me
  
  
set newList to {}
  
repeat with i in aList
    set j to contents of i
    
set myClass to (class of j) as string
    
if myClass is in classNameList then
      set the end of newList to j
    end if
  end repeat
  
return newList
end filterListByClass

on getClassNameConsideringSynonyms(aClassString)
  set smallClass to ((current application’s NSString’s stringWithString:aClassString)’s lowercaseString()) as string
  
set classRec to {|list|:{“list”}, |record|:{“record”}, |number|:{“number”, “integer”, “real”}, |integer|:{“integer”}, |real|:{“real”}, |text|:{“text”, “string”, “unicode text”}, |string|:{“text”, “string”, “unicode text”}, |unicode text|:{“text”, “string”, “unicode text”}, |boolean|:{“boolean”}}
  
set classDict to current application’s NSDictionary’s dictionaryWithDictionary:classRec
  
set aVal to (classDict’s valueForKey:smallClass) as list
  
if aVal = {missing value} then error “Unexpected class name string”
  
return aVal
end getClassNameConsideringSynonyms

★Click Here to Open This Script 

2017/04/11 NSMutableArrayの特定要素の書き換え

NSMutableArray中の特定要素を書き換えるAppleScriptです。

NSMutableArrayの内容をpredicateで条件を指定してフィルタリングする処理はAppleScriptでも頻繁に使うようになってきました。他のSQLデータベースに依存する必要もなく、処理速度も速いため非常に有効な手段です。

ただ、抽出処理は行えるものの、当該アイテムの書き換えを行って、もとのNSMutableArrayに書き戻せないとデータベース的な運用はできません。

そこで、簡単なサンプルScriptを作ってみて、Array中の特定要素を検索して書き換える処理を書いてみました。

AppleScript名:リスト中の指定アイテムを置き換える
– Created 2017-04-11 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4579

set anArray to current application’s NSMutableArray’s arrayWithArray:{5, 2, 1, 3, 4}
anArray’s replaceObjectsAtIndexes:(current application’s NSIndexSet’s indexSetWithIndex:0) withObjects:{-1}
return anArray as list
–> {-1, 2, 1, 3, 4}

★Click Here to Open This Script 

AppleScript名:レコード入りリスト中の指定アイテムを置き換える
– Created 2017-04-11 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4579

set anArray to current application’s NSMutableArray’s arrayWithArray:{{aLabel:0, bLabel:2, cLabel:100}, {aLabel:2, bLabel:3, cLabel:1}}
anArray’s replaceObjectsAtIndexes:(current application’s NSIndexSet’s indexSetWithIndex:0) withObjects:{{aLabel:-1, bLabel:-2, cLabel:-3}}
return anArray as list
–>  {{cLabel:-3, aLabel:-1, bLabel:-2}, {cLabel:1, aLabel:2, bLabel:3}}

★Click Here to Open This Script 

AppleScript名:リスト中の指定アイテムを置き換える(登場アイテム番号自動検索)
– Created 2017-04-11 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4579

set aTargValue to 2
set aNewValue to -100
set anArray to current application’s NSMutableArray’s arrayWithArray:{5, 2, 1, 3, 4}
set aInd to anArray’s indexOfObject:aTargValue
anArray’s replaceObjectsAtIndexes:(current application’s NSIndexSet’s indexSetWithIndex:aInd) withObjects:{aNewValue}
return anArray as list
–>  {5, -100, 1, 3, 4}

★Click Here to Open This Script 

AppleScript名:レコード入りリスト中の指定アイテムを置き換える(登場アイテム番号自動検索)
– Created 2017-04-11 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4579

set aTargValue to {aLabel:2, bLabel:3, cLabel:1}
set aNewValue to {aLabel:-1, bLabel:-2, cLabel:-3}

set anArray to current application’s NSMutableArray’s arrayWithArray:{{aLabel:0, bLabel:2, cLabel:100}, {aLabel:2, bLabel:3, cLabel:1}, {aLabel:0, bLabel:0, cLabel:0}}
set aInd to anArray’s indexOfObject:aTargValue

anArray’s replaceObjectsAtIndexes:(current application’s NSIndexSet’s indexSetWithIndex:aInd) withObjects:{aNewValue}
return anArray as list
–>  {{cLabel:100, aLabel:0, bLabel:2}, {cLabel:-3, aLabel:-1, bLabel:-2}, {cLabel:0, aLabel:0, bLabel:0}}

★Click Here to Open This Script 

2017/03/18 文字を集合(CountedSet)に変換して文字列同士の近似度を計算する v2

複数の文字列同士の近似度を擬似的に計算できないかと考えて、文字列をCountedSetに変換して、CountedSet同士でand演算(intersectSet)を実行。その計算結果が大きいほど「文字列中に含まれている文字列の傾向が似ている」と判断するテストのAppleScriptです。

countedset_intersect_resized.png

とりあえずはintersectSetで積集合を計算しています。重複している部分を求めているわけです。

 「This is an apple.」と「This is a pinapple.」–> 11
 「This is a pinapple.」と「Piyomaru San Dayo.」–> 5
 「Piyomaru San Dayo.」と「This is an apple.」–> 5

v1とv2の計算結果を合わせて、両方の傾向を反映させるようにするとよいのかもしれません。

AppleScript名:文字を集合(CountedSet)に変換して文字列同士の近似度を計算する v2
– Created 2017-03-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4532

set aStr to "This is a pinnapple."
set bStr to "This is an apple."
set cStr to "Piyomaru San Dayo."

set a1Res to getApproximationBetweenStringsIntersect(aStr, bStr) of me
–>  11

set bRes to getApproximationBetweenStringsIntersect(bStr, cStr) of me
–>  5

set cRes to getApproximationBetweenStringsIntersect(cStr, aStr) of me
–>  5

on getApproximationBetweenStringsIntersect(aStr, bStr)
  set aList to current application’s NSMutableArray’s arrayWithArray:(characters of aStr)
  
set bList to current application’s NSMutableArray’s arrayWithArray:(characters of bStr)
  
  
set aIndex to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bIndex to current application’s NSCountedSet’s alloc()’s initWithArray:bList
  
  
aIndex’s intersectSet:bIndex
  
set aRes to aIndex’s allObjects()’s |count|()
  
return aRes
end getApproximationBetweenStringsIntersect

★Click Here to Open This Script 

2017/03/18 文字を集合(CountedSet)に変換して文字列同士の近似度を計算する v1

複数の文字列同士の近似度を擬似的に計算できないかと考えて、文字列をCountedSetに変換して、CountedSet同士で減算を実行。その計算結果が少ないほど「文字列中に含まれている文字列の傾向が似ている」と判断するテストのAppleScriptです。

countedset.png

とりあえずはminusSetで減算を行なっていますが、ほかの方法も試してみたいところです。

本Scriptでは、得られた結果の数値が小さければ重複している文字が多いということで、計算結果そのものにはあまり意味はありませんが、複数の結果を大小比較して、数値が小さいもののペアが「似たような傾向を持つもの」として期待できます。

 「This is an apple.」と「This is a pinapple.」–> 3
 「This is a pinapple.」と「Piyomaru San Dayo.」–> 8
 「Piyomaru San Dayo.」と「This is an apple.」–> 9

ということで、これらの間では「This is an apple.」と「This is a pinapple.」の近似度が一番高いといえることになります。

AppleScript名:文字を集合(CountedSet)に変換して文字列同士の近似度を計算する v1
– Created 2017-03-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4530

set aStr to “This is a pinnapple.”
set bStr to “This is an apple.”
set cStr to “Piyomaru San Dayo.”

set a1Res to getApproximationBetweenStrings(aStr, bStr) of me
–>  3

set bRes to getApproximationBetweenStrings(bStr, cStr) of me
–>  8

set cRes to getApproximationBetweenStrings(cStr, aStr) of me
–>  9

on getApproximationBetweenStrings(aStr, bStr)
  set aList to current application’s NSMutableArray’s arrayWithArray:(characters of aStr)
  
set bList to current application’s NSMutableArray’s arrayWithArray:(characters of bStr)
  
  
set aIndex to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bIndex to current application’s NSCountedSet’s alloc()’s initWithArray:bList
  
  
aIndex’s minusSet:bIndex
  
set aRes to aIndex’s allObjects()’s |count|()
  
  
bIndex’s minusSet:aIndex
  
set bRes to bIndex’s allObjects()’s |count|()
  
  
if aRes bRes then
    return bRes
  else
    return aRes
  end if
end getApproximationBetweenStrings

★Click Here to Open This Script 

2017/03/07 矩形座標同士の合計

NSUnionRectによる矩形座標(NSRect)の合計をためしてみました。

unionrect.png

実際に方眼紙を塗りつぶしてみると、計算結果が不思議な感じもするのですが(空いているセルもあるので)、、、そういうものなんでしょう、、、か(^ー^;;;;;

AppleScript名:矩形座標同士の合計
– Created 2017-03-06 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4515

set a1Rect to {origin:{x:10, y:10}, |size|:{width:40, height:40}}
set b1Rect to {origin:{x:30, y:30}, |size|:{width:40, height:40}}
set a1Res to current application’s NSUnionRect(a1Rect, b1Rect)
–>  {origin:{x:10.0, y:10.0}, size:{width:60.0, height:60.0}}

★Click Here to Open This Script 

2017/03/01 NSSet/NSMutableSetの演算 2

NSSet/NSMutableSetの演算について、Shane Stanleyから「こっちのほうが短く書けるぞ」というツッコミが(Thanks!)。

set1.png

AppleScript名:補集合(set difference)v2
– Created 2017-02-24 by Takaaki Naganoya
– Created 2017-03-01 by Shane Stanley
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4491

set aSet to current application’s NSMutableSet’s setWithArray:{1, 2, 3, 4}
set bSet to current application’s NSMutableSet’s setWithArray:{3, 5, 6, 7}

aSet’s minusSet:bSet –補集合
aSet’s allObjects() as list
–>  {2, 1, 4}

★Click Here to Open This Script 

set2.png

AppleScript名:積集合(product)v2
– Created 2017-02-24 by Takaaki Naganoya
– Created 2017-03-01 by Shane Stanley
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4491

set aSet to current application’s NSMutableSet’s setWithArray:{1, 2, 3, 4}
set bSet to current application’s NSMutableSet’s setWithArray:{3, 5, 6, 7}

aSet’s intersectSet:bSet –積集合
aSet’s allObjects() as list
–>  {3}

★Click Here to Open This Script 

set3.png

AppleScript名:和集合(union)v2
– Created 2017-02-24 by Takaaki Naganoya
– Created 2017-03-01 by Shane Stanley
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4491

set aSet to current application’s NSMutableSet’s setWithArray:{1, 2, 3, 4}
set bSet to current application’s NSMutableSet’s setWithArray:{3, 5, 6, 7}

aSet’s unionSet:bSet –和集合
aSet’s allObjects() as list
–>  {5, 1, 6, 2, 7, 3, 4}

★Click Here to Open This Script 

2017/03/01 NSSet/NSMutableSetの演算

NSSet/NSMutableSetが集合を表すClassであることをあとから知り、集合同士の演算の例を調べてみました。こういう地道な調査があとでジワジワ効いてくるのです。

set1.png

AppleScript名:補集合(set difference)
– Created 2017-02-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4487

set aArray to current application’s NSArray’s arrayWithArray:{1, 2, 3, 4}
set bArray to current application’s NSArray’s arrayWithArray:{3, 5, 6, 7}

set aSet to current application’s NSMutableSet’s alloc()’s initWithArray:aArray
set bSet to current application’s NSMutableSet’s alloc()’s initWithArray:bArray

aSet’s minusSet:bSet –補集合
aSet’s allObjects() as list
–>  {2, 1, 4}

★Click Here to Open This Script 

set2.png

AppleScript名:積集合(product)
– Created 2017-02-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4487

set aArray to current application’s NSArray’s arrayWithArray:{1, 2, 3, 4}
set bArray to current application’s NSArray’s arrayWithArray:{3, 5, 6, 7}

set aSet to current application’s NSMutableSet’s alloc()’s initWithArray:aArray
set bSet to current application’s NSMutableSet’s alloc()’s initWithArray:bArray

aSet’s intersectSet:bSet –積集合
aSet’s allObjects() as list
–>  {3}

★Click Here to Open This Script 

set3.png

AppleScript名:和集合(union)
– Created 2017-02-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4487

set aArray to current application’s NSArray’s arrayWithArray:{1, 2, 3, 4}
set bArray to current application’s NSArray’s arrayWithArray:{3, 5, 6, 7}

set aSet to current application’s NSMutableSet’s alloc()’s initWithArray:aArray
set bSet to current application’s NSMutableSet’s alloc()’s initWithArray:bArray

aSet’s unionSet:bSet –和集合
aSet’s allObjects() as list
–>  {5, 1, 6, 2, 7, 3, 4}

★Click Here to Open This Script 

2017/02/23 リストから重複要素のみを返す v2

Shane Stanleyによる「リストから重複する要素のみを抽出して返すAppleScript」の改良版です。シンプルで美しい処理になっています。

この手の処理でNSSetやNSCountedSetを使うのは「そういうものだろー」とすぐに思いつきますが、「minusSet:」というのはドキュメント中から見つけ切れませんでした。これは深い(^ー^;;。

また、ループ処理や条件判断の処理が入っていないため、自分の書いたバージョンよりも2.3倍ぐらい高速でした(100回実行時の平均)。

AppleScript名:リストから重複要素のみを返す v2
– Created 2017-02-23 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4469

set aList to {“4efa7f9f587f3d1dbc4a1f6ebff92ef5″, “59cd07ea69acc2c9004dc815803cf184″, “5841f4bcc13e85c3b8ba1eafcacd43be”, “dfb393cd3c0eb3f228236367f171cd01″, “59cd07ea69acc2c9004dc815803cf184″, “59cd07ea69acc2c9004dc815803cf184″}
set dList to returnDuplicatesOnly(aList) of me
–> {”59cd07ea69acc2c9004dc815803cf184″}

on returnDuplicatesOnly(aList)
  set countedSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set simpleSet to current application’s NSSet’s setWithArray:aList
  
countedSet’s minusSet:simpleSet
  
return countedSet’s allObjects() as list
end returnDuplicatesOnly

★Click Here to Open This Script 

2017/02/16 YAMLのじっけん

オープンソースのフレームワーク「YAML.framework」(Mirek Rusin)を用いて、構造化データ記述言語であるYAMLとオブジェクト(listやrecord)との間の相互変換を行うAppleScriptです。

これまでYAMLとは縁のない生活を送ってきましたが、とくに問題はありませんでした。構造を持つデータの分量が増えた場合には、プログラム中に直接記述せず、Excelの表からデータを読み取って処理したり、データベースなど他のデータソースからデータを取得していました。

ただ、listとかrecordの内容が込み入ってくる(フィールド数が多いとか、入れ子構造の段数が深いとか)と、こういう仕組みがあったほうが便利なんだろうな、ということは理解できます。

YAML.frameworkのプロジェクトをXcodeでビルドし、出来上がったフレームワークを~/Library/Frameworksに入れてテストしてみてください。

途中、Githubに掲載されているObjective-CのサンプルプログラムがNSInputStreamを使っており、これをAppleScriptに書き換えて呼び出すとAppleScriptの処理系が100%クラッシュ。NSDataを経由して変換する方法なども試してみましたがNSInputStreamを作りにいくとクラッシュ。

結局、Stringから直接変換するメソッドがあったため、これを使用することで安定して処理できるようになりました。

当初は機械学習フレームワークの「YCML」をいじくっていたのですが、その過程で本フレームワークを発見。なかなか有用性が高そうなので試してみた次第です。

AppleScript名:YAMLのじっけん
– Created 2017-02-16 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “YAML” –https://github.com/mirek/YAML.framework
–http://piyocast.com/as/archives/4464

–YAMLの文字列からオブジェクトを生成する
set aYAMLstr to
items:
- name: Foo
- name: Bar

set aStr to current application’s NSString’s stringWithString:aYAMLstr
set aData to aStr’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)

set aData to current application’s YAMLSerialization’s objectsWithYAMLString:aStr options:(4096) |error|:(missing value)
–>  (NSArray) {{items:{{name:”Foo”}, {name:”Bar”}}}}

–オブジェクトからYAMLの文字列を取得する
set aString to (current application’s YAMLSerialization’s createYAMLStringWithObject:aData options:(1) |error|:(missing value)) as string
(* –>
“—
- items:
- name: Foo
- name: Bar
…”
*)

★Click Here to Open This Script 

AppleScript名:YAMLのじっけん4
– Created 2017-02-16 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “YAML” –https://github.com/mirek/YAML.framework
–http://piyocast.com/as/archives/4464

–YAMLの文字列からオブジェクトを生成する
set aYAMLstr to
- name: Smith
email: smith@mail.com
- name: Shelton
email: shelton@mail.com
- name: Kelly
email: kelly@mail.com

set aRes to retObjectFromYAMLString(aYAMLstr) of me
–>  {{{name:”Smith”, email:”smith@mail.com”}, {name:”Shelton”, email:”shelton@mail.com”}, {name:”Kelly”, email:”kelly@mail.com”}}}

set bYAMLstr to
names: [Smith, Shelton, Kelly]
emails: [smith@mail.com, shelton@mail.com, kelly@mail.com]

set bRes to retObjectFromYAMLString(bYAMLstr) of me
–>  {{names:{”Smith”, “Shelton”, “Kelly”}, emails:{”smith@mail.com”, “shelton@mail.com”, “kelly@mail.com”}}}

–オブジェクト(list)からYAMLの文字列を生成する
set bStr to retYAMLStringFromObject(bRes)
(*  
“—
- names:
- Smith
- Shelton
- Kelly
emails:
- smith@mail.com
- shelton@mail.com
- kelly@mail.com


*)

on retObjectFromYAMLString(aYAMLstr as string)
  set aStr to current application’s NSString’s stringWithString:aYAMLstr
  
set aData to aStr’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aData to current application’s YAMLSerialization’s objectsWithYAMLString:aStr options:(4096) |error|:(missing value)
  
return aData as list
end retObjectFromYAMLString

on retYAMLStringFromObject(anObject)
  set aString to (current application’s YAMLSerialization’s createYAMLStringWithObject:anObject options:(1) |error|:(missing value)) as string
  
return aString
end retYAMLStringFromObject

★Click Here to Open This Script 

2016/12/15 PDFしおり用データをNumbersから取得

PDFに「しおり」を作成する元のデータをNumbers上に記述しておくと、作成用のデータを取得・変換するAppleScriptです。構文確認および実行には、Shane Stanleyの「BridgePlus」AppleScript Libraries(フリー)のインストールを必要とします。

また、Numbersで(↓)のような書類を作成して、Numbersでオープンしていることが動作の前提条件です。

numbers_shiori.png

元のプログラムでは直接Script Editor上でレコードとして記述するのが、なかなか大変。また、親項目をタイトル文字列で記述するのも(作業時にミスりそうで)大変だったので、Numbers書類上で記述できるようにしてみたものです。

shiori.png

親項目は番号で記述するようにして、ID自体の連番の生成もAppleScriptから行い、極力作業ミスが発生しないように配慮してみました。

shiori2.png

AppleScript名:しおり用データをNumbersから取得
【コメント】 Book2_index_v2 を前提としています
– Created 2016-12-15 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use framework “Foundation”
use scripting additions
use BridgePlus : script “BridgePlus”
–http://piyocast.com/as/archives/4363

set aData to getIndexRecListFromNumbers() of me
–> {{|index|:3, title:”広告”, |parent|:”"}, {|index|:4, title:”本書購入特典のご案内”, |parent|:”"},…..

–NumbersのデータからPDFに付けるしおりのデータを取得する
on getIndexRecListFromNumbers()
  tell application “Numbers”
    tell window 1
      set aWinProp to properties
    end tell
    
    
set aDoc to document of aWinProp
    
tell aDoc
      tell active sheet
        tell table 1
          set colNum to column count
          
if colNum is not equal to 4 then error “Illegal Column Numbers”
          
set rowNum to row count
          
set vList to value of every cell
        end tell
      end tell
    end tell
  end tell
  
  
–Transform 1D array to 2D array
  
load framework
  
set tdList to (current application’s SMSForder’s subarraysFrom:(vList) groupedBy:colNum |error|:(missing value)) as list
  
–> {{”ID”, “index”, “title”, “parent”}, {1.0, 3.0, “広告”, missing value}, …..
  
  
–Skip First Row
  
set td2List to rest of tdList –first itemだけスキップする
  
  
set mokujiRecords to {}
  
repeat with i in td2List
    copy i to {anID, anIND, aTITLE, aParent}
    
    
–log {anID, anIND, aTITLE, aParent}
    
if aParent is not equal to missing value then
      set bParent to contents of item 3 of (item aParent of td2List)
    else
      set bParent to “”
    end if
    
    
set tmpRec to {|index|:(contents of anIND) as integer, title:aTITLE, |parent|:bParent}
    
set the end of mokujiRecords to tmpRec
  end repeat
  
  
return mokujiRecords
  
end getIndexRecListFromNumbers

★Click Here to Open This Script 

2016/12/14 &と=で区切られたテキストをrecordに 改

「aParam=1234&bParam=2345」のように、URLのパラメータ部のような文字列を「&」と「=」で区切ってrecordとして出力するAppleScriptです。

「&と=で区切られたテキストをrecordに(NSScanner版)」をedama2さんがさらに改良したものです。

「先日掲載されたNSScannerのスクリプト、自分でも試してみてとても便利だったんですが、値なしの時にエラーになるので修正してみました。

あとリファレンス本に「repeat until」はあんまり使わないと書いてあったので使ってみました。(edama2さん)」

なるほど。たしかにラベルだけで値が存在しないケースに対応できるとよさそうです。

AppleScript名:&と=で区切られたテキストをrecordに 改
– Created 2016-12-12 by Shane Stanley
– Modified 2016-12-14 by edama2
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4358

set aParamStr to "access_token=XXxxx(XXxXXXXXxxXxxXXx))&expires=86399&name="
set aDict to (parseStrByAmpAndEqual(aParamStr) of me)
–>  {expires:"86399", |name|:"", access_token:"XXxxx(XXxXXXXXxxXxxXXx))"}

on parseStrByAmpAndEqual(aParamStr)
  set theScanner to current application’s NSScanner’s scannerWithString:aParamStr
  
set aDict to current application’s NSMutableDictionary’s |dictionary|()
  
  
repeat until (theScanner’s isAtEnd as boolean)
    – terminate check, return the result (aDict) to caller
    
set {theResult, theKey} to theScanner’s scanUpToString:"=" intoString:(reference)
    
    
– skip over separator
    
theScanner’s scanString:"=" intoString:(missing value)
    
set {theResult, theValue} to theScanner’s scanUpToString:"&" intoString:(reference)
    
if theValue is missing value then set theValue to "" –>追加
    
    
– skip over separator
    
theScanner’s scanString:"&" intoString:(missing value)
    
    
aDict’s setObject:theValue forKey:theKey
  end repeat
  
  
return aDict as record
end parseStrByAmpAndEqual

★Click Here to Open This Script 

2016/12/13 顔認識結果のデータを加工

Microsoftの顔認識APIを呼び出して、その結果を加工して表情認識APIを呼び出すために、顔認識APIの実行結果を加工するAppleScriptです。

まだ表情認識APIは呼び出せていませんが、その途中で作ったものです。

典型的なデータ加工の処理なので、ほかにも(もう少しうまい)やり方がありそうです。

AppleScript名:顔認識結果のデータを加工
– Created 2016-12-13 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4357

set aList to current application’s NSArray’s arrayWithArray:{{faceId:"c49883a0-c4ee-4671-ad06-6f7f8370ab20", faceRectangle:{top:68, width:40, |left|:336, height:40}}, {faceId:"93459b48-4c19-4cc7-85e6-b38b8d0fc73b", faceRectangle:{top:81, width:38, |left|:92, height:38}}, {faceId:"9c796619-c654-47dd-b7b0-c382dc6bda84", faceRectangle:{top:63, width:38, |left|:214, height:38}}, {faceId:"94a2ceec-c089-494c-982e-a213579342b6", faceRectangle:{top:92, width:38, |left|:462, height:38}}, {faceId:"18e8dad0-fe46-4c5c-81c3-3ba483129512", faceRectangle:{top:89, width:37, |left|:700, height:37}}, {faceId:"4031f4bd-4e47-4050-89a0-f66e2e4e9142", faceRectangle:{top:45, width:37, |left|:570, height:37}}}

set aRes to retFaceArray(aList) of me
–>  "336,68,40,40;92,81,38,38;214,63,38,38;462,92,38,38;700,89,37,37;570,45,37,37"

on retFaceArray(aList)
  set a1Res to (aList’s valueForKeyPath:"faceRectangle.top") as list
  
set a2Res to (aList’s valueForKeyPath:"faceRectangle.width") as list
  
set a3Res to (aList’s valueForKeyPath:"faceRectangle.left") as list
  
set a4Res to (aList’s valueForKeyPath:"faceRectangle.height") as list
  
  
set aLen to length of a1Res
  
set aRes to {}
  
  
repeat with i from 1 to aLen
    set aLeft to (contents of item i of a3Res) as string
    
set aTop to (contents of item i of a1Res) as string
    
set aWidth to (contents of item i of a2Res) as string
    
set aHeight to (contents of item i of a4Res) as string
    
set tmpRes to aLeft & "," & aTop & "," & aWidth & "," & aHeight
    
set the end of aRes to tmpRes
  end repeat
  
  
set allRes to retStrFromArrayWithDelimiter(aRes, ";") of me
  
  
return allRes
end retFaceArray

–リストを指定デリミタをはさんでテキスト化
on retStrFromArrayWithDelimiter(aList, aDelim)
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set aRes to anArray’s componentsJoinedByString:aDelim
  
return aRes as text
end retStrFromArrayWithDelimiter

★Click Here to Open This Script 

2016/12/08 GameplayKitを使ったリストのシャッフル

Shane Stanleyから教えてもらった、GameplayKitを用いた高速なリストのシャッフルScriptです。ただし、実行にはmacOS 10.12を必要とします。

9999項目のリストをシャッフルする処理で、DCRandomizeを使ったScriptで0.02秒、本Script(GameplayKitのshuffledArray())では0.427秒かかりました(10回実行時の平均値)。

本Scriptでも9999項目のNSMutableArrayの作成部分だけ取り出して計測すると0.405秒かかっているので、シャッフル部分は0.02秒程度です。

AppleScript名:GameplayKitを使ったリストのシャッフル
– Created 2016-12-08 by Shane Stanley
use AppleScript version “2.5″
use framework “Foundation”
use framework “GameplayKit”
use scripting additions
–http://piyocast.com/as/archives/4353

set anArray to current application’s NSArray’s arrayWithArray:{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
set newArray to anArray’s shuffledArray() as list – requires macOS 10.12

★Click Here to Open This Script 

AppleScript名:GameplayKitを使ったリストのシャッフル(計測用)
– Created 2016-12-08 by Shane Stanley
– Modified 2016-12-08 by Takaaki Naganoya
use AppleScript version “2.5″
use framework “Foundation”
use framework “GameplayKit”
use scripting additions
–http://piyocast.com/as/archives/4353

set anArray to current application’s NSMutableArray’s alloc()’s init()
repeat with i from 1 to 10000
  (anArray’s addObject:i)
end repeat

set newArray to anArray’s shuffledArray() as list – requires macOS 10.12

★Click Here to Open This Script 

AppleScript名:リストのシャッフル(計測用)
– Created 2016-12-06 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ArrayRandomize” –https://github.com/masakihirokawa/objc-classes-dc-randomize
–http://piyocast.com/as/archives/4353

–1〜9999の数値をシャッフルして配列取得
set cArray to (current application’s DCRandomize’s shuffle:1 max:9999) as list

★Click Here to Open This Script 

2016/12/07 リスト項目のシャッフル(ASOC)

リスト項目のシャッフルを行うAppleScriptです。オープンソースの「objc-classes-dc-randomize」をフレームワーク化した「ArrayRandomize」フレームワークを呼び出してシャッフルしています。

AppleScriptだけで作成した9999項目のリストのシャッフルと比べて、5,000倍ぐらい高速です(Objective-C側で処理した内容をただlistに変換しているだけなので)。本フレームワークを使うと、9999項目のリストのシャッフル生成で0.018秒(MacBook Pro Retina 2012 Core i7 2.66GHz)でした。

# ただ、比較対象のPure AppleScriptのプログラムも、まだまだ高速化の余地があったので、実際にはもう少し(10%ぐらい?)差は小さいと思います。Pure AppleScriptでも1,000項目ぐらいだと1秒ぐらいで処理が終わるのですが、、、ただ乱数を配列に追加するだけでなく、存在チェックと乱数の再生成を行うので、なかなかASには負荷が高い処理です

ArrayRandomize.frameworkをmacOS 10.10以降用にビルドしたバイナリを用意しましたので、自己責任で~/Library/Frameworksフォルダに入れて使って使ってみてください。

→ フレームワーク(19KB)のダウンロード

AppleScript名:リスト項目のシャッフル(ASOC)
– Created 2016-12-06 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ArrayRandomize” –https://github.com/masakihirokawa/objc-classes-dc-randomize
–http://piyocast.com/as/archives/4351

–配列をシャッフルして取得
set anArray to current application’s NSMutableArray’s alloc()’s initWithArray:{1, 2, 3, 4, 5}
set bArray to (current application’s DCRandomize’s shuffleArray:anArray) as list
–>  {5, 3, 1, 2, 4}

–1〜10の数値をシャッフルして配列取得
set cArray to (current application’s DCRandomize’s shuffle:1 max:10) as list
–>  {9, 4, 6, 5, 3, 2, 7, 8, 1, 10}

–5〜10の範囲の乱数を取得
set dArray to (current application’s DCRandomize’s range:5 max:10) as integer
–>  7

–5〜10の範囲で 9以外の乱数を取得
set eArray to (current application’s DCRandomize’s exact:5 max:10 exceptId:9)
–>  9

★Click Here to Open This Script 

2016/11/05 XMLをNSDictionaryに

オープンソースのXMLDictionary(By Nick Lockwood)をFramework化した「XmlToDictKit」を呼び出して、XMLをNSDictionaryにするAppleScriptです。

XMLをNSDictionaryにするのには、なかなか手こずらされており、依然としてSatimageのXMLLib OSAXが手放せない状況ですが、OSAXを使わずになんとかする方法についてはつねに模索しておりました。

「XML Parser」などをキーワードにGithub上でいろいろ物色していたところ、そんなに気合の入ったキーワードでなくても、「XML NSDictionary」ぐらいでいろいろ見つかりました。

それらを人気順でソートし上から順番に物色。条件が合って手軽にフレームワーク化に成功したのがこの「XMLDictionary」です。

XMLをNSDictionaryに変換し、さらにNSDictionaryをrecordまで変換すればAppleScriptで簡単に取り扱えます(NSDictionaryの属性値ラベルに空白などが入っていなければ)。

フレームワークについては、例によってOS X 10.10をターゲットにしてビルドしてみました。~/Library/Frameworksに入れてご利用ください(あくまで自己責任で)。

XMLそのものよりも、RSSのParseが割と手間だったので、RSSを手軽に扱えるようになったことのメリットが大きいと感じています。

→ FrameworkのZipアーカイブのダウンロード(30KB)

AppleScript名:XMLをDictionaryに(remote file)
– Created 2016-11-05 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “XmlToDictKit” –https://github.com/nicklockwood/XMLDictionary
–http://piyocast.com/as/archives/4304

set aURL to current application’s |NSURL|’s alloc()’s initWithString:“http://www.ibiblio.org/xml/examples/shakespeare/all_well.xml”
set xmlString to current application’s NSString’s alloc()’s initWithContentsOfURL:aURL encoding:(current application’s NSUTF8StringEncoding) |error|:(missing value)
if xmlString = missing value then return false
set xmlDoc to (current application’s NSDictionary’s dictionaryWithXMLString:xmlString) as record

★Click Here to Open This Script 

AppleScript名:XMLをDictionaryに(local file)
– Created 2016-11-05 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “XmlToDictKit” –https://github.com/nicklockwood/XMLDictionary
–http://piyocast.com/as/archives/4304

set aFile to POSIX path of (choose file)
set aURL to current application’s |NSURL|’s fileURLWithPath:aFile
set xmlString to current application’s NSString’s alloc()’s initWithContentsOfURL:aURL encoding:(current application’s NSUTF8StringEncoding) |error|:(missing value)
if xmlString = missing value then return false
set xmlDoc to (current application’s NSDictionary’s dictionaryWithXMLString:xmlString) as record

★Click Here to Open This Script 

AppleScript名:RSSをDictionaryに(remote file)
– Created 2016-11-05 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “XmlToDictKit” –https://github.com/nicklockwood/XMLDictionary
–http://piyocast.com/as/archives/4304

set aURL to current application’s |NSURL|’s alloc()’s initWithString:“http://piyocast.com/as/feed”
set xmlString to current application’s NSString’s alloc()’s initWithContentsOfURL:aURL encoding:(current application’s NSUTF8StringEncoding) |error|:(missing value)
if xmlString = missing value then return false
set xmlDoc to (current application’s NSDictionary’s dictionaryWithXMLString:xmlString) as record
set aChannel to |item| of channel of xmlDoc
set aDoc1 to first item of aChannel
–>  {category:{”Application Control”, “10.10 savvy”, “10.11 savvy”, “10.12 savvy”}, dc:creator:”maro”, comments:”http://piyocast.com/as/archives/4304#comments”, title:”XMLをNSDictionaryに”, link:”http://piyocast.com/as/archives/4304″, pubDate:”Sat, 05 Nov 2016 21:21:17 +0900″, description:”オープンソースのXMLDictionary(By Nick Lockwood)をFramework化した「XmlToDictKit」を呼び出して、XMLをNSDictionaryにするAppleScr…”, guid:{__text:”http://piyocast.com/as/archives/4304″, _isPermaLink:”false”}, wfw:commentRss:”http://piyocast.com/as/archives/4304/feed/”}

★Click Here to Open This Script 

2016/10/31 listのrecordをplistにserializeして、plistをde-serializeする

Listでまとめたrecordをエンコーディングしてplist文字列にして(serialize)、さらにそれを元に戻す(deserialize)AppleScriptです。

本来、「エンコーダーとデコーダーは一緒に作る」はずのものですが、plistへのエンコードScriptしかできておらず、世の中に転がっているObjective-Cのサンプルとにらめっこしてもさっぱり分からなかったので、AppleScript Users MLに質問を投げてみたら、Shane Stanleyからあっさりと、

「これ、もうdeprecatedなmethodなんで使っちゃダメだよ。あと、deserializeするときには文字列をそのまま渡さないでね」

というアドバイスとコードそのものを教えてもらいました。というわけで、整理して掲載しておきます。

AppleScript名:listのrecordをplistにserializeして、plistをde-serializeする
– Created 2016-10-30 by Takaaki Naganoya
– Modified 2016-10-31 by Shane Stanley
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4296

set aList to {{theName:“Sound Track”, numberOfTimes:1721}, {theName:“Rock”, numberOfTimes:942}}
set aRes to serializeToPlistString(aList) of me
set bRes to (deserializeToPlistString(aRes) of me) as list
–>  {{numberOfTimes:1721, theName:”Sound Track”}, {numberOfTimes:942, theName:”Rock”}}

–list or record –> XML-format plist string
on serializeToPlistString(aList as {list, record})
  set pListData to current application’s NSPropertyListSerialization’s dataWithPropertyList:aList |format|:(current application’s NSPropertyListXMLFormat_v1_0) options:0 |error|:(missing value)
  
set bStr to (current application’s NSString’s alloc()’s initWithData:pListData encoding:(current application’s NSUTF8StringEncoding)) as string
  
return bStr
end serializeToPlistString

–XML-format plist string–> list or record
on deserializeToPlistString(aStr as string)
  set deStr to current application’s NSString’s stringWithString:aStr
  
set theData to deStr’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aList to current application’s NSPropertyListSerialization’s propertyListWithData:theData options:(current application’s NSPropertyListMutableContainersAndLeaves) |format|:(missing value) |error|:(missing value)
  
return aList
end deserializeToPlistString

★Click Here to Open This Script 

2016/10/30 Listのrecordをエンコーディングしてplist文字列にする

Listでまとめたrecordをエンコーディングしてplist文字列にするAppleScriptです。

ただのrecordでもなんでもいいのですが、plistのファイルに書き込むのではなく、文字列として取得します。

AppleScriptをTerminal上で呼び出して、複数のAppleScript同士でデータをやりとりする場合に、リストやレコードをそのままやりとりすることは困難です。そこで、plistの文字列にして標準出力に出すことを検討してみました。

ご注意:本Scriptはdeprecatedなmethodを使っているため、アップデート版を利用してください。

AppleScript名:Listのrecordをエンコーディングしてplist文字列にする
– Created 2016-10-30 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4295

set aList to {{theName:“サウンドトラック”, numberOfTimes:1721}, {theName:“ロック”, numberOfTimes:942}}

–2D Arrayをplistの文字列にエンコードする
set anArray to current application’s NSArray’s arrayWithObject:aList
set pListData to current application’s NSPropertyListSerialization’s dataFromPropertyList:anArray |format|:(current application’s NSPropertyListXMLFormat_v1_0) errorDescription:(missing value)
set bStr to (current application’s NSString’s alloc()’s initWithData:pListData encoding:(current application’s NSUTF8StringEncoding)) as string

(*
–>  ”<?xml version=\”1.0\” encoding=\”UTF-8\”?>
<!DOCTYPE plist PUBLIC \”-//Apple//DTD PLIST 1.0//EN\” \”http://www.apple.com/DTDs/PropertyList-1.0.dtd\”>
<plist version=\”1.0\”>
<array>
  <array>
    <dict>
      <key>numberOfTimes</key>
      <integer>1721</integer>
      <key>theName</key>
      <string>サウンドトラック</string>
    </dict>
    <dict>
      <key>numberOfTimes</key>
      <integer>942</integer>
      <key>theName</key>
      <string>ロック</string>
    </dict>
  </array>
</array>
</plist>

*)

★Click Here to Open This Script 

2016/10/28 ベクトルのコサイン類似度を計算する v2

ベクトル同士のコサイン類似度を計算するAppleScriptの改良版です。

「ガンダム」「アムロ・レイ」「ガンキャノン」

という3つの言葉の類似度を計算したところ、

 (1)「ガンダムとガンキャノン」
 (2)「アムロ・レイとガンキャノン」
 (3)「アムロ・レイとガンダム」

の順に類似度が計算されてしまい、「ガンキャノン問題」として問題視されました。

Apitoreさんより「ベクトルの長さで正規化するとよい」という助言をいただき、いろいろ調べて改良してみたものです。

その結果、

 (1)「ガンダムとガンキャノン」
 (2)「ガンダムとアムロ・レイ」
 (3)「アムロ・レイとガンキャノン」

の順番に計算結果が出るようになり、一安心しています。

AppleScript名:ベクトルのコサイン類似度を計算する v2
– Created 2016-10-28 by Takaaki Naganoya
– 2016 Piyomaru Software
–以下のページを参照しました
–http://www.cse.kyoto-su.ac.jp/~g0846020/keywords/cosinSimilarity.html
–http://piyocast.com/as/archives/4293

set aRec to {startTime:“1477635439753″, |word|:“ガンダム”, endTime:“1477635439754″, |log|:“Success.”, |vector|:{-0.173511996865, 0.186350002885, 0.288884997368, 0.107758000493, 0.287292987108, 0.119222998619, 0.246404007077, -0.332718014717, -0.309754997492, 0.326180011034, 0.499563008547, -0.131274998188, 0.238587006927, -0.317025989294, -0.008682000451, 0.619518995285, 0.316774994135, -0.053045999259, 0.028408000246, -0.428086012602, -0.607270002365, 0.657006978989, 0.676119029522, 0.203107997775, -0.316679000854, 0.082666002214, -0.310041993856, 0.603790998459, 0.468154996634, 0.206021994352, 0.028333999217, -0.087867997587, -0.358617991209, 0.128415003419, 0.037046000361, -0.260360985994, -0.210915997624, -0.015564999543, -0.180935993791, 0.083250999451, -0.193316996098, 0.250761002302, 0.202393993735, -0.155086994171, 0.036905001849, 0.418110996485, 0.067231997848, -0.116421997547, -0.341655999422, 0.05919200182, 0.389017999172, -0.544457018375, -0.244222998619, 0.337971001863, 0.163227006793, 0.117914997041, -0.042672999203, -0.215838998556, 0.191798001528, 0.174465000629, -0.055527999997, 0.121985003352, -0.046782001853, -0.347003012896, -0.425747990608, 0.576622009277, 0.322551995516, -0.426732987165, -0.580038011074, -0.579939007759, 0.29191800952, 0.076993003488, 0.220890000463, -0.374727010727, 0.11546599865, 0.239750996232, -0.599394023418, 0.581852018833, -0.124090999365, -0.180638998747, 0.5446190238, -0.65235298872, 0.456075012684, 0.494884997606, 0.484183996916, 0.020594999194, 0.362075001001, -0.089720003307, 0.230300992727, 0.281304001808, 0.286731004715, 0.374053001404, -0.177623003721, 0.090945996344, -0.399394005537, 0.573561012745, 0.130366995931, 0.15235799551, -0.323183000088, 0.143162995577, 0.274109989405, 0.520829021931, 0.171061992645, -0.079223997891, -0.529187977314, 0.109682999551, -0.433328002691, -0.26163700223, -0.624193012714, 1.016695022583, -0.359939008951, 0.183194994926, 0.018155999482, -0.14149799943, -0.240256994963, 0.413583993912, 0.378069013357, -0.35772100091, 0.056784998626, 0.842347025871, -0.041281998158, 0.121949002147, -0.55557101965, -0.012947999872, -0.451754003763, 0.095089003444, 0.468187004328, -0.376350998878, 0.78152102232, 0.307211011648, -0.709493994713, -0.498080998659, -0.324746012688, -0.199910998344, 0.066499002278, -0.047377999872, -0.116584002972, -0.392536014318, 0.534222006798, -0.004480999894, 0.106450997293, 0.492370009422, -0.205549001694, -0.138926997781, -0.25551199913, 0.122440002859, -0.063225999475, 0.400667995214, -0.294638991356, -0.618892014027, -0.163193002343, -0.203306004405, -0.500850975513, 0.183540001512, -0.46670499444, -0.213167995214, -0.276264995337, 0.204497992992, -0.156630992889, 0.383563011885, 0.496547013521, 0.113885998726, 0.020508000627, -0.389571994543, 0.218575999141, -0.064272001386, -0.026503000408, -0.173591002822, 0.254842013121, 0.464908987284, -0.103918999434, -0.269497007132, 0.070835001767, 0.203738003969, 0.181133002043, -0.246653005481, -0.136351004243, -0.24780100584, 0.326480001211, -0.193390995264, -0.041266001761, 0.245121002197, -0.118851996958, -0.083679996431, -0.171301007271, 0.031709998846, -0.332567989826, -0.059787001461, 0.001627000049, -0.048179998994, -0.396964997053, 0.31639200449, -0.352144986391, 0.008798000403, -0.232255995274, -0.394028007984, 0.116296000779, 0.171626001596, 0.013128999621, -0.295181006193}, processTime:“1″}

set bRec to {startTime:“1477635460487″, |word|:“アムロ・レイ”, endTime:“1477635460487″, |log|:“Success.”, |vector|:{0.03407099843, 0.10659699887, 0.127606004477, -0.13093200326, 0.17143599689, -0.386317998171, 0.223474994302, -0.63797801733, -0.21521499753, 0.215176001191, 0.607864022255, 0.176204994321, -0.184221997857, 0.361393988132, 0.16435199976, 0.652567028999, 0.242174997926, -0.325437992811, 0.394699007273, -0.393142998219, -0.312689989805, 0.173059001565, 0.660327970982, -0.07935500145, -0.34789198637, -0.223361998796, -0.153245002031, 0.175822004676, 0.104438997805, 0.50031298399, 0.16487300396, -0.138288006186, -0.054469998926, 0.100807003677, 0.05673699826, -0.067408002913, 0.017626000568, -0.07518299669, -0.201003998518, -0.005166999996, -0.088767997921, 0.615378975868, 0.126588001847, -0.127129003406, 0.159886002541, 0.374316006899, -0.03769300133, -0.050262000412, 0.063642002642, 0.169852003455, 0.409768998623, -0.453413009644, -0.122203998268, 0.294649988413, 0.11619400233, 0.576021015644, -0.117141999304, -0.486111998558, 0.283957004547, -0.101135000587, -0.078950002789, 0.173895001411, -0.083311997354, 0.028666999191, -0.21795900166, 0.184988006949, -0.185552999377, -0.399181008339, -0.098324000835, -0.352382987738, 0.075119003654, -0.17525100708, 0.373353004456, -0.152073994279, 0.051049001515, 0.110192000866, -0.726333022118, 0.334517002106, -0.075718998909, -0.354999989271, 0.655991971493, -0.298009991646, 0.508288025856, 0.243245005608, 0.239094004035, -0.086781002581, -0.161684006453, -0.507776021957, 0.261065006256, 0.284135997295, 0.307931989431, 0.213102996349, 0.136901006103, 0.397157996893, -0.464179992676, 0.262387990952, 0.380863010883, -0.071410998702, -0.165156006813, 0.135739997029, 0.283789008856, 0.820464015007, -0.359337002039, 0.155907005072, -0.330406993628, 0.400182008743, 0.119069002569, -0.182172998786, -0.147823005915, 0.674717009068, -0.637548983097, -0.110163003206, 0.025941999629, -0.274792999029, -0.184186995029, 0.543650984764, 0.189351007342, -0.354799985886, -0.005100999959, 0.318190008402, 0.088809996843, 0.300523996353, -0.336024999619, -0.279132008553, -0.489708006382, 0.119197003543, 0.357654988766, -0.009196000174, 0.908367991447, 0.127497002482, -0.877427995205, -0.362311005592, 0.045292001218, 0.228176996112, 0.003637999995, -0.021867999807, 0.264483004808, -0.531185984612, 0.075176000595, -0.258029013872, 0.180007994175, 0.549230992794, 0.085698001087, 0.164148002863, 0.198268994689, 0.206103995442, 0.182986006141, 0.262667000294, -0.509878993034, -0.44718798995, 0.136090993881, -0.18127900362, -0.148757994175, 0.263893991709, -0.386029988527, -0.198642000556, 0.220932006836, 0.202956005931, 0.048569001257, 0.194492995739, 0.180389001966, 0.697315990925, 0.139156997204, -0.228732004762, 0.201507002115, -0.043519001454, -0.419701009989, -0.424322992563, 0.085637003183, 0.513258993626, -0.90073800087, -0.365974009037, -0.043921001256, -0.012201000005, 0.343672990799, -0.352656006813, 0.335415005684, -0.584758996964, -0.045765001327, -0.614067018032, 0.095513001084, 0.461355000734, -0.371479004622, -0.612700998783, 0.043907001615, 0.56964302063, -0.364234000444, -0.080641999841, 0.140410006046, -0.180212005973, -0.543507993221, 0.225119993091, -0.285872995853, 0.08812700212, -0.299535006285, 0.026107000187, -0.221154004335, 0.39902600646, 0.160721004009, -0.433041006327}, processTime:“0″}

set cRec to {startTime:“1477635477524″, |word|:“ガンキャノン”, endTime:“1477635477524″, |log|:“Success.”, |vector|:{0.072226002812, -0.123470000923, 0.229124993086, 0.024253999814, 0.090787000954, -0.554116010666, 0.127351999283, -0.277144014835, -0.273193985224, 0.049963001162, 0.459771990776, -0.271524995565, 0.12961499393, -0.174656003714, 0.56355202198, 0.922071993351, 0.629299998283, 0.046698000282, 0.017914000899, -0.093442000449, -0.435452997684, 0.599241018295, 0.600166976452, -0.085536003113, -0.361353993416, 0.147931993008, -0.145070001483, 0.277393013239, 0.016388999298, 0.262728989124, 0.212905004621, 0.189909994602, -0.292201012373, 0.332486003637, 0.308021992445, -0.036079999059, -0.271553009748, -0.20025600493, -0.090479001403, 0.268270999193, -0.272096991539, 0.199298992753, 0.15323600173, -0.348919987679, 0.290313988924, 0.180563002825, -0.179280996323, -0.239015996456, -0.279372006655, 0.237440004945, 0.588576972485, -0.73378098011, -0.176648005843, 0.382687985897, 0.023191999644, 0.218005001545, 0.104557998478, -0.209011003375, -0.139624997973, 0.429735004902, 0.027498999611, -0.114556998014, 0.439689993858, -0.343279987574, -0.206854000688, 0.510254979134, 0.38624098897, -0.413646996021, -0.354449987411, -0.344117999077, -0.059645000845, 0.084478996694, 0.013961999677, -0.162633001804, 0.16069200635, -0.239609003067, -0.710308015347, 0.490334004164, 0.209011003375, -0.068875998259, 0.620296001434, -0.67517799139, 0.308690011501, 0.349496990442, 0.543331027031, 0.014736999758, 0.265686988831, -0.242991000414, 0.08111499995, 0.433555006981, 0.534663021564, 0.440093994141, 0.046149998903, 0.456764996052, -0.426779985428, 1.205618023872, 0.433625012636, 0.19698600471, -0.024245999753, -0.195654004812, 0.778258979321, 1.02594602108, -0.0279610008, -0.08894199878, -0.757061004639, 0.001425000024, -0.355924993753, 0.055286001414, 0.080266997218, 0.389950990677, -0.39531698823, 0.532419979572, 0.106784999371, -0.050149999559, -0.230510994792, 0.41841301322, 0.785488009453, 0.17853499949, 0.012822999619, 0.533285975456, 0.046064998955, 0.457116991282, -0.336412996054, 0.086345002055, -0.490134000778, -0.060506001115, 0.505389988422, -0.440815001726, 0.701705992222, 0.233691006899, -0.556469976902, -0.175993993878, 0.047694001347, -0.439999997616, 0.048073999584, 0.32014799118, -0.157723993063, -0.406812012196, -0.235781997442, 0.149423003197, 0.221878007054, 0.274697005749, -0.336528003216, -0.027574999258, -0.05121299997, 0.049157001078, -0.061744999141, 0.571139991283, -0.426824986935, -0.511521995068, -0.180418998003, -0.173777997494, -0.501815021038, 0.165115997195, -0.52134001255, -0.110209003091, -0.296977996826, 0.113278999925, -0.254267007113, 0.274937003851, 0.171541005373, 0.226473003626, -0.05610800162, -0.063437998295, 0.179731994867, 0.016723999754, -0.181597992778, -0.0923660025, 0.297807008028, 0.402370989323, -0.933079004288, -0.062503002584, 0.156483992934, 0.066535003483, -0.129124999046, -0.464343994856, 0.046394001693, -0.510720014572, 0.117109999061, -0.378863990307, 0.104653000832, 0.297672003508, 0.057688999921, -0.290758013725, -0.042853001505, 0.69950902462, -0.666705012321, -0.062345001847, 0.131890997291, 0.12205799669, 0.190595000982, 0.141661003232, -0.141069993377, 0.29548099637, -0.252436995506, -0.12503400445, 0.245934993029, 0.292874008417, -0.207329005003, -0.592303991318}, processTime:“0″}

set aList to |vector| of aRec
set bList to |vector| of bRec
set cList to |vector| of cRec

set aRes to calcCosinSimilarity(aList, bList) of me –ガンダムとアムロ・レイ
set bRes to calcCosinSimilarity(aList, cList) of me –ガンダムとガンキャノン
set cRes to calcCosinSimilarity(bList, cList) of me –アムロ・レイとガンキャノン

return {aRes, bRes, cRes}
–> {44.057800255168, 50.555325012947, 32.83911534787}
–(1)「ガンダムとガンキャノン」、(2)「ガンダムとアムロ・レイ」、(3)「アムロ・レイとガンキャノン」の順番

–コサイン類似度をベクターのリストから計算する
on calcCosinSimilarity(aList, bList)
  set aLen to length of aList
  
set bLen to length of bList
  
if aLenbLen then error “Not Same Item Nums”
  
  
set aRes to 0
  
repeat with i from 1 to aLen
    set a1 to (contents of item i of aList)
    
set b1 to (contents of item i of bList)
    
    
set vL to getVectorLength(a1, b1) of me
    
set normF to (1 / vL)
    
set aRes to aRes + ((a1 * normF) * (b1 * normF))
  end repeat
  
  
return aRes
end calcCosinSimilarity

–ベクトルの長さを求める
on getVectorLength(a, b)
  return getSQR(a ^ 2 + b ^ 2) of me
end getVectorLength

–平方根を求める
on getSQR(aNum)
  return (aNum ^ 0.5)
end getSQR

★Click Here to Open This Script 

2016/10/28 ベクトルのコサイン類似度を計算する

ベクトル同士の類似度を求めるために、2つのベクトル同士のコサイン類似度を計算するAppleScriptです。

なんのことやら?(^ー^;;; 

だいたい、なぜこんなものを作ってみたかといえば、Apitoreの「単語ベクトル変換【新語対応】」というWebサービスをAppleScriptから呼び出して、200次元のベクトルを取得。このベクトル同士の類似度を計算する方法を聞いてみたところ、「コサイン距離を求めればわかるよー」とのこと。

本来、単語同士の類似度を計算するサービスはApitoreの「Word2Vec-Neologd-Wiki」にあるSimilarity APIがあり、これを呼べば2つの単語の意味的な近さを求めてくれます。

ただ、ベクトル同士の近さを求める「やりかた」自体は理解しておいたほうがよいと考え、やや「車輪の再発明」的な内容であるものの、調べて、理解して、実装してみました。

なんだー、要素ごとに掛け算して足すだけでいいんじゃん(汗) というわけで、いろいろ実際に計算した内容を検証してみました。

A「富士山」B「エベレスト」C「きゃりーぱみゅぱみゅ」という3つの単語のベクトルを単語ベクトル変換【新語対応】から求め、AとB、AとC、BとCの3つのコサイン類似度の計算を行ってみました。

  富士山とエベレスト:9.96044011858
  富士山ときゃりーぱみゅぱみゅ:5.348813123563
  エベレストときゃりーぱみゅぱみゅ:6.25804549236

この結果から、これら3つの単語の間では「富士山とエベレスト」の類似度が高い、という計算結果が得られました(よかったよかった ^ー^;)。

ちなみに、A「ガンダム」B「アムロ・レイ」C「ガンキャノン」で類似度を計算してみたところ、

  ガンダムとアムロ・レイ:14.92435981554
  ガンダムとガンキャノン:17.465853286865
  アムロ・レイとガンキャノン:15.693039744314

「ガンダムとガンキャノン」というメカ同士の類似度が高いという結果が得られた一方で、アムロ・レイと距離が近いのがガンダムよりもガンキャノンだという謎の計算結果が出てきました。これは、学習データの内容によりものでしょうか。それとも、「こまけえことはいいんだよ」というレベルの問題なんでしょうか。

→ ベクトルを長さで正規化すると解決するとのこと。さぁ、勉強だ(汗)

AppleScript名:ベクトルのコサイン類似度を計算する
– Created 2016-10-28 by Takaaki Naganoya
– 2016 Piyomaru Software
–以下のページを参照しました
–http://www.cse.kyoto-su.ac.jp/~g0846020/keywords/cosinSimilarity.html

–http://piyocast.com/as/archives/4292

set aRec to {startTime:“1477632528599″, |word|:“富士山”, endTime:“1477632528599″, |log|:“Success.”, |vector|:{0.123668000102, -0.309015005827, 0.120112001896, -0.044573001564, 0.313836991787, 0.077581003308, 0.495095998049, -0.352721989155, 0.492121994495, 0.637359976768, 0.116067998111, 0.188023999333, -0.17861700058, -0.28166899085, -0.01465999987, 0.337170988321, -0.071643002331, 0.432227998972, -0.097863003612, -0.035069998354, -0.010216999799, -0.192351996899, 0.319081991911, -0.109619997442, 0.187950998545, -0.27009499073, -0.088083997369, 0.284711003304, 0.128161996603, -0.291191011667, -0.052581999451, -0.291323006153, -0.403849005699, 0.480201989412, -0.261173009872, -0.603130996227, 0.340840995312, -0.538646996021, 0.441242009401, 0.168537005782, -0.287396997213, 0.027472000569, 0.478017985821, 0.006159000099, -0.536579012871, -0.182714998722, -0.434570014477, -0.619507014751, -0.044015999883, -0.066451996565, 0.252929985523, 0.088529996574, -0.263377010822, 0.312680006027, 0.174722999334, -0.117349997163, 0.059971999377, -0.477564007044, -0.220599994063, 0.322254002094, -0.093304999173, 0.297847986221, -0.308070003986, 0.007362000179, -0.201299995184, 0.564171016216, 0.197040006518, -0.212391003966, -0.332953006029, -0.015080000274, 0.061990000308, 0.300307005644, 0.063493996859, -0.033411998302, -0.274958997965, -0.239563003182, -0.499040007591, 0.127872005105, -0.08571100235, 0.209193006158, -0.010835999623, -0.373616993427, -0.13042999804, 0.322919011116, 0.569968998432, 0.135514006019, 0.412106990814, 0.246760994196, 0.584402024746, 0.038107000291, 0.485549002886, 0.36462700367, 0.210249006748, 0.168840005994, -0.015666000545, -0.231536999345, -0.339715987444, 0.12304700166, -0.186777994037, -0.291483014822, 0.328925997019, -0.075723998249, -0.313980996609, -0.460673004389, -0.305492013693, 0.083364002407, 0.28477498889, 0.163294002414, 0.020129000768, 0.138465002179, -0.280802994967, 0.0436029993, 0.114759996533, -0.494895011187, 0.526228010654, 0.214810997248, 0.592833995819, -0.495696008205, 0.446736991405, 0.147870004177, 0.09175799787, -0.071817003191, 0.095923997462, -0.323009997606, 0.282640010118, 0.197969004512, 0.017850000411, -0.220227003098, 0.057261001319, 0.5905200243, -0.261938005686, 0.238176003098, -0.202760994434, -0.042277999222, 0.639414012432, -0.042134001851, -0.076684996486, -0.118372000754, 0.333503007889, -0.22937899828, -0.299755007029, -0.443275988102, -0.31064799428, 0.301041990519, -0.056919999421, 0.286974996328, 0.50066202879, -0.196336001158, 0.005377999973, -0.049904000014, -0.872128009796, 0.097332000732, 0.273398011923, 0.015759000555, -0.182218998671, 0.018466999754, 0.619598984718, 0.276064991951, -0.191751003265, 0.025626000017, 0.12149900198, 0.00335699995, -0.112106002867, -0.097810000181, 0.170493006706, 0.321725994349, 0.06719700247, -0.009019000456, -0.056265998632, 0.147505998611, 0.136828005314, 0.228912994266, 0.329273998737, -0.011854999699, 0.038917001337, -0.122969001532, 0.194609001279, -0.158902004361, -0.372310996056, -0.433764994144, 0.023022999987, 0.764874994755, 0.246930003166, -0.331984996796, -0.00559599977, 0.078703999519, 0.091015003622, 0.119796998799, 0.006475999951, 0.124388001859, 0.199450001121, 0.327385008335, -0.006484000012, 0.067487999797, 0.17902199924, -0.356110006571, -0.206619992852, 0.086388997734, -0.275979995728, -0.136234998703}, processTime:“0″}

set bRec to {startTime:“1477632723419″, |word|:“エベレスト”, endTime:“1477632723419″, |log|:“Success.”, |vector|:{0.232161998749, -0.021962000057, 0.018812000751, 0.019821999595, -0.172334998846, -0.207186996937, 0.131844997406, -0.304751992226, -0.044002000242, 0.681266009808, -0.321467995644, 0.303873986006, -0.19711600244, -0.806095004082, -0.046836998314, -0.160034000874, 0.036371000111, 0.706255972385, 0.053663000464, -0.246535003185, -0.13503099978, 0.073703996837, 0.197100996971, -0.171170994639, 0.193028002977, -0.215641006827, 0.220181003213, 0.603963017464, 0.208072006702, 0.188728004694, 0.088546000421, -0.361923009157, 0.07780700177, -0.059170998633, -0.068483002484, -0.805943012238, 0.122937999666, -0.318515002728, 0.465512007475, 0.264575988054, -0.308703988791, -0.162440001965, 0.371463000774, 0.011003999971, -0.44861599803, -0.052464999259, -0.079640999436, -0.742060005665, 0.004040999804, 0.00926699955, 0.106600999832, 0.023274000734, -0.225715994835, -0.023219000548, 0.003835000098, 0.330017000437, 0.450482994318, -0.321902990341, 0.221350997686, -0.031302001327, -0.074280999601, -0.057861000299, 0.122330002487, 0.359564006329, -0.182457000017, 0.15286000073, 0.300184994936, -0.264039993286, -0.23186199367, -0.212647005916, 0.022517999634, 0.06595300138, 0.322301000357, -0.685081005096, -0.207968994975, 0.125552996993, -0.568157970905, 0.373304992914, -0.317216992378, -0.200730994344, -0.078373000026, -0.423943012953, -0.145215004683, -0.07396300137, 0.174961999059, 0.653276979923, 0.163136005402, -0.386029005051, 0.318922996521, -0.397913008928, 0.446060985327, -0.020895000547, -0.65869897604, 0.412039995193, 0.343986004591, 0.147389993072, -0.001555999974, 0.19599199295, 0.128003999591, -0.560048997402, -0.031364999712, 0.103477999568, -0.62273401022, -0.152143999934, -0.769581973553, 0.329198986292, -0.024667000398, 0.061011999846, 0.203813001513, 0.300633996725, -0.918317019939, -0.110868997872, 0.058814998716, -0.473046988249, 0.317030012608, 0.014874000102, 0.756187975407, -0.373053014278, 0.016914999112, -0.286927014589, 0.038632001728, -0.183412998915, 0.010959000327, -0.632750988007, 0.469480007887, -0.218618005514, 0.113091997802, -0.177783995867, -0.068285003304, -0.108176998794, -0.384323000908, -0.139712005854, -0.224274992943, 0.281195014715, 0.324263989925, 0.230408996344, 0.055860001594, -0.027174999937, -0.079732000828, -0.390644013882, -0.561515986919, -0.64296400547, 0.074805997312, -0.134819999337, 0.699452996254, -0.097543999553, 0.650906980038, 0.016352999955, 0.237734004855, 0.100365996361, 0.281136989594, 0.074234999716, 0.2350410074, -0.754948019981, -0.447870999575, 0.170350000262, 0.469761997461, 0.075043998659, -0.560901999474, 0.050087001175, 0.067097000778, -0.204071000218, -0.089464001358, -0.604591012001, 0.399424999952, -0.188191995025, -0.184063002467, -0.275462001562, -0.438647985458, -0.028305999935, -0.10909999907, 0.306037008762, 0.553808987141, -0.042507998645, -0.089280001819, -0.030742000788, 0.307033002377, -0.102701000869, -0.226081997156, 0.122754998505, -0.509634971619, 0.82189899683, 0.012555999681, -0.309893995523, 0.617228984833, 0.13081599772, 0.264277994633, -0.521031022072, 0.369996011257, 0.402808994055, 0.169545993209, -0.144013002515, -0.26952201128, 0.852178990841, 0.489789992571, -0.407970011234, -0.20611999929, -0.025805000216, -0.042392000556, -0.245032995939}, processTime:“0″}

set cRec to {startTime:“1477632906147″, |word|:“きゃりーぱみゅぱみゅ”, endTime:“1477632906147″, |log|:“Success.”, |vector|:{0.117769002914, 0.547421991825, -0.55005300045, -0.004116999917, 0.037840001285, -0.220541000366, 0.278791993856, -0.126565992832, -0.11717300117, -0.134132996202, -0.169262006879, -0.047348998487, 0.139651998878, 0.096625000238, -0.524344027042, 0.171568006277, -0.438012003899, 0.096740998328, 0.181114003062, -0.507890999317, -0.162144005299, -0.256267994642, 0.787092983723, -0.301274001598, -0.131623998284, -0.667850971222, 0.126826003194, 0.399556994438, -0.331470012665, 0.086039997637, -0.207508996129, -0.341479003429, 0.453637003899, 0.682955026627, 0.022078000009, -0.187252998352, 0.1002940014, -0.123255997896, 0.297253012657, 0.347470998764, 0.979870975018, 0.439393997192, 0.264191001654, -0.245868995786, -0.534951984882, 0.524555027485, -0.281354993582, -0.382270008326, -0.550571024418, -0.219003006816, 0.700820982456, 0.090194001794, 0.438223004341, 0.132016003132, -0.120622001588, 0.094403997064, -0.341901004314, -0.091567002237, 0.096225000918, -0.574598014355, 0.054416999221, -0.12799499929, 0.207303002477, 0.40427801013, 0.237173005939, 0.645721971989, 0.359672009945, -0.744382977486, 0.071580000222, 0.231180995703, 0.02777400054, 0.596056997776, 0.363346010447, -0.457264989614, -0.19236600399, -0.514294981956, -0.183853000402, 0.215189993382, -0.372281998396, -0.235982000828, 0.153041005135, -0.050188001245, 0.359631001949, -0.440890014172, 0.174553006887, -0.100065998733, 0.210250005126, 0.280330985785, 0.398196995258, 0.281033992767, 0.437768012285, 0.521552026272, -0.481240004301, -0.100391998887, 0.687992990017, 0.415670007467, 0.054366998374, 0.302630990744, 0.081652998924, -0.326240986586, 0.312976002693, 0.380755007267, 0.360621005297, -0.277276992798, -0.586230993271, 0.284016996622, -0.145888999104, -0.001132000005, 0.148311004043, 0.462684988976, -0.186974003911, -0.078097999096, -0.23281699419, -0.601405024529, 0.15837700665, 0.270709007978, 0.093841001391, -0.415028005838, 0.17201000452, -0.199463993311, -0.206508994102, 0.053318999708, 0.02006999962, -0.278010010719, 0.069329999387, -0.211704999208, 0.353031992912, 0.172609999776, 0.551793992519, 0.14820599556, -0.182607993484, 0.301723003387, -0.48807901144, 0.072370998561, 0.105828002095, 0.417632997036, 0.369803994894, -0.471235990524, 0.064530000091, -0.206820994616, -0.28040599823, 0.652179002762, -0.340546995401, 0.400236010551, 0.204622000456, 0.056784000248, -0.331907987595, 0.029787000269, -0.311051011086, -0.262612998486, -0.001846999978, 0.027634000406, 0.312009006739, -0.03695999831, -0.153132006526, -0.026866000146, 0.039252001792, 0.203341007233, -0.157428994775, 0.121481001377, -0.154116004705, -0.0451150015, 0.686644017696, -0.484241992235, 0.184045001864, 0.30873298645, 0.204081997275, -0.321480989456, 0.391580998898, -0.106555998325, -0.475353002548, 0.141835004091, 0.37692001462, 0.202901005745, 0.021635999903, 0.070069000125, 0.195032000542, 0.300967991352, -0.341152012348, 0.018368000165, 0.102963000536, 0.260273009539, -0.323379009962, -0.125611007214, 0.145910993218, 0.321619004011, -0.191367998719, 0.006186999846, 0.089144997299, 0.144384995103, -0.150334000587, 0.465972006321, -0.099472999573, -0.001772999996, 0.331198006868, -0.031812999398, -0.196685001254, 0.192193999887, -0.468513011932, 0.307538002729}, processTime:“0″}

set aList to |vector| of aRec
set bList to |vector| of bRec
set cList to |vector| of cRec

set aRes to calcCosinSimilarity(aList, bList) of me –富士山とエベレスト
set bRes to calcCosinSimilarity(aList, cList) of me –富士山ときゃりーぱみゅぱみゅ
set cRes to calcCosinSimilarity(bList, cList) of me –エベレストときゃりーぱみゅぱみゅ

return {aRes, bRes, cRes}
–> {9.96044011858, 5.348813123563, 6.25804549236}–「富士山とエベレスト」の距離が一番近い

–コサイン類似度をベクターのリストから計算する
on calcCosinSimilarity(aList, bList)
  set aLen to length of aList
  
set bLen to length of bList
  
if aLenbLen then error “Not Same items”
  
  
set aRes to 0
  
repeat with i from 1 to aLen
    set a1 to contents of item i of aList
    
set b1 to contents of item i of bList
    
set c to a1 * b1
    
set aRes to aRes + c
  end repeat
  
  
return aRes
end calcCosinSimilarity

★Click Here to Open This Script 

2016/06/17 ASOCでmdfindするじっけん v4(フルパスを返す)

Spotlightの機能をCocoa経由で呼び出してmdfindコマンドのクエリーと検索対象フォルダをPOSIX pathで与えると、条件に合致するファイルのPOSIX pathをリストに入れて返してくるAppleScriptです。

以前に掲載したバージョンを実際に使おうとしたら、激しく間違っていることを発見。なんで気がつかなかったんでしょう。いえ、なんでこんな忙しいときに気づいてしまうんでしょう。

AppleScript名:ASOCでmdfindするじっけん v4(フルパスを返す)
– Created 2016-06-17 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

property searchRes : {}

set origPath to POSIX path of (choose folder)
set aList to spotlightSearch(origPath, “kMDItemContentType == ’net.daringfireball.markdown’”) of me

on spotlightSearch(origPath, aMDfindParam)
  
  
set my searchRes to {} –initialize
  
initiateSearchForFullPath(aMDfindParam, origPath) –Predicate & Scope Directory
  
  
–Waiting for the result
  
repeat while my searchRes = {}
    delay 0.01
  end repeat
  
  
set anObj to my searchRes’s firstObject() –Pick up the first one for test
  
if anObj = missing value then return {} –No Result
  
  
set resArray to {}
  
repeat with anItem in my searchRes
    set j to contents of anItem
    
set aPath to (j’s valueForAttribute:“kMDItemPath”) as string
    
set the end of resArray to aPath
  end repeat
  
  
return resArray
  
end spotlightSearch

on initiateSearchForFullPath(aQueryStrings, origPath)
  
  
set aSearch to current application’s NSMetadataQuery’s alloc()’s init()
  
  
current application’s NSNotificationCenter’s defaultCenter()’s addObserver:(me) selector:“queryDidUpdate:” |name|:(current application’s NSMetadataQueryDidUpdateNotification) object:aSearch
  
current application’s NSNotificationCenter’s defaultCenter()’s addObserver:(me) selector:“initalGatherComplete:” |name|:(current application’s NSMetadataQueryDidFinishGatheringNotification) object:aSearch
  
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aQueryStrings
  
aSearch’s setPredicate:aPredicate
  
  
set aScope to current application’s NSArray’s arrayWithObjects:{origPath}
  
aSearch’s setSearchScopes:aScope
  
  
set sortKeys to current application’s NSSortDescriptor’s sortDescriptorWithKey:“kMDItemFSName” ascending:true
  
aSearch’s setSortDescriptors:(current application’s NSArray’s arrayWithObject:sortKeys)
  
  
aSearch’s startQuery()
  
end initiateSearchForFullPath

on queryDidUpdate:sender
  log sender
  
–> (NSConcreteNotification) NSConcreteNotification 0×7fa618450820 {name = NSMetadataQueryDidFinishGatheringNotification; object = }
end queryDidUpdate:

on initalGatherComplete:sender
  set anObject to sender’s object
  
anObject’s stopQuery()
  
current application’s NSNotificationCenter’s defaultCenter()’s removeObserver:me |name|:(current application’s NSMetadataQueryDidUpdateNotification) object:anObject
  
current application’s NSNotificationCenter’s defaultCenter()’s removeObserver:me |name|:(current application’s NSMetadataQueryDidFinishGatheringNotification) object:anObject
  
  
set my searchRes to anObject’s results()
end initalGatherComplete:

★Click Here to Open This Script 

2016/03/11 shellの出力結果をスペースでparseする

shellの出力結果を利用する際に、スペースでparseするAppleScriptです。

連続するスペースキャラクターでparseしつつ不要なゴミを削除して必要な項目だけ取得するというものです。

AppleScript名:shellの出力結果をスペースでparseする
– Created 2016-03-11 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set a to "3 0×4248387 1920×1200 0 0 -1920 -1200 0 [main]"

set aStr to (current application’s NSString’s stringWithString:a)
–> (NSString) "3 0×4248387 1920×1200 0 0 -1920 -1200 0 [main]"

set aLine to (aStr’s componentsSeparatedByString:" ")
–> (NSArray) {"3", "", "0×4248387", "", "", "", "", "1920×1200", "", "", "", "", "", "0", "", "", "", "", "0", "", "-1920", "", "-1200", "", "", "", "", "", "0", "", "", "", "[main]"}

(aLine’s removeObject:"")
–> (NSArray) {"3", "0×4248387", "1920×1200", "0", "0", "-1920", "-1200", "0", "[main]"}

set bList to aLine as list
–>  {"3", "0×4248387", "1920×1200", "0", "0", "-1920", "-1200", "0", "[main]"}

★Click Here to Open This Script