Archive for the '10.10 savvy' Category

2017/06/22 指定矩形内に含まれるデータをリストで返す v3

指定矩形座標内に指定座標が含まれるかどうかを判定するAppleScriptです。

NSPointInRectを見つけて、NSRectの中にNSPointが含まれるかどうかチェックできることがわかりました(汗)

→ 矩形座標(NSRect)同士の衝突判定はこちら

AppleScript名:指定矩形内に含まれるデータをリストで返す v3
– Created 2017-06-22 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4702

set aList to {{507, 162}, {338, 166}, {389, 166}, {448, 166}, {286, 110}, {504, 109}, {558, 108}, {341, 113}, {394, 115}, {447, 112}, {234, 107}, {611, 110}, {286, 58}, {501, 63}, {556, 58}, {337, 59}, {391, 60}, {448, 63}, {611, 58}}

set rangeList to {{500, 100}, {550, 180}} –{{x1,y1}, {x2,y2}}
set resList to withinRange(rangeList, aList) of me
–>  {{507, 162}, {504, 109}}

on withinRange(rangeList as list, targetList as list)
  set aRect to makeNSRect(rangeList) of me
  
  
set includedList to {}
  
repeat with i in targetList
    copy i to {x, y}
    
set aPoint to current application’s NSMakePoint(x, y)
    
set aRes to (current application’s NSPointInRect(aPoint, aRect)) as boolean
    
    
if aRes = true then
      set the end of includedList to contents of i
    end if
  end repeat
  
  
return includedList
end withinRange

on makeNSRect(aList as list)
  try
    copy aList to {{x1, y1}, {x2, y2}}
    
set xWidth to (x2 - x1)
    
set yHeight to (y2 - y1)
    
set a1Rect to {origin:{x:x1, y:y1}, |size|:{width:xWidth, height:yHeight}}
    
return a1Rect
  on error
    return missing value
  end try
end makeNSRect

★Click Here to Open This Script 

2017/06/22 指定矩形内に含まれるデータをリストで返す v2

指定矩形座標内に指定座標が含まれるかどうかを判定するAppleScriptです。

以前に掲載したPure AppleScript版から改修してCocoaの機能で書き直してみました。ただ、これで正しいのかどーかというのはいまひとつ確証がありません。

width=0, height=0のRectを作ってオーバーラップのチェックをしてみましたが、これではオーバーラップの検出ができなかったためにwidth=1, height=1にしてみました。

→ やっぱり計算内容に納得が行かなかったので作った改修版(v3)はこちら

AppleScript名:指定矩形内に含まれるデータをリストで返す v2
– Created 2017-06-22 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4701

set aList to {{507, 162}, {338, 166}, {389, 166}, {448, 166}, {286, 110}, {504, 109}, {558, 108}, {341, 113}, {394, 115}, {447, 112}, {234, 107}, {611, 110}, {286, 58}, {501, 63}, {556, 58}, {337, 59}, {391, 60}, {448, 63}, {611, 58}}

set rangeList to {{500, 100}, {550, 180}} –{{x1,y1}, {x2,y2}}
set resList to withinRange(rangeList, aList) of me
–>  {{507, 162}, {504, 109}}

on withinRange(rangeList, targetList)
  set aRect to makeNSRect(rangeList) of me
  
  
set includedList to {}
  
repeat with i in targetList
    set bRect to makeNSRectFromXY(i) of me
    
if bRect = missing value then error “Missing Data”
    
set aRes to detectRectanglesCollision(aRect, bRect) of me
    
if aRes = true then
      set the end of includedList to contents of i
    end if
  end repeat
  
  
return includedList
end withinRange

on makeNSRectFromXY(bList as list)
  try
    copy bList to {x, y}
    
set xWidth to 1
    
set yHeight to 1
    
set a1Rect to {origin:{x:x, y:y}, |size|:{width:xWidth, height:yHeight}}
    
return a1Rect
  on error
    return missing value
  end try
end makeNSRectFromXY

on makeNSRect(aList as list)
  try
    copy aList to {{x1, y1}, {x2, y2}}
    
set xWidth to (x2 - x1)
    
set yHeight to (y2 - y1)
    
set a1Rect to {origin:{x:x1, y:y1}, |size|:{width:xWidth, height:yHeight}}
    
return a1Rect
  on error
    return missing value
  end try
end makeNSRect

–NSRect同士の衝突判定
on detectRectanglesCollision(aRect, bRect)
  set a1Res to current application’s NSIntersectionRect(aRect, bRect)
  
return not (a1Res = {origin:{x:0.0, y:0.0}, |size|:{width:0.0, height:0.0}})
end detectRectanglesCollision

★Click Here to Open This Script 

2017/06/21 日の出、日没時刻を計算するv2

オープンソースのプロジェクト「EDSunriseSet」(By Ernesto García)をFramework化した「EDSunriseSet.framework」を呼び出して日の出、日没時刻を計算するAppleScriptのアップデート版です。

本AppleScriptのテストのためには、EDSunriseSet.frameworkを~/Library/Frameworksフォルダに入れておく必要があります。バイナリを用意しておきましたので、自己責任でおためしください。

→ Download Binary (26KB)

EDSunriseSetが用意している各種の日の出、日没情報を取得するようにしてみました。

日没や日の出前後の「薄明」の情報についても取得します。

1024px-twilight_subcategoriessvg_resized.png

ただ、白夜などの現象が発生しない地域でこれらの薄明の情報はとくに必要はないように感じます(個人の見解です)。

AppleScript名:日の出、日没時刻を計算するv2
– Created 2017-06-19 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “EDSunriseSet” –erndev/EDSunriseSet
–https://github.com/erndev/EDSunriseSet
–http://piyocast.com/as/archives/4699

set cityRecList to {{kCityName:“Tokyo”, kCityLatitude:(35.6894875), kCityLongitude:(139.6917064), kCityTimeZone:“Asia/Tokyo”}}

set dList to {}

repeat with i in cityRecList
  set the end of dList to getSunriseSunset(i) of me
end repeat
return dList
–>  {{sunrise:date “2017年6月21日水曜日 4:25:37″, sunset:date “2017年6月21日水曜日 19:00:21″, civilTwilightStart:date “2017年6月21日水曜日 3:55:35″, civilTwilightEnd:date “2017年6月21日水曜日 19:30:23″, nauticalTwilightStart:date “2017年6月21日水曜日 3:18:15″, nauticalTwilightEnd:date “2017年6月21日水曜日 20:07:44″, astronomicalTwilightStart:date “2017年6月21日水曜日 2:36:45″, astronomicalTwilightEnd:date “2017年6月21日水曜日 20:49:13″, cityname:”Tokyo”}}

on getSunriseSunset(cityRec)
  set curLocale to current application’s NSLocale’s currentLocale()
  
set curDate to current application’s NSDate’s |date|()
  
  
set aTZ to current application’s NSTimeZone’s alloc()’s initWithName:(kCityName of cityRec)
  
set aSunrizeSunset to current application’s EDSunriseSet’s alloc()’s initWithDate:curDate timezone:aTZ latitude:(kCityLatitude of cityRec) longitude:(kCityLongitude of cityRec)
  
  
–日の出、日没  
  
set aSunRiseDate to (aSunrizeSunset’s sunrise) as date
  
set aSunSetDate to (aSunrizeSunset’s sunset) as date
  
  
–https://en.wikipedia.org/wiki/Twilight
  
–https://ja.wikipedia.org/wiki/薄明
  
  
–市民薄明(常用薄明、第三薄明)
  
set aCivilTwilightStart to (aSunrizeSunset’s civilTwilightStart) as date
  
set aCivilTwilightEnd to (aSunrizeSunset’s civilTwilightEnd) as date
  
  
–航海薄明(第二薄明)
  
set aNauticalTwilightStart to (aSunrizeSunset’s nauticalTwilightStart) as date
  
set aNauticalTwilightEnd to (aSunrizeSunset’s nauticalTwilightEnd) as date
  
  
–天文薄明(第一薄明)
  
set anAstronomicalTwilightStart to (aSunrizeSunset’s astronomicalTwilightStart) as date
  
set anAstronomicalTwilightEnd to (aSunrizeSunset’s astronomicalTwilightEnd) as date
  
  
return {sunrise:aSunRiseDate, sunset:aSunSetDate, civilTwilightStart:aCivilTwilightStart, civilTwilightEnd:aCivilTwilightEnd, nauticalTwilightStart:aNauticalTwilightStart, nauticalTwilightEnd:aNauticalTwilightEnd, astronomicalTwilightStart:anAstronomicalTwilightStart, astronomicalTwilightEnd:anAstronomicalTwilightEnd, cityname:kCityName of cityRec}
end getSunriseSunset

★Click Here to Open This Script 

2017/06/19 日の出、日没時刻を計算する

オープンソースのプロジェクト「EDSunriseSet」(By Ernesto García)をFramework化した「EDSunriseSet.framework」を呼び出して日の出、日没時刻を計算するAppleScriptです。

edsunriseset.png
▲もともとのGUI版サンプルプログラム

本AppleScriptのテストのためには、EDSunriseSet.frameworkを~/Library/Frameworksフォルダに入れておく必要があります。バイナリを用意しておきましたので、自己責任でおためしください。

→ Download Binary (26KB)

本Scriptは単にEDSunriseSetのサンプル中に書かれていたサンプルデータをそのまま利用したものであり、本来であればCoreLocationを呼び出して現在位置を取得し、システム設定からタイムゾーン情報を取得し位置情報から逆住所ジオコーダーで場所の住所情報を取得するといった処理になることでしょう。もちろん、任意の年月日の日付オブジェクトを作って指定するとか。

AppleScript名:日の出、日没時刻を計算する
– Created 2017-06-19 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “EDSunriseSet” –erndev/EDSunriseSet
–https://github.com/erndev/EDSunriseSet
–http://piyocast.com/as/archives/4696

set cityRecList to {{kCityName:“Madrid”, kCityLatitude:(40.4165), kCityLongitude:(-3.70256), kCityTimeZone:“Europe/Madrid”}, {kCityName:“Beijing”, kCityLatitude:(39.9075), kCityLongitude:(116.39723), kCityTimeZone:“Asia/Shanghai”}, {kCityName:“Cupertino”, kCityLatitude:(37.3229978), kCityLongitude:(-122.0321823), kCityTimeZone:“America/Los_Angeles”}, {kCityName:“New York”, kCityLatitude:(40.7127837), kCityLongitude:(-74.0059413), kCityTimeZone:“America/New_York”}, {kCityName:“Tokyo”, kCityLatitude:(35.6894875), kCityLongitude:(139.6917064), kCityTimeZone:“Asia/Tokyo”}, {kCityName:“Sydney”, kCityLatitude:(-33.8674869), kCityLongitude:(151.2069902), kCityTimeZone:“Australia/Sydney”}}

set dList to {}

repeat with i in cityRecList
  set the end of dList to getSunriseSunset(i) of me
end repeat
return dList
–>  {{sunrise:date “2017年6月19日月曜日 13:44:22″, sunset:date “2017年6月20日火曜日 4:48:04″, cityname:”Madrid”}, {sunrise:date “2017年6月19日月曜日 5:45:35″, sunset:date “2017年6月19日月曜日 20:45:54″, cityname:”Beijing”}, {sunrise:date “2017年6月19日月曜日 21:47:30″, sunset:date “2017年6月20日火曜日 12:31:43″, cityname:”Cupertino”}, {sunrise:date “2017年6月19日月曜日 18:24:37″, sunset:date “2017年6月20日火曜日 9:30:19″, cityname:”New York”}, {sunrise:date “2017年6月19日月曜日 4:25:14″, sunset:date “2017年6月19日月曜日 18:59:52″, cityname:”Tokyo”}, {sunrise:date “2017年6月19日月曜日 5:59:28″, sunset:date “2017年6月19日月曜日 15:53:30″, cityname:”Sydney”}}

on getSunriseSunset(cityRec)
  set curLocale to current application’s NSLocale’s currentLocale()
  
set curDate to current application’s NSDate’s |date|()
  
  
set aTZ to current application’s NSTimeZone’s alloc()’s initWithName:(kCityName of cityRec)
  
set aSunrizeSunset to current application’s EDSunriseSet’s alloc()’s initWithDate:curDate timezone:aTZ latitude:(kCityLatitude of cityRec) longitude:(kCityLongitude of cityRec)
  
  
set aSunRiseDate to (aSunrizeSunset’s sunrise) as date
  
–>  date “2017年6月19日月曜日 4:25:14″
  
  
set aSunSetDate to (aSunrizeSunset’s sunset) as date
  
–>  date “2017年6月19日月曜日 18:59:52″
  
  
return {sunrise:aSunRiseDate, sunset:aSunSetDate, cityname:kCityName of cityRec}
end getSunriseSunset

★Click Here to Open This Script 

2017/06/18 PDFから本文テキストを抽出して配列にストアして文字列検索

指定PDFで指定キーワードを検索して、キーワードが存在するページのノンブル(数値)のリストを返すAppleScriptの改良強化版です。

最初にPDFからページ単位でテキストを抽出し、テキスト検索キャッシュを作成。このテキスト検索キャッシュに対して検索を実行し、存在しなかったらPDFに対してテキスト検索を行うようにしてみました。

最初からPDFに対してテキスト検索するよりも、テキスト抽出後に検索するほうが、複数キーワードの検索ではスピードが有利になるものと期待しています。

これで不満が出るようなら、AppleScriptで並列処理を行なって処理速度をかせぐしかないでしょう。

AppleScript名:PDFから本文テキストを抽出して配列にストアして文字列検索
– Created 2017-06-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4691

property textCache : missing value
property aList : {}

–検索対象の語群
set sList to {“notification”, “Cocoa”} –considering case

set thePath to POSIX path of (choose file of type {“com.adobe.pdf”})

–PDFのテキスト内容をあらかじめページごとに読み取って、検索用のテキストキャッシュを作成
set anNSURL to (current application’s |NSURL|’s fileURLWithPath:thePath)
set theDoc to current application’s PDFDocument’s alloc()’s initWithURL:anNSURL
set theCount to theDoc’s pageCount() as integer

set textCache to current application’s NSMutableArray’s new()

repeat with i from 0 to (theCount - 1)
  set aPage to (theDoc’s pageAtIndex:i)
  
set tmpStr to (aPage’s |string|())
  (
textCache’s addObject:{pageIndex:i + 1, pageString:tmpStr})
end repeat

–主にテキストキャッシュを対象にキーワード検索
repeat with s in sList
  
  
–❶部分一致で抽出
  
set bRes to ((my filterRecListByLabel1(textCache, “pageString contains ’” & s & “’”))’s pageIndex) as list
  
  
–❷、❶のページ単位のテキスト検索で見つからなかった場合(ページ間でまたがっている場合など)
  
if bRes = {} then
    set bRes to {}
    
set theSels to (theDoc’s findString:s withOptions:0)
    
repeat with aSel in theSels
      set thePage to (aSel’s pages()’s objectAtIndex:0)’s label()
      
set curPage to (thePage as integer)
      
if curPage is not in bRes then
        set the end of bRes to curPage
      end if
    end repeat
  end if
  
  
set the end of aList to bRes
  
end repeat

return aList

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel1(aRecList as list, aPredicate as string)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
return filteredArray
end filterRecListByLabel1

★Click Here to Open This Script 

2017/06/17 PDFでテキスト検索してキーワードの存在ページをリストで返す

指定PDFで指定キーワードを検索して、キーワードが存在するページのノンブル(数値)のリストを返すAppleScriptです。

自分の書いた本のPDFファイル(483ページ)で検索を行なってみたところ、数秒程度はかかりました。

この手の処理では、同じScriptを実行しても2回目以降もとくにスピードアップしないので、ページごとに個別にテキスト抽出しておいて、配列に対してテキスト検索するほうが高速処理できると思われます。

配列変数上でページごとに分けておいたテキストに対して検索を行い、見つからなかった場合には仕方なく本ルーチンのような処理でPDFに対してテキスト検索を行うといったところでしょうか。

AppleScript名:PDFでテキスト検索してキーワードの存在ページをリストで返す
– Created 2016-01-05 10:17:51 by Shane Stanley
– Modified 2017-06-17 by Takaaki Naganoya
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4690

set aPath to POSIX path of (choose file of type {“com.adobe.pdf”})
set aSearchKeyword to “数値のインクリメント/デクリメント”
set guardPage to 15 –検索対象から外すページ(冒頭からこのページまでを除外)
set pRes to searchPDFforString(aPath, aString, guardPage) of me
–>  {67, 78}

–指定のPDFの指定のキーワードを検索してキーワードが存在するページのリストを返す
on searchPDFforString(posixPath, aSearchKeyword, guardPage)
  set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath
  
set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL
  
  
set theSels to (thePDF’s findString:searchString withOptions:0)
  
set aList to {}
  
  
repeat with aSel in theSels
    set thePage to (aSel’s pages()’s objectAtIndex:0)’s label()
    
set curPage to (thePage as integer)
    
if curPage > guardPage then
      if curPage is not in aList then
        set the end of aList to curPage
      end if
    end if
  end repeat
  
  
return aList
end searchPDFforString

★Click Here to Open This Script 

2017/06/16 指定PDFの最初のページに大量のスクウェアアノテーションを添付する

指定PDFの最初のページに大量のスクウェアアノテーションを添付するAppleScriptです。

他のGUIアプリケーションを併用せずQuartz Frameworkの機能を利用して、PDFに対するアノテーションの添付を行います。

square_anno1.png

PDFのアノテーションまわりはmacOS 10.13で大幅に変更されているため、本Scriptがそのまま10.13上でも動作することは期待していません。

AppleScript名:指定PDFの最初のページに大量のスクウェアアノテーションを添付する
– Created 2017-06-16 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “AppKit”
–http://piyocast.com/as/archives/4688

set aHFSPath to (choose file of type {“com.adobe.pdf”} with prompt “Select PDF”)
set aPOSIX to POSIX path of aHFSPath
set aURL to (current application’s |NSURL|’s fileURLWithPath:aPOSIX)

set aPDFdoc to current application’s PDFDocument’s alloc()’s initWithURL:aURL
set pCount to aPDFdoc’s pageCount()
set aPage to aPDFdoc’s pageAtIndex:0

set firstPage to (aPDFdoc’s pageAtIndex:0)

–Remove Annotation
my removeAnnotationFromPage:firstPage –Call by Reference

–Get PDF size by Point
set aBounds to aPage’s boundsForBox:(current application’s kPDFDisplayBoxMediaBox)
set aSize to |size| of aBounds

–Add Annotation
repeat with xNum from 30 to ((width of aSize) - 30) by 50
  repeat with yNum from 30 to ((height of aSize) - 30) by 50
    set squAnn to (current application’s PDFAnnotationSquare’s alloc()’s initWithBounds:{origin:{x:xNum, y:yNum}, |size|:{width:40, height:40}})
    (
squAnn’s setValue:(current application’s NSColor’s blueColor()) forAnnotationKey:(current application’s kPDFAnnotationKey_Color))
    (
squAnn’s setValue:(current application’s NSColor’s clearColor()) forAnnotationKey:(current application’s kPDFAnnotationKey_InteriorColor))
    (
firstPage’s addAnnotation:squAnn)
  end repeat
end repeat

–Save It
aPDFdoc’s writeToFile:aPOSIX

–Remove All Annotation from a Page. Call by Reference
on removeAnnotationFromPage:aPage
  set anoList to (aPage’s annotations()) as list
  
repeat with i in anoList
    (aPage’s removeAnnotation:i)
  end repeat
end removeAnnotationFromPage:

★Click Here to Open This Script 

2017/06/14 Googleで検索して結果を返す v2

指定キーワードをGoogle検索して該当するWebサイトのURLをリストで返すAppleScriptです。

もともとはShane StanleyがAppleScript Users MLで発表したオリジナル版(v1)があり、これに対して、私が検索件数の拡張(100件まで)を行なったものです(3月の時点でShaneにフィードバックずみ)。

本Scriptは、AppleScriptからCocoaの機能を呼び出す処理を洗練させまくった内容であり、よくこんなもんを考えついて実装したものだと心底感心させられます。いままで見たScriptの中でもダントツに(いろんな意味で)突き抜けています。突き抜けすぎていて、掲載するまで(Googleに刺されないかどうか)かなり悩まされたほどです。

# ほかの言語でも同じような処理をしている例を見つけたので、問題は少ないものと判断

Webブラウザ経由でGoogle検索を行い、結果をAppleScriptで取得するようなやりかたは、短期的には使うことができていましたが、Google側の広告や表示スタイルの変更などによってScriptの定期的な書き換えや修正が必要になっていました。その場で試す分には使えるものの、長期的に使い続けることには疑問が生じていました。

本Scriptでは検索結果のHTMLをXMLとして評価し、Webブラウザ側に表示される各種要素には関係なく検索結果のURLのみを抽出。Webブラウザ経由のGoogle検索の手口を悪魔的に洗練させたものといえます。最大検索件数は100件なので用途は制限されますが、お手軽な検索程度であれば使えます。

本当に業務で長期的にGoogle検索をシステムやツールの一部の機能として利用するのであれば、Google Web API(REST API)経由でGoogle検索エンジンを呼び出すようにすることが望ましいでしょう。AppleScriptからMicrosoftのBing検索エンジンにREST API経由で検索実行することも可能です

AppleScript名:Googleで検索して結果を返す v2
– Created 2017-03-31 by Shane Stanley
– Modified 2017-03-31 by Takaaki Naganoya
use AppleScript version “2.4″
use framework “Foundation”
use scripting additions
–http://piyocast.com/as/archives/4687

set theQuery to “AppleScript”
set aResList to searchByGoogle(theQuery, 100) of me

on searchByGoogle(theQuery, maxNum)
  – build and escape query string
  
set theQuery to current application’s NSString’s stringWithString:theQuery
  
set theQuery to theQuery’s stringByReplacingOccurrencesOfString:space withString:“+”
  
set escQuery to theQuery’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())
  
  
– do search
  
set searchURLString to current application’s NSString’s stringWithFormat_(“https://www.google.com/search?client=safari&rls=en&ie=UTF-8&oe=UTF-8&q=%@&complete=0&num=%@&as_qdr=all”, escQuery, (maxNum as string))
  
set theURL to current application’s |NSURL|’s URLWithString:searchURLString
  
set {theData, theError} to current application’s NSData’s dataWithContentsOfURL:theURL options:0 |error|:(reference)
  
if theData = missing value then error (theError’s localizedDescription() as text)
  
  
– convert to XML
  
set {theXMLDoc, theError} to current application’s NSXMLDocument’s alloc()’s initWithData:theData options:(current application’s NSXMLDocumentTidyHTML) |error|:(reference)
  
if theXMLDoc = missing value then error (theError’s localizedDescription() as text)
  
  
– filter via XPath and predicate
  
set xpathStr to “//*[@class=\”r\”]/a/@href”
  
set {theNodes, theError} to theXMLDoc’s nodesForXPath:xpathStr |error|:(reference)
  
if theNodes = missing value then error (theError’s localizedDescription() as text)
  
set nodeStrings to (theNodes’s valueForKey:“stringValue”)
  
set thePred to current application’s NSPredicate’s predicateWithFormat:“self BEGINSWITH ’/url?q=’”
  
set nodeStrings to nodeStrings’s filteredArrayUsingPredicate:thePred
  
  
– trim URL strings
  
set theURLStrings to {}
  
repeat with aString in nodeStrings
    set theOffset to (aString’s rangeOfString:“&”)
    
set end of theURLStrings to (aString’s substringWithRange:{7, (theOffset’s location) - 7}) as text
  end repeat
  
  
return theURLStrings
end searchByGoogle

★Click Here to Open This Script 

2017/06/13 指定PDFの最初のページにアノテーションを追加する(テキストアノテーション)

指定のPDFの最初のページにテキストのアノテーションを追加するAppleScriptです。

だいたい想定していたとおりの処理はできているはずなんですが、Preview.app上で確認してみると想定していたのとは違う(クリックするとテキストが展開される)ので、まだいろいろ試してみないとダメっぽい感じです。

▼処理したPDFをPreview.appでオープンしたところ
pdf_ano1_resized.png

▼本AppleScriptで添付したアノテーションをクリックしたところ
pdf_ano2_resized.png

PDFのアノテーションまわりはmacOS 10.13で大幅に手が加わって変更されるので、このAppleScriptは単なるmacOS 10.10.x〜10.12.x上でのアノテーション追加実験ということになります。

AppleScript名:指定PDFの最初のページにアノテーションを追加する(テキストアノテーション)
– Created 2017-06-13 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “QuartzCore”
use framework “AppKit”
–http://piyocast.com/as/archives/4685

set aHFSPath to (choose file of type {“com.adobe.pdf”} with prompt “Choose a PDF”)
set aPOSIX to POSIX path of aHFSPath
set aURL to (current application’s |NSURL|’s fileURLWithPath:aPOSIX)

set aPDFdoc to current application’s PDFDocument’s alloc()’s initWithURL:aURL
set pCount to aPDFdoc’s pageCount()
set firstPage to (aPDFdoc’s pageAtIndex:0)

set textAnnotation to current application’s PDFAnnotationText’s alloc()’s initWithBounds:{origin:{x:10, y:400}, |size|:{width:200, height:100}}
textAnnotation’s setType:(current application’s PDFAnnotationTextWidget)
textAnnotation’s setValue:“/FreeText” forAnnotationKey:(current application’s kPDFAnnotationKey_Subtype)
textAnnotation’s setValue:“Hello PDF” forAnnotationKey:(current application’s kPDFAnnotationKey_Contents)
textAnnotation’s setValue:(current application’s NSColor’s yellowColor()) forAnnotationKey:(current application’s kPDFAnnotationKey_Color)

firstPage’s addAnnotation:textAnnotation

aPDFdoc’s writeToFile:aPOSIX

★Click Here to Open This Script 

2017/06/12 PDFでテキスト検索してURLリンクのアノテーションを追加する

指定のPDFで指定のテキスト(list)を検索して、URLリンク(list)のアノテーションを追加するAppleScriptです。

PDFにアノテーションを追加するAppleScriptで、他のアプリケーションを併用せずにQuartz Frameworkの機能を利用するタイプのものを探してみたら、Shane StanleyがMacScripter.netに投稿したものだけが見つかりました。一応、読みやすく清書して一部変更したのと、日本語環境で日本語を含んだPDFに対して処理検証を行なったものを掲載しています。

ただ、Objective-Cで記述したサンプルについてもほとんど見つからないので、なかなか探すのに苦労させられています。むしろ、サードパーティのフレームワーク「PSPDFkit」あたりのほうがサンプルが充実しているので、用途によってはこちらも選択肢に入ってくることでしょう。

macOS 10.13, High SierraでPDFkitに大幅に手が入るようなので、そちらの登場を待てるようであれば、10.13のPDFkitを使ってもよいでしょう。

AppleScript名:PDFでテキスト検索してURLリンクのアノテーションを追加する
– Created 2016-01-05 10:17:51 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4682

set aPath to POSIX path of (choose file of type {“com.adobe.pdf”})
set pRes to my makeLinksInPDF:aPath forStrings:{“日本語 WordNet”, “日本語WordNet”} linkURLs:{“http://compling.hss.ntu.edu.sg/wnja/”, “http://compling.hss.ntu.edu.sg/wnja/”}

–指定のPDFの指定のキーワード群に対してURL群でリンクのアノテーションを追加する
on makeLinksInPDF:posixPath forStrings:listOfSearchStrings linkURLs:listOfLinkURLStrings
  set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath
  
set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL
  
  
repeat with i from 1 to count of listOfSearchStrings
    
    
set searchString to item i of listOfSearchStrings
    
set linkURLString to item i of listOfLinkURLStrings
    
    
– get list of matches as PDFSelections
    
set theSels to (thePDF’s findString:searchString withOptions:0)
    
    
repeat with aSel in theSels
      set thePage to (aSel’s pages()’s objectAtIndex:0)
      
set theBounds to (aSel’s boundsForPage:thePage)
      
      
set theLink to (current application’s PDFAnnotationLink’s alloc()’s initWithBounds:theBounds) – make link with those bounds
      
set theAction to (current application’s PDFActionURL’s alloc()’s initWithURL:(current application’s |NSURL|’s URLWithString:linkURLString))
      
      (
theLink’s setMouseUpAction:theAction)
      
      
– set link’s appearance
      (
theLink’s setColor:(current application’s NSColor’s blueColor()))
      
set linkBorder to current application’s PDFBorder’s alloc()’s init()
      (
linkBorder’s setLineWidth:1.0)
      (
linkBorder’s setStyle:0)
      (
theLink’s setBorder:(linkBorder))
      (
theLink’s setShouldDisplay:true)
      
      
– add it to the page
      (
thePage’s addAnnotation:theLink)
    end repeat
  end repeat
  
  
– save the modified PDF
  
set oldName to theURL’s lastPathComponent()’s stringByDeletingPathExtension()
  
set newURL to (theURL’s URLByDeletingLastPathComponent()’s URLByAppendingPathComponent:(oldName’s stringByAppendingString:“-new”))’s URLByAppendingPathExtension:“pdf”
  
thePDF’s writeToURL:newURL
  
end makeLinksInPDF:forStrings:linkURLs:

★Click Here to Open This Script 

2017/06/09 指定PDFの最初のページからアノテーションを削除する

指定PDFの最初のページに添付されたアノテーション(Preview.app上ではマークアップと呼ばれる)を削除するAppleScriptです。

■実行前(Before)
pdf_annotation1_resized.png

■実行後(After)
pdf_annotation2_resized.png

とりあえず、指定PDFの指定ページ上のアノテーションを取得して削除できるようになりました。このあたり、もはやプログラミングではなく単なる調査です(汗)。

アノテーションを検出するScriptにも記載してあるとおり、Skimで添付したアノテーションは処理できません。Preview.appで添付したアノテーションを処理対象にしています。Preview.appで添付したアノテーションはSkimでもAdobe Acrobatでも表示が可能です。

AppleScript名:指定PDFの最初のページからアノテーションを削除する
– Created 2017-06-09 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4681

set aHFSPath to (choose file of type {“com.adobe.pdf”} with prompt “Choose a PDF with Annotation”)
set aPOSIX to POSIX path of aHFSPath
set aURL to (current application’s |NSURL|’s fileURLWithPath:aPOSIX)

set aPDFdoc to current application’s PDFDocument’s alloc()’s initWithURL:aURL
set pCount to aPDFdoc’s pageCount()

set firstPage to (aPDFdoc’s pageAtIndex:0)

set anoList to (firstPage’s annotations()) as list

repeat with i in anoList
  (firstPage’s removeAnnotation:i)
end repeat

aPDFdoc’s writeToFile:aPOSIX

★Click Here to Open This Script 

2017/06/08 指定PDFの最初のページからアノテーションを取得する

指定PDFの最初のページに添付されたアノテーション(Preview.app上ではマークアップと呼ばれる)を取得するAppleScriptです。

pdf_annotation1_resized.png

とりあえず、指定PDFの指定ページ上のアノテーションを取得して種類や大きさを取得できるようになりました。

日常的に利用しているPDFビューワーとしてはオープンソースのSkimがあり、むしろPreview.appよりもこちらの方を主に利用していますが、Skimで添付したアノテーションについては保存形式が異なる(外部保存?)ようで、本Scriptでは検知できませんでした。テストにはPreview.app上で編集して任意のアノテーション(マークアップ)を追加したPDFを用意する必要があります。

PDF上の指定ページ上のアノテーションを取得することはできるようになりましたが、取得することが目的ではなく、Script側からアノテーションを作成してPDFに添付することが最終目的です。アノテーションの作成についてはあまり情報が見つからず、ちょっと苦労させられています。

他のアプリケーションに依存しないでPDFの各種処理が行えることが望ましく(とくに、Adobe Acrobatが入っていない環境でも処理できることが望ましい)、アノテーションの添付はAppleScriptでCocoaの機能を利用して行うPDF処理としては「最後の難関」として残っています。ほかはひととおり他のアプリケーションなしでできています。

AppleScript名:指定PDFの最初のページからアノテーションを取得する
– Created 2017-06-08 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4679

set aHFSPath to (choose file of type {“com.adobe.pdf”} with prompt “Choose a PDF with Annotation”)
set aPOSIX to POSIX path of aHFSPath
set aURL to (current application’s |NSURL|’s fileURLWithPath:aPOSIX)

set aPDFdoc to current application’s PDFDocument’s alloc()’s initWithURL:aURL
set pCount to aPDFdoc’s pageCount()

set firstPage to (aPDFdoc’s pageAtIndex:0)
–>  (PDFPage) PDFPage, label 1

set anoList to (firstPage’s annotations()) as list
(*
{(PDFAnnotationMarkup) Type: ’Highlight’, Bounds: (81, 624) [434, 53]
, (PDFAnnotationSquare) Type: ’Square’, Bounds: (50, 419) [212, 162]
, (PDFAnnotationSquare) Type: ’Square’, Bounds: (301, 107) [244, 484]
}
*)

repeat with i in anoList
  set aBounds to i’s |bounds|()
  
  
log aBounds
  
(* {origin:{x:80.79, y:624.4106}, size:{width:433.6944, height:52.8918}} *)
  
(* {origin:{x:50.05553, y:419.1671}, size:{width:212.27807, height:162.3308}} *)
  
(* {origin:{x:300.6213, y:106.8405}, size:{width:244.0961, height:484.4566}} *)
  
end repeat

★Click Here to Open This Script 

2017/06/05 Webサービスを用いてIPアドレスから位置情報を検索

Web APIを用いて与えられたIPアドレスから対応する位置情報を検索するAppleScriptです。

IPアドレスから位置情報を提供するWeb APIは割とたくさんあって、無料で使えるものが多いものの、サービスの提供が長続きしなかったり、サービス状態が安定しなかったり(時間帯によってアクセスできなかったり)、無料がゆえに呼び出し頻度の制約が割ときつかったりします(仕事で継続的に利用する場合には各サービスの有償コースの利用をおすすめします)。

サービス名 アクセス制限 サービス運営者の所在国
ipinfo.io 1日あたり1000リクエスト 記載なし(イギリス?)
ip-api.com 1分あたり240リクエスト ルーマニア
ipinfodb.com 1秒間に2リクエスト マレーシア

それでも、サービスを利用できると助かるケースが多いため、実際に呼び出し方法について確認しておくとよいでしょう。

AppleScript名:ipinfo.ioでIPアドレスから場所を検索
– Created 2017-06-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4675

set myIP to getGeoLocationByIPinfo(“45.59.69.202″) of me
–>  {region:”Delaware”, city:”Wilmington”, country:”US”, org:”AS3800 Talent House, Inc.”, hostname:”No Hostname”, postal:”19801″, ip:”45.59.69.202″, loc:”39.7157,-75.5281″}

–http://ipinfo.io/developers
on getGeoLocationByIPinfo(myIP)
  set aURL to “http://ipinfo.io/” & myIP
  
set aRes to callRestGETAPIAndParseResults(aURL) of me
  
set aRESTres to (json of aRes)
  
set aRESTcode to responseCode of aRes
  
if aRESTcode is not equal to 200 then return false
  
return aRESTres as record
end getGeoLocationByIPinfo

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s 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 resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s 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

★Click Here to Open This Script 

2017/06/04 指定スクリプト書類の記述OSA言語を取得する

指定スクリプト書類の記述OSA(Open Scripting Architecture)言語の情報を取得するAppleScriptです。

指定のスクリプト書類がどのOSA言語で記述されているかについては、Script Editorでオープンして書類のプロパティを取得するのが手っ取り早い方法ですが、

AppleScript名:Script Editorでスクリプト書類をオープンして記述OSA言語名称を取得
set anAlias to choose file of type {“com.apple.applescript.script”, “com.apple.applescript.script-bundle”}
tell application “Script Editor”
  set aDoc to open anAlias
  
tell aDoc
    set aProp to properties
    
set aLang to name of language of aProp
  end tell
end tell

★Click Here to Open This Script 

これだと、スクリプト書類内で呼び出しているアプリケーションが自動的に起動されます。

スクリプト書類を大量に処理するような場合、アプリケーションが自動起動されたくないような用途もあります。そのために、Cocoaの機能(OSAKit)を呼び出して、スクリプト書類から直接情報を取得してみました。

これだと、InDesignのコントロールを行なっているスクリプトから情報を取得しても、InDesignが起動されることはありません。

AppleScript名:指定スクリプト書類の記述OSA言語を取得する
– Created 2017-06-04 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “OSAKit”
–http://piyocast.com/as/archives/4674

set anAlias to choose file of type {“com.apple.applescript.script”, “com.apple.applescript.script-bundle”}

set aURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of anAlias)
set theScript to current application’s OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)

set scriptName to theScript’s |language|()’s |name|() as string
set scriptDesc to theScript’s |language|()’s info() as string
set scriptVer to theScript’s |language|()’s |version|() as string

return {osaName:scriptName, osaDesc:scriptDesc, osaVer:scriptVer}
–>  {osaName:”AppleScript”, osaDesc:”AppleScript.”, osaVer:”2.5″}
–>  {osaName:”JavaScript”, osaDesc:”JavaScript”, osaVer:”1.1″}

★Click Here to Open This Script 

2017/06/03 指定フォルダ中のPure ASのファイルを別フォルダに移動

指定フォルダ中のPure AppleScriptのファイルを別フォルダに移動するAppleScriptです。

最近は(処理速度が速いことや並列実行させやすいことから)なるべくCocoaの機能を呼び出すASOC(AppleScriptObjC)の部品を使うようにしているので、Pure AppleScript(Cocoaの機能を使わないもの)のファイルを整理して別フォルダに移動させておくためのScriptを書いてみました。

任意のAppleScript書類からソースを取得して、ソース中にuse framework “Foundation”の宣言文が入っていないかどうかを確認しています。入っていればASOC、入っていなければPure ASと判定。実行専用のScriptからはソースコードは取得できないので無視していますし、実行形式のアプレットについては最初の段階で対象外にしています。

AppleScript名:指定フォルダ中のPure ASのファイルを別フォルダに移動
– Created 2017-06-03 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “OSAKit”
–http://piyocast.com/as/archives/4673

set tFol to choose folder with prompt “処理対象フォルダを選択”
set sFol to choose folder with prompt “Pure AppleScriptの移動先フォルダを選択”

tell application “Finder”
  tell folder (tFol)
    set sList to (every file whose name ends with “.scpt” or name ends with “.scptd”) as alias list
  end tell
end tell

repeat with i in sList
  set sRes to detectScriptIsPureASorASOC(i) of me
  
if sRes = false then
    tell application “Finder”
      move i to sFol
    end tell
  end if
end repeat

–指定AppleScriptファイルがPure ASかASOCかを判定して返す
on detectScriptIsPureASorASOC(aFile)
  set sText to getASsourceFor(aFile) of me
  
if sText = “” or sText = missing value then return missing value
  
if sText contains “use framework \”Foundation\”" then
    return true –ASOC (AppleScript with Cocoa Framework)
  else
    return false –Pure AppleScript
  end if
end detectScriptIsPureASorASOC

–指定AppleScriptファイルのソースコードを取得する(実行専用Scriptからは取得できない)
on getASsourceFor(anAlias as {alias, string})
  set anHFSpath to anAlias as string
  
set aURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of anHFSpath)
  
set theScript to current application’s OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
return theScript’s source() as text
end getASsourceFor

★Click Here to Open This Script 

2017/05/30 メールアドレスからMessage-IDらしきものを作成

与えられたメールアドレスから、メールヘッダに入るMessage-IDらしきものを生成するAppleScriptです。実行結果は、毎回変わります(そういう目的のために作ったので)。

高速メール送信が行えるWeb API「SendGrid」でメールの高速送信をAppleScriptから行ってみました。1通あたり0.2秒程度。さらに複数一括指定送信を行うと、AppleScriptからでも1通あたり0.007秒ぐらいで送信できたので(100通一括指定時)、たいへんに有用性が高いサービスだと感じられました。

そんなテストを繰り返す中、テスト送信先のメールアドレスがGmailのアドレスで、しかも1つのGMailアドレスに対して「+」でメールアドレス拡張を行ったときに、複数のメールが1つのメールとして見なされるという問題が起こりました。

その対処方法を探してみたところ、Twitter上で「Mail-HeaderにMessage-IDを入れるといいよ」と教えてもらいました。

Message-IDの指定について調べてみると、SendGrid呼び出し時にMessage-IDフィールドにメールアドレスをそのまま突っ込むといった乱暴なサンプルが見つかりました。とりあえず1回送るだけならこれでも問題がなさそうですが、ちゃんとユニークな値のMessage IDを入れないと、同じメールアドレスに複数回メールを送ったときに問題が発生する可能性がありそうでした。

厳密にRFC5322に準拠していなくても、それっぽくて一意に区別できれば問題ないものと考え、それっぽいものを作るAppleScriptを用意してみました。一応、MailCoreのプロジェクトの中にMessage-IDを作るメソッドがないかさがしてみたものの、単体で呼び出せるようなメソッドが見つからなかったので、まーこんなもんでしょう。

AppleScript名:メールアドレスからMessage-IDらしきものを作成
– Created 2017-05-30 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4672

set anAddress to “piyomarusoft+0001@gmail.com”
set anID to getMessageIDFromMailAddress(anAddress) of me
–>  ”<D6A128D3-2D53-4163-B2F7-53A25FB9608C@gmail.com>”

–とりあえずMessage IDらしきものを組み立ててみた
on getMessageIDFromMailAddress(anAddress as string)
  set anOffset to (offset of “@” in anAddress)
  
if anOffset = 0 then return false –Error
  
set aDomain to text anOffset thru -1 of anAddress
  
set aStr to (current application’s NSUUID’s UUID()’s UUIDString()) as string
  
return (“< " & aStr & aDomain & “>”)
end getMessageIDFromMailAddress

–offset命令の実行を横取りする
on offset of searchStr in str
  set aRes to getOffset(str, searchStr) of me
  
return aRes
end offset

on getOffset(str, searchStr)
  set d to divideBy(str, searchStr)
  
if (count d) is less than 2 then return 0
  
return (length of item 1 of d) + 1
end getOffset

on divideBy(str, separator)
  set delSave to AppleScript’s text item delimiters
  
set the AppleScript’s text item delimiters to separator
  
set strItems to every text item of str
  
set the AppleScript’s text item delimiters to delSave
  
return strItems
end divideBy

★Click Here to Open This Script 

2017/05/27 Wikipediaで検索を行ってキーワードのカテゴリを取得する v1

与えられたキーワードをWikipediaで検索して、キーワードのカテゴリ名を取得するAppleScriptです。

何かのキーワードのカテゴリを取得するのに、いろいろプログラムやシソーラス辞書を検索することも試してみましたが、もっと乱暴かつ粗暴で即物的で低レベルな解決方法を見つけたので試してみました。

wiki0_resized.png

WikipediaをREST API経由で検索して、本文を取得し、文末にあるカテゴリ情報を取得すればいい感じのカテゴリ情報になるんでは? と思いつき、試してみたところ、、、うまく行ってしまいました(汗)

wiki1_resized.png

まだ、キーワードのフォワーディング(Mac OS X→macOS)、同音異義語や類義語への分岐(カール→複数の同音異義語への分岐)には対応していませんが、対応するのも(パターンがわかれば)それほど難しくなさそうです。

→ 実際にやってみたら割と簡単に処理できてしまいました(汗) 

AppleScript名:Wikipediaで検索を行ってキーワードのカテゴリを取得する v1
– Created 2017-05-27 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–https://www.mediawiki.org/wiki/API:Main_page/ja
–http://piyocast.com/as/archives/4666

set aRes1 to getCategoryFromKeyword(“カール (スナック菓子)”) of me
–>  {”スナック菓子の商品名”, “明治 (企業)”, “登録商標”}

on getCategoryFromKeyword(aText)
  set wikiStr to getBodyFromWikipedia(aText) of me
  
set aList to categoryTagListFromWikipedia(wikiStr, “[[Category:”) of me
  
set bList to cleanupArray(aList, “[[Category:”, “]]”) of me
  
return bList
end getCategoryFromKeyword

on categoryTagListFromWikipedia(sText, pickUpKey)
  set aString to current application’s NSString’s stringWithString:sText
  
set anArray to aString’s componentsSeparatedByString:(string id 10)
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat_(“SELF BEGINSWITH %@”, pickUpKey)
  
return (anArray’s filteredArrayUsingPredicate:aPredicate) as list
end categoryTagListFromWikipedia

–Wikipediaで指定キーワードの検索を行う(同義語、類義語などへの分岐に未対応)
on getBodyFromWikipedia(aText)
  set reqURLStr to “https://jp.wikipedia.org/w/api.php” –Japanese Version
  
  
set aRec to {action:“query”, titles:aText, |prop|:“revisions”, rvprop:“content”, |format|:“json”}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
set aRes to callRestGETAPIAndParseResults(aURL) of me
  
  
set aRESTres to (pages of query of json of aRes)
  
  
set allKeys to (aRESTres’s allKeys()) as list
  
repeat with i in allKeys
    set j to contents of i
    
set aKeyPath to j & “.” & “revisions.*”
    
set aContent to (aRESTres’s valueForKeyPath:aKeyPath)
    
return aContent as string
  end repeat
end getBodyFromWikipedia

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s 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 resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s 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 current application’s 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 (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s 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 urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

on cleanupArray(aList, fromStr, toStr)
  set newList to {}
  
  
repeat with i in aList
    set b1 to repChar(i, fromStr, “”) of me
    
set b2 to repChar(b1, toStr, “”) of me
    
    
set b3 to offset of “|” in b2
    
if b3 is not equal to 0 then
      set b2 to text 1 thru (b3 - 1) of b2
    end if
    
set the end of newList to b2
  end repeat
  
  
return newList
end cleanupArray

–Pure AppleScript Version
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

★Click Here to Open This Script 

2017/05/27 書式つきテキストを組み立てて、クリップボードに設定(影をつける)

書式つきテキスト(NSAttributedString)を組み立てて、クリップボードに設定するAppleScriptの改良版です。影(NSShadow)の追加指定を行ってみました。

stylet2.png

AppleScript名:書式つきテキストを組み立てて、クリップボードに設定(影をつける)
– Created 2017-05-26 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
–http://piyocast.com/as/archives/4664

set anAttrStr to makeRTFfromParameters("ぴよまるソフトウェア", 2.0, 36) of me

set attrList to {anAttrStr}
restoreClipboard(attrList) of me –set the clipboard to rtf_data

–書式つきテキストを組み立てる
on makeRTFfromParameters(aStr as string, outlineNum as real, aFontSize as real)
  –フォント
  
set aVal1 to current application’s NSFont’s fontWithName:"HiraKakuStdN-W8" |size|:aFontSize
  
set aKey1 to (current application’s NSFontAttributeName)
  
  
–色
  
set aVal2 to current application’s NSColor’s blackColor()
  
set aKey2 to (current application’s NSForegroundColorAttributeName)
  
  
–カーニング
  
set aVal3 to -2.0
  
set akey3 to (current application’s NSKernAttributeName)
  
  
–アンダーライン
  
set aVal4 to 0
  
set akey4 to (current application’s NSUnderlineStyleAttributeName)
  
  
–リガチャ
  
set aVal5 to 2 –全てのリガチャを有効にする
  
set akey5 to (current application’s NSLigatureAttributeName)
  
  
–枠線(アウトライン)
  
set aVal6 to outlineNum
  
set akey6 to (current application’s NSStrokeWidthAttributeName)
  
  
–Shadow
  
set aVal7 to current application’s NSShadow’s alloc()’s init()
  
aVal7’s setShadowOffset:(current application’s CGSizeMake(1.0, 1.0)) –影のサイズ
  
aVal7’s setShadowColor:(current application’s NSColor’s blackColor()) –影の色
  
aVal7’s setShadowBlurRadius:2.0 –ぼかしの半径
  
set akey7 to (current application’s NSShadowAttributeName)
  
  
set keyList to {aKey1, aKey2, akey3, akey4, akey5, akey6, akey7}
  
set valList to {aVal1, aVal2, aVal3, aVal4, aVal5, aVal6, aVal7}
  
set attrsDictionary to current application’s NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
  
  
set attrStr to current application’s NSMutableAttributedString’s alloc()’s initWithString:aStr attributes:attrsDictionary
  
return attrStr
  
end makeRTFfromParameters

–From Shane Stanley’s Book "Everyday AppleScriptObjC"
on restoreClipboard(theArray as list)
  set thePasteboard to current application’s NSPasteboard’s generalPasteboard()
  
thePasteboard’s clearContents()
  
thePasteboard’s writeObjects:theArray
end restoreClipboard

★Click Here to Open This Script 

2017/05/26 書式つきテキストを組み立てて、クリップボードに設定

書式つきテキスト(NSAttributedString)を組み立てて、クリップボードに設定するAppleScriptです。

作成した書式つきテキストは、そのままKeynoteなどのアプリケーションにペーストして利用することが可能です。グラフィックではないため、アプリケーション上での再編集や影の指定、色の変更などが可能です。

styles.png

Keynoteでアウトライン文字を使いたいことはままあるので、このように手軽にクリップボードに転送して利用できると実用性が高いことでしょう。

後日談:という紹介をしたら、KeynoteのヘビーユーザーからKeynoteのGUI上からアウトライン文字の書式を指定できることを教えてもらいました。

AppleScript名:書式つきテキストを組み立てて、クリップボードに設定
– Created 2017-05-26 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
–http://piyocast.com/as/archives/4662

set anAssrStr to makeRTFfromParameters(“ぴよまるソフトウェア”, 3.0, 72) of me

set attrList to {anAssrStr}
restoreClipboard(attrList) of me –set the clipboard to rtf_data

–書式つきテキストを組み立てる
on makeRTFfromParameters(aStr as string, outlineNum as real, aFontSize as real)
  –フォント
  
set aVal1 to current application’s NSFont’s fontWithName:“HiraKakuStdN-W8″ |size|:aFontSize
  
set aKey1 to (current application’s NSFontAttributeName)
  
  
–色
  
set aVal2 to current application’s NSColor’s blueColor()
  
set aKey2 to (current application’s NSForegroundColorAttributeName)
  
  
–カーニング
  
set aVal3 to -2.0
  
set akey3 to (current application’s NSKernAttributeName)
  
  
–アンダーライン
  
set aVal4 to 0
  
set akey4 to (current application’s NSUnderlineStyleAttributeName)
  
  
–リガチャ
  
set aVal5 to 2 –全てのリガチャを有効にする
  
set akey5 to (current application’s NSLigatureAttributeName)
  
  
–枠線(アウトライン)
  
set aVal6 to outlineNum
  
set akey6 to (current application’s NSStrokeWidthAttributeName)
  
  
set keyList to {aKey1, aKey2, akey3, akey4, akey5, akey6}
  
set valList to {aVal1, aVal2, aVal3, aVal4, aVal5, aVal6}
  
set attrsDictionary to current application’s NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
  
  
set attrStr to current application’s NSMutableAttributedString’s alloc()’s initWithString:aStr attributes:attrsDictionary
  
return attrStr
  
end makeRTFfromParameters

–From Shane Stanley’s Book “Everyday AppleScriptObjC”
on restoreClipboard(theArray as list)
  set thePasteboard to current application’s NSPasteboard’s generalPasteboard()
  
thePasteboard’s clearContents()
  
thePasteboard’s writeObjects:theArray
end restoreClipboard

★Click Here to Open This Script 

2017/05/25 AppleScript+Web APIで行う自然言語処理

ライター/編集者仲間である友人と雑談していたところ、自然言語処理がいろいろ使えそうなシーンが見えてきました。彼によると、Twitter上で過去記事の紹介ツイートを行いたいが、何も関係ないところに唐突に記事紹介のツイートを投げても不自然だし、興味を持たれにくいので、時事ネタと関連する記事を紹介する仕組みを作れないだろうか、という話になりました。

そこで、比較的鮮度および注目度が高いと思われる「ニュース記事」から固有名詞だけを抽出し、その固有名詞にどのぐらい世間的な注目が集まっているかを判定できると、そのキーワードに関連する過去記事をツイートしやすくなるかもしれないと考えました。

apitoreのREST APIには、ニュースフィードを提供するもの、形態素解析を行うもの、Twitter検索を行うものなどがあり、これらを組み合わせるとできそうな感じがしてきました。

→ Playing with rest api

実際に試してみたところ、ニュースフィードからニュース記事本文を抽出するのは(RSS Feedに本文の冒頭部分が含まれていないケースもあるので、結局記事のサイトを見に行って本文を抽出する必要がある)けっこう大変で、タイトル(題名)のみ処理することに。

次に、タイトルの文章を形態素解析して、「固有名詞」だけを抽出してみました。これは別に難しくもなんともありません。さらに、入り組んだrecordから目的のデータを取り出すのは、AppleScriptでもCocoaの機能を使えば造作もありません。NSDictionaryからvalueForKeyPath:でオブジェクトパスを記述して抽出すれば、データ取り出しのために長々とループ処理で記述する必要はありません。

次の段階は、その時点における「注目度」の計算です。仮にTwitter全体を1つの「世間」とみなし、Twitter上で拡散されていたりお気に入りに入れられる回数の高い単語は、比較的「注目度」が高いものだろうという仮説を立てました。

→ キーワードの言語ごとのTwitter発言内容集計

そこで、ニュースのタイトルから抽出した固有名詞をTwitterで検索し、それぞれの固有名詞がTweet上でどの程度リツイートされたか、お気に入りに入れられたかを計算してみました。これについては、コストの問題からREST APIではなくローカルのmacOS上で動作するAppleScript用Twitterクライアント「TwitterScripter」を呼び出すことにしました。apitore上の各種REST APIは無料で試用できますが、呼び出し回数が増えれば料金がかかるため、その部分を節約することが目的です。TwitterScripterを使用することによるデメリットは、それ自体が並列処理に対応していないこと。Mac上で(AppleScriptによる)並列処理を行ってTwitter検索を行う場合には、直接Twitterの(割と整理されていない)APIを直接呼び出すか、apitore上のREST APIを呼び出すしかなさそうです。

AS.Parallel

指定のキーワード(固有名詞)を含むツイートをTwitter上で検索し、それぞれがどの程度リツイートされたか、お気に入りに入れられたかを実際に数値化。その数値をもとにキーワードのランキングを計算することができました。

一応、「活性度の高い」≒「注目度の高い」キーワードを計算できたわけです。ここまでのプログラムはすでに実稼働状態にあり、「こんな(へんな)単語が注目されてるのかー!」という未知の単語のピックアップに成功しています。

ただし、これでは目的を50%しか達成できていません。

この「注目度の高いキーワード」と「過去記事」の間をブリッジする必要があるからです。もう少しわかりやすくいえば、「カール」という本日注目度急上昇中のキーワードがありますが、この「カール」という固有名詞で過去記事を検索したところで、まったく異なる単語の一部がたまたま偶然ひっかかってヒットする程度で、過去記事が超絶的にヒットしにくいことが予想されます(グスタフ・カールとかザンスカール帝国とかカール自走臼砲とかパリダカールラリーとか)。

この「カール」を「スナック菓子」という上位概念に変換し、さらにスナック菓子に所属する単語を取得して、それらの単語で検索できるとよいでしょう(菓子、和菓子など)。このあたりは個人的に「スター・クエリー」と昔から呼んでいるもので、与えられたキーワードから類似・関連するキーワードを複数生成して検索することで、ヒットする確率を高める仕組みです。GoogleやYouTubeでもおそらく類似の機構が検索エンジンに実装されており、入力した単語以外でもヒットするようになっているようです(とくにYouTube)。

apitoreでも日本語Word.netのデータを利用して類義語や上位概念の言葉を計算できるようになっていますが、日本語の基本的な語句に特化しており、実際に試してみたところ「カール」「ガンダム」といった商品名などから類義語や上位概念を求める用途に向いていないことがわかりました。これらの計算を行うためには、Wikipediaのデータからカテゴリを取得できれば、やりやすくなるものと思われます。

2017/05/24 restcountriesですべての国の情報を取得する

REST API経由で世界の国情報を配信しているrestcountries.euのサービスを呼び出して、すべての国情報を取得するAppleScriptです。

restcountriesのREST APIサービスについては、ひととおりすべての機能をAppleScriptから呼び出せることを確認しています。

国情報についてはそれほど変更があるわけでもないので(人口などの統計は年単位でしかアップデートされないでしょうし、首都などもコロコロ変わるわけではなく)、いっそOS側にビルトインで最初から用意されていてもいい気がします。

アプリケーションの各国語ローカライズを行う場合などに国情報は参考にするので、意外と国情報にREST API経由でアクセスできるのは助かります。

→ 調査してみたところ、オープンソースの「countries」というプロジェクトでデータが公開されているのを見つけました。JSON形式のデータも入っているので、このあたりをローカルで小突き回して加工するのがよさそうです。

AppleScript名:ALL(すべての国の情報を取得する)
– Created 2017-05-15 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4660

set reqURLStr to “https://restcountries.eu/rest/v2/all”

set aRes to callRestGETAPIAndParseResults(reqURLStr) of me

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

set aRESTres to (json of aRes)

return aRESTres
–> {{alpha2Code:”AF”, alpha3Code:”AFG”, nativeName:”افغانستان“, region:”Asia”, borders:{”IRN”, “PAK”, “TKM”, “UZB”, “TJK”, “CHN”}, numericCode:”004″, currencies:{{name:”Afghan afghani”, symbol:”؋“, code:”AFN”}}, translations:{fr:”Afghanistan”, pt:”Afeganistão”, de:”Afghanistan”, it:”Afghanistan”, es:”Afganistán”, br:”Afeganistão”, ja:”アフガニスタン”}, flag:”https://restcountries.eu/data/afg.svg”, name:”Afghanistan”, callingCodes:{”93″}, timezones:{”UTC+04:30″}, subregion:”Southern Asia”, altSpellings:{”AF”, “Afġānistān”}, topLevelDomain:{”.af”}, population:27657145, area:652230.0, regionalBlocs:{{otherNames:{}, otherAcronyms:{}, acronym:”SAARC”, name:”South Asian Association for Regional Cooperation”}}, latlng:{33.0, 65.0}, capital:”Kabul”, gini:27.8, demonym:”Afghan”, languages:{{nativeName:”پښتو“, iso639_2:”pus”, name:”Pashto”, iso639_1:”ps”}…

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s 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 resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s 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

★Click Here to Open This Script 

2017/05/21 与えられた数が素数かどうかチェック v2

与えられた数が素数かどうか(素数テーブルを使わずに)チェックするAppleScriptの改良版です。

C言語などの他の言語での実装を確認していたら、「あれ、ループ範囲がチェック値の半分になってるぞ」と気づき、理由に思い当たって修正したものです。

よくよく考えてみたら、素数というのは「1とそれ以外で割ることのできない数」なわけですが、その範囲で最小の素数が2なので、素数チェックの範囲は「2から(その数-1)」ではなく、「2から(その数÷2)」の間でチェックすればよいことに。当初行っていたループ処理の半分の時間で素数チェックが行えます。

AppleScript名:与えられた数が素数かどうかチェック v2
– Created 2017-05-21 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
–http://piyocast.com/as/archives/4659

set pRes to checkPrimeNumber(9973) of me
–> true

set pRes to checkPrimeNumber(24) of me
–> false

set pRes to checkPrimeNumber(1021) of me
–> true

set pRes to checkPrimeNumber(311) of me
–> true

–素数チェック
on checkPrimeNumber(aNum as integer)
  if aNum < 1 then error “Number is smaller than 1.”
  
repeat with i from 2 to (aNum div 2)
    if aNum mod i is equal to 0 then
      return false
    end if
  end repeat
  
return true
end checkPrimeNumber

★Click Here to Open This Script 

2017/05/20 与えられた数が素数かどうかチェック(PrimeNumberHelper)

オープンソースのprime-number-objc(By NazarYavornytskyy)中のPrimeNumberHelperをFramework化した「primeNumKit」を呼び出して指定の数が素数かどうかをチェックするAppleScriptです。

また、「primeNumKit」を利用した素因数分解のScriptも掲載しておきます。

OS X 10.10以降用にビルドしたフレームワークのバイナリを用意しておきました。興味のある方は自己責任で~/Library/Frameworksフォルダに入れてお試しください。

–> Download Framework Binary

素数のチェックで対象の数が大きく、かつ素数である場合には処理に時間がかかってしまいます。一方で、チェック対象の数がそれほど大きくない場合には、AppleScriptだけでループ処理した方がObjective-Cのプログラムを呼び出すよりも高速なケースが多々あります。

そこで、場合分けしてAppleScriptとObjective-Cのプログラムを選択的に呼び出すようにすると演算性能を維持できるようです。応用範囲が広いため、素数のチェックは割と重要です。

AppleScript名:与えられた数が素数かどうかチェック(PrimeNumberHelper)
– Created 2017-05-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “primeNumKit”
–https://github.com/NazarYavornytskyy/prime-number-objc
–http://piyocast.com/as/archives/4656

set aPrime to current application’s PrimeNumberHelper’s alloc()’s init()
set a to 75777773
set aRes to (aPrime’s isPrime:a) as boolean

★Click Here to Open This Script 

AppleScript名:簡単な素因数分解v4
– Created 2017-05-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “primeNumKit”
–https://github.com/NazarYavornytskyy/prime-number-objc
–http://piyocast.com/as/archives/4656

set aRes to getPrimeFactor(56) of me
–> {2, 3, 3}

set aRes to getPrimeFactor(4999999) of me
–> {2, 127}

set aRes to getPrimeFactor(9999991) of me
–> {1021} –素数

–与えられた数を素因数分解する
on getPrimeFactor(aTargNum)
  copy aTargNum to a
  
set pFactList to {}
  
  
repeat
    set pRes to checkPrimeNumber(a) of me
    
if pRes = true then
      set the end of pFactList to a
      
return pFactList
    end if
    
    
set aFactor to checkFactor(a) of me
    
set the end of pFactList to aFactor
    
set a to a div aFactor
  end repeat
end getPrimeFactor

–素数チェック
on checkPrimeNumber(aNum)
  if aNum < 10000 then –0.25秒以上かかりそうな処理はCocoaで処理(実測値ベース)
    return checkPrimeNumberSub1(aNum) of me
  else
    set aPrime to current application’s PrimeNumberHelper’s alloc()’s init()
    
return (aPrime’s isPrime:aNum) as boolean
  end if
end checkPrimeNumber

–小さい数の場合の素数検出
on checkPrimeNumberSub1(aNum)
  repeat with i from 2 to aNum - 1
    if aNum mod i is equal to 0 then
      return false
    end if
  end repeat
  
return true
end checkPrimeNumberSub1

–素因数チェック
on checkFactor(aNum)
  repeat with i from 2 to aNum - 1
    if aNum mod i is equal to 0 then
      return i
    end if
  end repeat
end checkFactor

★Click Here to Open This Script 

2017/05/20 最小公倍数を求める

2つの数の最小公倍数を求めるAppleScriptです。

最大公約数や素数チェックや素因数分解を作ったので、ついでにこの手の計算を行ってみました。

AppleScript名:最小公倍数を求める
– Created 2017-05-20 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4654

set a1Num to 75
set b1Num to 315
set cRes to getLCMbetweenTwoNums(a1Num, b1Num) of me
–> 1575

–2つの数の最小公倍数を求める
on getLCMbetweenTwoNums(a1Num, b1Num)
  set aGCD to getGCDbetweenTwoNums(a1Num, b1Num) of me
  
set a2Num to a1Num div aGCD
  
set b2Num to b1Num div aGCD
  
return (aGCD * a2Num * b2Num)
end getLCMbetweenTwoNums

–2つの数の最大公約数を求める
on getGCDbetweenTwoNums(aNum, bNum)
  set aRes to getPrimeFactor(aNum) of me
  
set bRes to getPrimeFactor(bNum) of me
  
  
–2つのリストを集合として扱い、積集合を求める
  
set aSet to current application’s NSMutableSet’s setWithArray:aRes
  
set bSet to current application’s NSMutableSet’s setWithArray:bRes
  
aSet’s intersectSet:bSet
  
set cRes to aSet’s allObjects() as list
  
  
set dRes to multipleListElements(cRes) of me
  
return dRes
end getGCDbetweenTwoNums

–与えられた数を素因数分解する
on getPrimeFactor(aTargNum)
  copy aTargNum to a
  
set pFactList to {}
  
  
repeat
    set pRes to checkPrimeNumber(a) of me
    
if pRes = true then
      set the end of pFactList to a
      
return pFactList
    end if
    
    
set aFactor to checkFactor(a) of me
    
set the end of pFactList to aFactor
    
set a to a div aFactor
  end repeat
end getPrimeFactor

–素数チェック
on checkPrimeNumber(aNum)
  repeat with i from 2 to aNum - 1
    if aNum mod i is equal to 0 then
      return false
    end if
  end repeat
  
return true
end checkPrimeNumber

–素因数チェック
on checkFactor(aNum)
  repeat with i from 2 to aNum - 1
    if aNum mod i is equal to 0 then
      return i
    end if
  end repeat
end checkFactor

–リスト内の要素をすべて乗算する
on multipleListElements(aList)
  set aNum to 1
  
set aRes to 1
  
repeat with i in aList
    set aRes to aRes * (aNum * i)
  end repeat
  
return aRes
end multipleListElements

★Click Here to Open This Script 

2017/05/20 最大公約数を求めるv2

2つの数の最大公約数を求めるAppleScriptです。

素数チェックや素因数分解を作ったので、この手の計算を行ってみました。

AppleScript名:最大公約数を求めるv2
– Created 2017-05-20 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4653

set aRes to getGCDbetweenTwoNums(12, 18) of me
–> 6

–2つの数の最大公約数を求める
on getGCDbetweenTwoNums(aNum, bNum)
  set aRes to getPrimeFactor(aNum) of me
  
set bRes to getPrimeFactor(bNum) of me
  
  
–2つのリストを集合として扱い、積集合を求める
  
set aSet to current application’s NSMutableSet’s setWithArray:aRes
  
set bSet to current application’s NSMutableSet’s setWithArray:bRes
  
aSet’s intersectSet:bSet
  
set cRes to aSet’s allObjects() as list
  
  
set dRes to multipleListElements(cRes) of me
  
return dRes
end getGCDbetweenTwoNums

–与えられた数を素因数分解する
on getPrimeFactor(aTargNum)
  copy aTargNum to a
  
set pFactList to {}
  
  
repeat
    set pRes to checkPrimeNumber(a) of me
    
if pRes = true then
      set the end of pFactList to a
      
return pFactList
    end if
    
    
set aFactor to checkFactor(a) of me
    
set the end of pFactList to aFactor
    
set a to a div aFactor
  end repeat
end getPrimeFactor

–素数チェック
on checkPrimeNumber(aNum)
  repeat with i from 2 to aNum - 1
    if aNum mod i is equal to 0 then
      return false
    end if
  end repeat
  
return true
end checkPrimeNumber

–素因数チェック
on checkFactor(aNum)
  repeat with i from 2 to aNum - 1
    if aNum mod i is equal to 0 then
      return i
    end if
  end repeat
end checkFactor

–リスト内の要素をすべて乗算する
on multipleListElements(aList)
  set aNum to 1
  
set aRes to 1
  
repeat with i in aList
    set aRes to aRes * (aNum * i)
  end repeat
  
return aRes
end multipleListElements

★Click Here to Open This Script 

2017/05/18 16進数文字列を10進数数値に変換するv2

16進数文字列をCocoaの機能を利用して10進数数値に変換するAppleScriptです。

以前、Pure AppleScriptで組んだものがありましたが、ためしにCocoaの機能を利用して実行速度を比較してみました。

 Pure AppleScript版:0.03秒ぐらい
 本AppleScript:0.02秒ぐらい

Cocoaの機能を呼び出すAppleScriptObjCのScriptは、Pure AppleScriptにくらべて1回目の実行がやや遅くなるものの、同じ処理を複数回呼び出すと2回目以降の速度が大幅に上がる傾向があります。繰り返し実行する場合にはAppleScriptObjC版のほうがおすすめです。

AppleScript名:16進数文字列を10進数数値に変換するv2
– Created 2017-05-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4645

set aHex to “0×9AC”
set hNum to retIntFromHexString(aHex) of me

on retIntFromHexString(aHex as string)
  set {aRes, hexRes} to (current application’s NSScanner’s scannerWithString:aHex)’s scanHexInt:(reference)
  
if aRes = false then
    return “” –エラーの場合
  else
    return hexRes
  end if
end retIntFromHexString

★Click Here to Open This Script 

2017/05/18 簡単な素因数分解v3

簡単な素因数分解を行うAppleScriptです。

これまで、素数のチェックを行う手間を省いて素数リストをデータに持って素因数分解を行ったりはしていましたが、素数のチェック自体はそれほど難しくないことに気づきまして(汗)

  「素数=1とそれ自体以外で割り切れない数」

ということで、普通に2から対象の数-1までループして、途中で割り切れたら素数ではない、というだけでチェックが可能でした。

素数のチェックさえ計算できてしまえば、応用で素因数分解も簡単なので、すぐに素因数分解までできました。

本格的に使うのであれば、素数計算の結果を「計算キャッシュ」としてファイルにキャッシュしておき、同じ数の素数判定演算を2回目以降は行わないようにするとよさそうです。ループで計算を行うコスト(時間)と、計算キャッシュの内容を取り出すコスト(時間)を実際に計測して釣り合いが取れるかどうか確認する必要はあるでしょう。

ループして割り切れないかどうかチェックしているだけなので、チェック対象の数値が大きくなると純粋に処理時間が伸びてしまいます。75777773の素数チェックを行ってみたら、本Scriptでは35秒。Objective-Cの素数チェックルーチンをFramework化して呼び出してみたら0.23秒でした。キャッシュするよりも、Objective-CのFrameworkを呼び出してみたほうが速度的にメリットが大きいかもしれません。

ただ、チェック対象の数が小さいと、Framework呼び出しの方が遅くなる傾向がありました。複数の手段をミックスして、チェック対象の数の大きさで場合分けするのがいいのかも。

AppleScript名:与えられた数が素数かどうかチェック
– Created 2017-05-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
–http://piyocast.com/as/archives/4644

set pRes to checkPrimeNumber(24) of me
–> false

set pRes to checkPrimeNumber(1021) of me
–> true

set pRes to checkPrimeNumber(311) of me
–> true

–素数チェック
on checkPrimeNumber(aNum)
  repeat with i from 2 to aNum - 1
    if aNum mod i is equal to 0 then
      return false
    end if
  end repeat
  
return true
end checkPrimeNumber

★Click Here to Open This Script 

AppleScript名:簡単な素因数分解v3
– Created 2017-05-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
–http://piyocast.com/as/archives/4644

set aRes to getPrimeFactor(18) of me
–> {2, 3, 3}

set aRes to getPrimeFactor(254) of me
–> {2, 127}

set aRes to getPrimeFactor(1021) of me
–> {1021} –素数

–与えられた数を素因数分解する
on getPrimeFactor(aTargNum)
  copy aTargNum to a
  
set pFactList to {}
  
  
repeat
    set pRes to checkPrimeNumber(a) of me
    
if pRes = true then
      set the end of pFactList to a
      
return pFactList
    end if
    
    
set aFactor to checkFactor(a) of me
    
set the end of pFactList to aFactor
    
set a to a div aFactor
  end repeat
end getPrimeFactor

–素数チェック
on checkPrimeNumber(aNum)
  repeat with i from 2 to aNum - 1
    if aNum mod i is equal to 0 then
      return false
    end if
  end repeat
  
return true
end checkPrimeNumber

–素因数チェック
on checkFactor(aNum)
  repeat with i from 2 to aNum - 1
    if aNum mod i is equal to 0 then
      return i
    end if
  end repeat
end checkFactor

★Click Here to Open This Script 

2017/05/16 MatRによる行列データの取り扱い

MatR(By David Cox)をFramework化した「DCMatrix.framework」を呼び出して行列データのハンドリングを行うAppleScriptです。

行列データの作成、入力、演算、出力などをひととおり試してみたものです(野球でいえば、素振りのレベル。でも、これをやっておかないと高度なScriptが組めない、、、)。

OS X 10.10以降用にビルドしたフレームワークのバイナリを用意しておきました。興味のある方は自己責任で~/Library/Frameworksフォルダに入れてお試しください。

–> Download Framework Binary

AppleScriptで行列を扱うのに、仏Satimage Softwareが提供しているOSAX「Numerics OSAX」を用いるのが一般的です。

ただ、数値変数の表現レンジ(指数表示を使わずに表現できる幅)が1E10ぐらいのAppleScriptの数値演算で、行列が扱えても実用上どうなんだろうと疑問に思っておりました。Numerics OSAX内で高精度の数値型のデータが使えるようではあるものの、外部とやりとりする場合には当然のごとく精度が落ちてしまいます。

# Satimage SoftwareのNumerics OSAXは、高速フーリエ変換とか画像処理とか、3次元配列の計算など、私には使い切れないほど高度な演算を提供してくれるOSAXなので、ぜひ知っておいていただきたいものです

ときに、そんなAppleScriptの数値ハンドリング機能でも、機械学習などの分野においては数値の表現レンジが大きくなくてよいので、割とよさそうです。

そうした利用分野では、CSVやタブ区切りテキストファイルから行列データを取得するケースが多いので、ファイルや配列から行列データを作成する手段を探していました。機械学習、とまで気合を入れなくても線形回帰分析(Linear Regression)を行うための準備として、このMatRを試してみたものです。

線形回帰分析の原理は、KeynoteやNumbersのグラフ「分散図」で実感することができます。「月ごとの平均気温とビール消費量の関係」「広告宣伝費と来店者数」など、グラフ化してみるととてもよく相関が見てとれます。

sample_graph.png

AppleScript名:MatRのじっけん v1
– Created 2017-05-15 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “DCMatrix”
–https://github.com/davidcox95/MatR
–http://piyocast.com/as/archives/4640

set aMatrix to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:5) andRows:3 byColumns:4
set aList to (aMatrix’s |print|())
(*
5 5 5 5
5 5 5 5
5 5 5 5
*)

set bMatrix to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:3) andRows:4 byColumns:3
set bScalar to current application’s NSNumber’s numberWithDouble:2
set bRes to bMatrix’s addScalar:bScalar
bRes’s |print|()
(*
5 5 5
5 5 5
5 5 5
5 5 5
*)

set cScalar to current application’s NSNumber’s numberWithDouble:2
set cRes to bMatrix’s subtractScalar:cScalar
cRes’s |print|()
(*
1 1 1
1 1 1
1 1 1
1 1 1
*)

set dScalar to current application’s NSNumber’s numberWithDouble:2
set eRes to bMatrix’s multiplyScalar:dScalar
eRes’s |print|()
(*
6 6 6
6 6 6
6 6 6
6 6 6
*)

set fScalar to current application’s NSNumber’s numberWithDouble:2
set fRes to bMatrix’s divideScalar:fScalar
fRes’s |print|()
(*
1.5 1.5 1.5
1.5 1.5 1.5
1.5 1.5 1.5
1.5 1.5 1.5
*)

set m4 to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:4) andRows:3 byColumns:3
set m2 to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:2) andRows:3 byColumns:3
set gRes to m4’s addMatrix:m2
gRes’s |print|()
(*
6 6 6
6 6 6
6 6 6
*)

set hRes to m4’s subtractMatrix:m2
hRes’s |print|()
(*
2 2 2
2 2 2
2 2 2
*)

set iRes to m4’s multiplyMatrix:m2
iRes’s |print|()
(*
24 24 24
24 24 24
24 24 24
*)

★Click Here to Open This Script 

AppleScript名:MatRのじっけん v2
– Created 2017-05-15 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “DCMatrix”
–https://github.com/davidcox95/MatR
–http://piyocast.com/as/archives/4640

set aMatrix to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:5) andRows:3 byColumns:4
set aList to doubleListFromMatrix(aMatrix) of me
–>  {{5.0, 5.0, 5.0, 5.0}, {5.0, 5.0, 5.0, 5.0}, {5.0, 5.0, 5.0, 5.0}}

set bList to intListFromMatrix(aMatrix) of me
–>  {{5, 5, 5, 5}, {5, 5, 5, 5}, {5, 5, 5, 5}}

set cList to strListFromMatrix(aMatrix) of me
–>  {{”5″, “5″, “5″, “5″}, {”5″, “5″, “5″, “5″}, {”5″, “5″, “5″, “5″}}

set bMatrix to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:3) andRows:4 byColumns:3
set bScalar to current application’s NSNumber’s numberWithDouble:2
set bRes to bMatrix’s addScalar:bScalar
set bbRes to intListFromMatrix(bRes) of me
–>  {{5, 5, 5}, {5, 5, 5}, {5, 5, 5}, {5, 5, 5}}

set cScalar to current application’s NSNumber’s numberWithDouble:2
set cRes to bMatrix’s subtractScalar:cScalar
set ccRes to intListFromMatrix(cRes) of me
–>  {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}}

set dScalar to current application’s NSNumber’s numberWithDouble:2
set eRes to bMatrix’s multiplyScalar:dScalar
set eeRes to intListFromMatrix(eRes) of me
–>  {{6, 6, 6}, {6, 6, 6}, {6, 6, 6}, {6, 6, 6}}

set fScalar to current application’s NSNumber’s numberWithDouble:2
set fRes to bMatrix’s divideScalar:fScalar
set ffRes to doubleListFromMatrix(fRes) of me
–>  {{1.5, 1.5, 1.5}, {1.5, 1.5, 1.5}, {1.5, 1.5, 1.5}, {1.5, 1.5, 1.5}}

set m4 to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:4) andRows:3 byColumns:3
set m2 to current application’s |Matrix|’s alloc()’s initWithValue:(current application’s NSNumber’s numberWithDouble:2) andRows:3 byColumns:3
set gRes to m4’s addMatrix:m2
set ggRes to intListFromMatrix(gRes) of me
–>  {{6, 6, 6}, {6, 6, 6}, {6, 6, 6}}

set hRes to m4’s subtractMatrix:m2
set hhRes to intListFromMatrix(hRes) of me
–>  {{2, 2, 2}, {2, 2, 2}, {2, 2, 2}}

set iRes to m4’s multiplyMatrix:m2
set iiRes to intListFromMatrix(iRes) of me
–>  {{24, 24, 24}, {24, 24, 24}, {24, 24, 24

on doubleListFromMatrix(aMatrix)
  set aList to {}
  
set aRows to aMatrix’s rows()
  
set aColumns to aMatrix’s columns()
  
  
repeat with rowC from 0 to (aRows - 1)
    set colList to {}
    
repeat with colC from 0 to (aColumns - 1)
      set the end of colList to (aMatrix’s getElementAtRow:rowC andColumn:colC) as real
    end repeat
    
set the end of aList to colList
  end repeat
  
return aList
end doubleListFromMatrix

on intListFromMatrix(aMatrix)
  set aList to {}
  
set aRows to aMatrix’s rows()
  
set aColumns to aMatrix’s columns()
  
  
repeat with rowC from 0 to (aRows - 1)
    set colList to {}
    
repeat with colC from 0 to (aColumns - 1)
      set the end of colList to (aMatrix’s getElementAtRow:rowC andColumn:colC) as integer
    end repeat
    
set the end of aList to colList
  end repeat
  
return aList
end intListFromMatrix

on strListFromMatrix(aMatrix)
  set aList to {}
  
set aRows to aMatrix’s rows()
  
set aColumns to aMatrix’s columns()
  
  
repeat with rowC from 0 to (aRows - 1)
    set colList to {}
    
repeat with colC from 0 to (aColumns - 1)
      set the end of colList to (aMatrix’s getElementAtRow:rowC andColumn:colC) as string
    end repeat
    
set the end of aList to colList
  end repeat
  
return aList
end strListFromMatrix

★Click Here to Open This Script 

AppleScript名:MatRのじっけん v3
– Created 2017-05-15 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “DCMatrix”
–https://github.com/davidcox95/MatR
–http://piyocast.com/as/archives/4640

–listからMatrixを作る
set mList to {{1, 2, 3, 4}, {11, 12, 13, 14}, {21, 22, 23, 24}}
set aMatrix to current application’s |Matrix|’s alloc()’s initWithArray:mList andRows:3 byColumns:4
aMatrix’s |print|()
(*
1 2 3 4
11 12 13 14
21 22 23 24
*)

set a1Res to aMatrix’s |transpose|() –左回転
(
a1Res’s |print|())
(*
1 11 21
2 12 22
3 13 23
4 14 24
*)

★Click Here to Open This Script 

tab_sep_text.png

AppleScript名:MatRのじっけん v4
– Created 2017-05-15 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “DCMatrix”
–https://github.com/davidcox95/MatR
–http://piyocast.com/as/archives/4640

–タブ区切りテキストファイルからMatrixを作る
set aPosixFile to POSIX path of (choose file)
set aMatrix to current application’s |Matrix|’s alloc()’s initWithContentsFromFile:aPosixFile
aMatrix’s |print|()
(*
5 6 7 8
3 4 5 6
1 2 3 4
*)

★Click Here to Open This Script 

2017/05/15 感情推定(極性判定) v2

apitoreのREST API「感情推定(極性判定) v2」を呼び出すAppleScriptです。

400文字以下のテキストを解析して、極性(感情)を判定します。ただし、文章が短すぎると判定しづらくなる傾向があるようです。これまでの感情推定APIではpositive/negativeとして判定する傾向があったため、このv2 APIではneutralとして判定する幅を広めにとってもらいました。

本Scriptをテストするためには、apitoreにサインアップしてAccess Tokenを取得し、Script末尾の伏字部分にコピー&ペーストしてください(掲載リストをそのまま実行してもエラーになります)。

AppleScript名:感情推定(極性判定) v2
– Created 2017-05-15 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4639

set aString to "このePubの考え方にそぐわない文章要素がいろいろある。代表的なものは「表」だ。データを掲載しておくのに、「表」は便利な存在だ。書く方からしても、いちいち長々とした文章で説明しなくていいし、読む方からしても整理された情報を読めるわけで、とくにお年寄りに好まれる。ところが、この「表」がePubの出版物にそぐわない。表の幅は変わってほしくないし、文字サイズが大きくなって数ページにわたって表示されるといったことは好ましくない。"
set a1Res to getSentimentFromString(aString) of me
–>  "positive"(なのか?)

on getSentimentFromString(aString)
  set reqURLStr to "https://api.apitore.com/api/39/sentiment-v2/predict"
  
set accessToken to retAccessToken() of me
  
set aRec to {access_token:accessToken, |text|:aString}
  
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 aRESTres to ((json of aRes)’s valueForKeyPath:"predict.sentiment") as string
  
return aRESTres
end getSentimentFromString

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:"application/json" forHTTPHeaderField:"Accept"
  
  
set aRes to current application’s 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 resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s 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 current application’s 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 (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s 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 retAccessToken()
  return "xxXXXxxX-XxXx-XXXX-xXXX-XXxXXxxXxxXx" –API Tore Access Token
end retAccessToken

★Click Here to Open This Script 

2017/05/14 Twitter ScripterでAppleScriptからTwitter投稿、検索

AppleScriptから利用する専用のGUIなしTwitterクライアント「Twitter Scripter」(By Mousedown)を呼び出してTwitter投稿や検索を行うAppleScriptです。

Twitter Scripterはフリーでダウンロードして利用できます。Twitter Scripterは本当にAppleScriptから呼び出すためだけに作られているので、ユーザーインタフェースは一切ありません。

tw1.png

システム環境設定から確認できる(macOS 10.12, Sierra)、Twitterアカウントの一覧を取得します。Twitterアカウントは複数登録されている可能性があるため、リスト(配列)で返ってきます。

AppleScript名:Twitterアカウントを取得
–http://piyocast.com/as/archives/4636
tell application “Twitter Scripter”
  set availableAccounts to available accounts
  
–> {”piyomaru”}
end tell

★Click Here to Open This Script 

さらに、得られたアカウント一覧から適当なものを選んでTwitter投稿してみましょう。

AppleScript名:Twitterにアカウントを指定して投稿(テキストのみ)
–http://piyocast.com/as/archives/4636
tell application “Twitter Scripter”
  set availableAccounts to available accounts
  
–> {”piyomaru”}
  
  
if length of availableAccounts = 0 then return
  
  
set twitterAccount to first item of availableAccounts
  
–> “piyomaru”
  
  
tweet “てすと” using account twitterAccount
end tell

★Click Here to Open This Script 

twitter2.png

システムからTwitterアカウントを取得しなくても、直接文字列で指定することも(当然)できます。ただし、自分で所有してOSに登録していないTwitterアカウントを指定するとエラー応答が返ってきます。

–> {response:{{}}, action:false}

AppleScript名:Twitterにアカウントを指定して投稿(テキストのみ2)
–http://piyocast.com/as/archives/4636
tell application “Twitter Scripter”
  tweet “てすと” using account “piyomaru”
end tell

★Click Here to Open This Script 

Twitter Scripterからはコマンド実行時に大量のデータが返ってくるため、Cocoaの機能を利用してデータの絞り込みを行うのにぴったりです。むしろ、Cocoaの機能を使わないと大量のデータからのしぼりこみを行うのは大変です。

画像を指定してテキストと一緒に画像を投稿することもできるのですが、画像添付についてはうまく動くときと画像が投稿されないときがあるようです(なんで? どうして???)。

検索も可能で、出力対象にrecent(最近の投稿から)、popular(話題の投稿から)、mixed(デフォルト)の3タイプから選択可能です。出力件数には数値で自由に指定できるようになっていますが、実際にためしてみたところ最大件数は100件のようです。

AppleScript名:Twitterを検索する
tell application “Twitter Scripter”
  set availableAccounts to available accounts
  
if length of availableAccounts = 0 then return
  
  
set anAccount to first item of availableAccounts
  
search for “戦場の絆” using account anAccount returning entries 10 result type “mixed”
end tell

★Click Here to Open This Script 

AppleScript名:Twitterを検索する(最近の投稿から)
tell application “Twitter Scripter”
  set availableAccounts to available accounts
  
if length of availableAccounts = 0 then return
  
  
set anAccount to first item of availableAccounts
  
search for “戦場の絆” using account anAccount returning entries 10 result type “recent” –最近の投稿
end tell

★Click Here to Open This Script 

AppleScript名:Twitterを検索する(話題の投稿から)
tell application “Twitter Scripter”
  set availableAccounts to available accounts
  
if length of availableAccounts = 0 then return
  
  
set anAccount to first item of availableAccounts
  
search for “戦場の絆” using account anAccount returning entries 10 result type “popular” –話題の投稿
end tell

★Click Here to Open This Script 

その他のサンプルScriptもMousedownのWebサイトに掲載されています。