Archive for 1月, 2011

2011/01/25 リストで与えられたデータの変動ベクトル方向を取得する

リストで与えられたデータの変動ベクトル方向を取得するAppleScriptです。

……こう書くと何のことやら分かりませんが、かなり具体的なニーズに応えるために作成したものです。

Illustrator上でグラフを作成し、グラフのマーカーに近接して数値情報を配置しようとしたときに、グラフの線と重ならないように数値情報を配置することが必要になりました。

そこで、グラフの値が上昇している部分なのか、下降している部分なのか……といった傾向の判断を行うためにこうしたデータを作成し、さらにグラフの左右の端にあるかどうかなどのデータを取得して総合的に位置決めを行うことにした次第。

こうしたデータの変動ベクトル方向を求めるという用途は意外にたくさんあり、自分は割とよく使う処理です。

Illustratorのグラフ機能は貧弱で、どうせそのままでは使い物にならないので、GUI Scripting経由でAppleScriptからデータを突っ込んで、グラフオブジェクトをグループ解除して「ただのpath item」にまで分解してから料理しています。データを差し替えるとグラフのマーカーが変わってしまったとしても、分解してしまえば大丈夫です。

スクリプト名:リストで与えられたデータの変動ベクトル方向を取得する
set aList to {0.325, 0.4, 0.35, 0.012, 0.025, 0.55}

set curItem to first item of aList
set aList to rest of aList

set trendList to {}

repeat with i in aList
  
  
if curItem < i then
    set aTrend to “u”
  else if curItem > i then
    set aTrend to “d”
  else
    aTrend to “-”
  end if
  
  
set the end of trendList to aTrend
  
copy i to curItem
  
end repeat

trendList
–> {”u”, “d”, “d”, “u”, “u”}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/18 Numbersでtableの縦サイズをふやす

Numbersのシート中の表(テーブル)の縦のセル数を増やすAppleScriptです。

意外といい加減に変更できてびっくりです。

スクリプト名:Numbersでtableの縦サイズをふやす
tell application "Numbers"
  tell document 1
    tell sheet 1
      tell table 1
        set rowNum to row count
        
set row count to rowNum + 5
      end tell
    end tell
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/18 選択したセルからNumbers上のセルを指定リストの値で埋める

Numbers上の選択したセルから、指定の入れ子になっているリストの値で埋めるAppleScriptです。

選択されていなかった場合には、左上の原点を基準にデータが展開されます。

num1.jpg

もしも、シート上の表のサイズよりもリストのデータ要素数が多かった場合にはエラーになります。対策方法もすでに分かっていて、表を適宜リサイズして広げてあげればエラーは回避できます。

「とりあえず動く」というレベルを目指したので、セルを埋める様子を目で追うことができる程度のスピードですが、真剣に最適化すればもう少し効率のよいコントロールは可能と思っています。

スクリプト名:選択したセルからNumbers上のセルを指定リストの値で埋める
set aList to {{“abc”, “10″}, {“bcd”, “20″}, {“cde”, “30″}}
fillCellFromSelectedCellOnNumbersByList(aList) of me

–与えたリストのデータ(入れ子のリスト)を、Numbersで現在選択中のセルから展開する
–セルが選択されていなかった場合には原点から展開
–展開後のデータ範囲が現在のテーブルの範囲を超える場合にはエラーになる
on fillCellFromSelectedCellOnNumbersByList(aList)
  set dataRow to length of aList
  
set dataColumn to length of first item of aList
  
  
set {aRow, aColumn} to getSelectedRowColumn() of me
  
  
if {aRow, aColumn} = {0, 0} then
    set aRow to 1
    
set aColumn to 1
  end if
  
  
set fromAddress to getNameOfNumbersAddress(aRow, aColumn) of me
  
set toAddress to getNameOfNumbersAddress(aRow + dataRow - 1, aColumn + dataColumn - 1) of me
  
  
set dataRange to fromAddress & “:” & toAddress
  
  
–リストをフラット化
  
set aaList to FlattenList(aList) of me
  
fillCellOnNumbers(aaList, dataRange) of me
  
end fillCellFromSelectedCellOnNumbersByList

–指定範囲のNumbers上のセルを指定リストの値で埋める
–ループでcellを埋めているので、処理が遅い
on fillCellOnNumbers(aList, aRangeAddress)
  tell application “Numbers”
    tell document 1
      tell sheet 1
        tell table 1
          –cellのリストが返ってくる
          
set aCellList to cell of range aRangeAddress
          
          
set cCount to 1
          
          
repeat with i in aCellList
            set aCon to contents of item cCount of aList
            
set value of i to aCon
            
            
set cCount to cCount + 1
          end repeat
          
        end tell
      end tell
    end tell
  end tell
end fillCellOnNumbers

–指定したNumbersのcell/rowのnameを返す
on getNameOfNumbersAddress(aRow, aColumn)
  try
    tell application “Numbers”
      tell document 1
        tell sheet 1
          tell table 1
            set aName to name of cell aRow of column aColumn
          end tell
        end tell
      end tell
    end tell
  on error
    return “”
  end try
end getNameOfNumbersAddress

–Numbersで選択されているセルのRowとColumnを取得する
on getSelectedRowColumn()
  tell application “Numbers”
    tell document 1
      tell sheet 1
        tell table 1
          try
            set selList to value of every cell of selection range –選択範囲のデータを取得
          on error
            return {0, 0}
          end try
          
          
set selName to name of selection range –選択範囲のrange情報を取得
          
set {s1, s2} to parseByDelim(selName, “:”) of me
          
          
–始点の情報を取得する
          
set s1Row to (address of row of range s1) as integer
          
set s1Column to (address of column of range s1) as integer
          
          
–終点の情報を取得する
          
set s2Row to (address of row of range s2) as integer
          
set s2Column to (address of column of range s2) as integer
          
          
–選択範囲の情報を取得する
          
set selHeight to s2Row - s1Row + 1 –高さ(Height of selection range)
          
set selWidth to s2Column - s1Column + 1 –幅(Width of selection range)
          
        end tell
      end tell
    end tell
  end tell
  
  
return {s1Row, s1Column}
end getSelectedRowColumn

–与えられた文字列を、指定デリミタ文字でparseしてリストにして返す
on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

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

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/16 タイマー割り込みでマウスの座標を取得する

NSTimerで宣言したタイマー割り込みサービスで定期的に(0.1秒ごとに)マウスカーソルの座標を取得するサンプルです。

昔、このために専用のアプリが配布されていましたが……AppleScriptでこんなに簡単に実現できるようになった、というのはすごいことです。以前から不満に思っていた機能が割とあるので、このサンプルをもとにいろいろ追加してしまいました。

→ mousewatcher.zip

2011/01/16 複数のNSButtonで別々のクリックイベントを受信

複数のNSButtonで別々のクリックイベントを受信するサンプルです。

AppleScript Studioのときには、このように1本のScriptの別々のイベントハンドラでボタンごとのクリックイベントを受信することはできませんでした。

→ buttons_separate_event.zip

2011/01/16 TextFieldの表示/非表示設定

NSTextFieldの表示/非表示を行うサンプルです。

→ hidetf.zip

2011/01/16 NSTextFieldからの文字列取得/文字列設定

ASOCでNSTextFieldへのアクセスを行うサンプルです。

 set a to textField1’s stringValue() –textFieldからの文字列の取得
 textField2’s setStringValue_(a) –textFieldへの文字列の設定

→ twotextfield.zip

2011/01/14 シェルソートでリストをソート

フラットな(入れ子ではない)リストをシェルソートでソートするAppleScriptです。冒頭にあるのはテスト用データ作成部分です。

入れ子になっているリスト、{{1,2,3,4}, {2,3,4,5}, {3,4,5,6}} をソートする機会はめちゃめちゃ多いのですが、単なるフラットなリストだと使用頻度はぐっと低く、わざわざ昇順/降順のシェルソートルーチンを用意していませんでした(もっと遅い部品を使っていました)。

たまたま、スピードにこだわりたい処理があったのでシェルソートで単純なリストの昇順/降順ソートをまとめておきました。

スクリプト名:シェルソートでリストをソート

set theList to {}
set i to 1
repeat 300 times
  copy (random number from 100 to 999) to the end of theList
  
set i to i + 1
end repeat

set s0Time to current date
set aRes to shellSortDecending(theList) of me
set s1Time to current date

display dialog (s1Time - s0Time) as string
aRes

–シェルソートでリストを昇順ソート(入れ子ではないリスト)
on shellSortAscending(a)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item (j - h + 1) of a) > v)
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortAscending

–シェルソートでリストを降順ソート(入れ子ではないリスト)
on shellSortDecending(a)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item (j - h + 1) of a) < v)
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortDecending

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/13 画面の解像度を取得するv5

画面の解像度を取得するAppleScriptです。

スクリプト名:画面の解像度を取得するv5
return {word 3 of (do shell script "defaults read /Library/Preferences/com.apple.windowserver | grep -w Width") as number, word 3 of (do shell script "defaults read /Library/Preferences/com.apple.windowserver | grep -w Height") as number}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/13 画面の解像度を取得するv4

画面の解像度を取得するAppleScriptです。

スクリプト名:画面の解像度を取得するv4
tell application "Finder"
  get bounds of window of desktop
  
–> {0, 0, 1440, 900}
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/13 画面の解像度を取得するv3

画面の解像度を取得するAppleScriptです。

スクリプト名:画面の解像度を取得するv3
return {word 3 of (do shell script "defaults read /Library/Preferences/com.apple.windowserver | grep -w Width"), word 3 of (do shell script "defaults read /Library/Preferences/com.apple.windowserver | grep -w Height")}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/13 画面の解像度を取得するv2

画面の解像度を取得するAppleScriptです。

スクリプト名:画面の解像度を取得するv2
tell (do shell script “/usr/sbin/system_profiler SPDisplaysDataType | grep Resolution”) to set {newR, newB} to {word 2 as number, word 4 as number} – get screen size for monitor

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/13 iCalで選択中のイベントのカレンダー情報を取得する

iCal上で選択中のイベントが所属しているカレンダーの名称を取得するAppleScriptです。

iCalのAppleScript用語辞書には致命的な欠陥が山のようにあって……GUI上で選択中のイベント(selection)を取得できません。普通のやり方では、選択中のイベントのカレンダー名を取得できません。もっと基本的なところで、いま表示中の月が何月なのかも分かりません。

日時を指定してイベントを登録したり、フィルタ参照でイベントを抽出したりするぐらいで、画面上で選択したイベントから対話的に何かの処理を行うようなAppleScriptを作りにくい(というよりも、作れない)状況にあります。

ical1.jpg

はい、おしまいおしまい〜

……などと言っていては海外の強豪Scripter連中に顔向けできません。

選択中のイベントが存在するのであれば、コピーを実行すると何らかの情報が得られるはずです。

実際にiCal上でコピーを実行してみると、

<ここから>
退去確認@ヴィラ山田
2011年1月22日 を 16:00 〜 17:00 にスケジュールしました
</ここまで>

のような内容が得られました。この情報から日付、開始時刻、終了時刻、イベント名 などを取得できます。

これらの情報を手がかりに、すべてのカレンダー上で検索(フィルタ参照による抽出)を行ってみました。

実行条件は、GUI Scriptingがオンになっていることと、iCal上でなにがしかのイベントが選択状態になっていることです。

ical2.jpg

GUI Scripting(UI Element Scripting)経由で選択イベントのコピー動作を行い、クリップボードの内容を解析。得られた情報をもとに今度はiCalに正攻法ですべてのカレンダーに対して「日付、開始時刻、終了時刻、イベント名」を手がかりにイベントの検索を行います。条件に合致するイベントが見つかったら、カレンダーの名称を取得して返します。これを複数のイベントに対してループで実行してみました。

実験してみたところ、複数のイベントを一度に選択した場合、その中に「繰り返しイベント」が含まれているとiCalがダイアログで警告します。このダイアログが邪魔なので、ダイアログのクローズ処理も行わなくてはなりません。

ical3.jpg

作成時間はトータルで40分程度でしょうか。かなり作り込みましたが、驚くべきことに、さほど実用性がありません、、、

スクリプト名:iCalで選択中のイベントの情報を取得する
set aRes to retSelectedEvent() of me

set icalRes to {}
repeat with i in aRes
  set j to contents of i
  
set the end of icalRes to getCalName(j) of me
end repeat
icalRes
–> {”ホーム”}

–選択中のiCal上のイベントが所属しているカレンダーの名称を取得する
on getCalName(aStr)
  
  
set aList to paragraphs of aStr
  
set aTitle to contents of item 1 of aList
  
set dStr to contents of item 2 of aList
  
  
set dOffset to offset of “日 を “ in dStr
  
set dDate to text 1 thru dOffset of dStr
  
–set dDateObj to date dDate
  
  
set tSeparator to offset of ” 〜 “ in dStr
  
if tSeparator = 0 then
    –「〜」がないことから、終日のスケジュールと判断
    
set timeFrom to “0:00″
    
set timeTo to “23:59:59″
  else
    –開始時刻と終了時刻のあるスケジュールと判断
    
set timeFrom to text (dOffset + 4) thru (tSeparator - 1) of dStr
    
set timeTo to text (tSeparator + 3) thru ((length of dStr) - 12) of dStr
  end if
  
  
set timeFromObj to date (dDate & ” “ & timeFrom)
  
set timeToObj to date (dDate & ” “ & timeTo)
  
  
  
  
tell application “iCal”
    set cnList to name of every calendar
    
set cList to every calendar
    
    
set cCount to 1
    
set findF to false
    
repeat with i in cList
      tell i
        set eList to (every event whose start date is not less than timeFromObj and start date is not greater than timeToObj and summary of it is aTitle)
        
if eList is not equal to {} then
          set findF to true
          
exit repeat
        end if
      end tell
      
set cCount to cCount + 1
    end repeat
    
    
if findF = true then
      set aName to contents of item cCount of cnList
    else
      set aName to “”
    end if
  end tell
  
  
return aName
end getCalName

–選択中のイベント情報をコピー(エラー時にはfalseをリターン)
on retSelectedEvent()
  activate application “iCal”
  
tell application “System Events”
    tell process “iCal”
      –「編集」メニューの項目「コピー」がイネーブルかどうかを取得
      
set copyEnabled to (enabled of menu item 5 of menu 1 of menu bar item 4 of menu bar 1)
      
if copyEnabled = false then return false
      
      
–コピーしてみる
      
try
        
        
keystroke “c” using {command down}
      on error
        –何らかの都合でコピー等の動作を行えなかった場合
        
return false
      end try
      
      
–ダイアログ表示時のボタンクリック
      
clickiCalDialog() of me
      
      
–クリップボードから文字情報を取得
      
set aConList to the clipboard
      
set aCon to aConList as string
      
    end tell
  end tell
  
  
set aList to parseByDelim(aCon, (ASCII character 13) & (ASCII character 13)) of me
  
  
return aList
  
end retSelectedEvent

–iCalでイベントをコピー時に、繰り返しイベントが選択されていた時に表示されるダイアログを乗り越えるためのルーチン
–(「キャンセル」ではない方のボタンを押す)
on clickiCalDialog()
  –ダイアログ検出
  
tell application “System Events”
    tell process “iCal”
      if (count every window) > 1 then
        if subrole of window 1 = “AXDialog” then
          tell window 1
            –キャンセル「ではない」方のボタンを取得
            
set bList to every button whose title is not equal to “キャンセル”
            
if bList is not equal to {} then
              set aButton to first item of bList
              
tell aButton
                click
              end tell
            end if
          end tell
        end if
      end if
    end tell
  end tell
end clickiCalDialog

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

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/12 リストの項目数をそろえてタブで区切ったテキストに変換する

与えられたリストの項目数をプロパティ(maxRow)で指定した数と比較し、足りない分はヌル要素を追加して、最終的にタブで区切ったテキストに変換するAppleScriptです。

Illustratorでグラフデータを連続自動作成する処理で、グラフに与えるデータを作成したものです。

スクリプト名:リストの項目数をそろえてタブで区切ったテキストに変換する
set maxRow to 9 –最大項目数
set aList to {40, 30, 20, 10}

–項目数が足りない場合には項目を追加する
set outStr to ""
set itemC to count every item of aList
if itemC < maxRow then
  repeat (maxRow - itemC) times
    set aList to aList & 0
  end repeat
end if
–> {40, 30, 20, 10, 0, 0, 0, 0, 0}

–リストを指定デリミタでテキスト化
set sList to {}
repeat with i in aList
  set j to contents of i
  
  
–このあたりで、適度にデータ加工するとよさそう(指定桁以下の切り捨てとか四捨五入とか)
  
if j = 0 then
    set jj to ""
  else
    set jj to j as string
  end if
  
  
set the end of sList to jj
end repeat
–> {"40", "30", "20", "10", "", "", "", "", ""}

set resStr to retDelimedText(sList, tab) of me
–> "40  30  20  10          "

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

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/12 与えられたリストに、値がヌルの要素が入っているか判定し、フラグ、ブランク開始終了位置を返す v2

与えられたリストに、値がヌルの要素が入っているか判定し、ヌルが入っているかをフラグで返し、前方にブランクがあるか後方にブランクがあるかのフラグ、ブランク開始位置、ブランク終了位置を返すAppleScriptです。

何らかの数字をO、ブランクをXとすると……

後方にブランクが存在するリスト {O, O, O, O, O, X, X}
前方にブランクが存在するリスト {X, X, O, O, O, O, O}

というタイプの「前方か後方にブランクが存在するリスト」を処理対象にしています。途中にブランクが登場するようなもの(例:{O, X, O, O, X, O, O})は前提にしていません。

はっきり言えば、カレンダーの日付の存在箇所と存在しない箇所をピックアップするために作成したものなので、そういう用途に使いました。

スクリプト名:与えられたリストに、値がヌルの要素が入っているか判定し、フラグ、ブランク開始終了位置を返す v2
set aList to {“1″, “2″, “3″, “4″, “5″, “6″, “7″} –すべての要素がヌルではないリスト
set {aFlag, pFlag, bStart, bEnd} to detectBlankItemFromList(aList) of me
log {aFlag, pFlag, bStart, bEnd}
–> (*true, , 0, 0*)

set aList to {“1″, “2″, “3″, “”, “”, “”, “”} –後ろにヌルが入っているリスト
set {aFlag, pFlag, bStart, bEnd} to detectBlankItemFromList(aList) of me
log {aFlag, pFlag, bStart, bEnd}
–> (*false, after, 4, 7*)

set aList to {“”, “”, “”, “4″, “5″, “6″, “7″} –先頭にヌルが入っているリスト
set {aFlag, pFlag, bStart, bEnd} to detectBlankItemFromList(aList) of me
log {aFlag, pFlag, bStart, bEnd}
–> (*false, before, 1, 3*)

–与えられたリストに、値がヌルの要素が入っているか判定し、フラグ、前がブランクか後がブランクか、ブランク開始・終了位置を返す
on detectBlankItemFromList(aList)
  set aCount to 1
  
set retF to true
  
set aLen to length of aList
  
  
set directionF to “”
  
  
set blankStart to 1
  
set blankEnd to aLen
  
  
  
if contents of item 1 of aList = “” then
    –頭の方にブランクがある場合
    
set rList to reverse of aList –リストを逆順に
    
repeat with i in rList
      if contents of i is equal to “” then
        set retF to false –Blank Itemが入っている場合
        
exit repeat
      end if
      
set aCount to aCount + 1
    end repeat
    
    
set blankStart to 1
    
set blankEnd to (aLen - aCount + 1)
    
    
set directionF to “before”
    
  else if contents of last item of aList = “” then
    –末尾の方にブランクがある場合
    
repeat with i in aList
      if contents of i is equal to “” then
        set retF to false –Blank Itemが入っている場合
        
exit repeat
      end if
      
set aCount to aCount + 1
    end repeat
    
    
set blankStart to aCount
    
set blankEnd to aLen
    
    
set directionF to “after”
    
  else
    –先頭にも末尾にもブランクがない場合
    
set blankStart to 0
    
set blankEnd to 0
    
set retF to true
    
  end if
  
  
return {retF, directionF, blankStart, blankEnd}
  
end detectBlankItemFromList

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/12 指定日がその月の中で何週目かを求めて、週リストを取得する

指定日がその月の中で何週目かを求め、その該当週のdateオブジェクトが入ったリストを取得するAppleScriptです。

スクリプト名:指定日がその月の中で何週目かを求めて、週リストを取得する
set tDate to "2011/1/3"
set tDateObj to date tDate

set aWeek to retTheNumberOfWeekInTheMonth(tDateObj) of me
–> 2

set aList to retTheListOfWeekInTheMonth(tDateObj, aWeek) of me
–> {date "2011年1月2日日曜日 0:00:00", date "2011年1月3日月曜日 0:00:00", date "2011年1月4日火曜日 0:00:00", date "2011年1月5日水曜日 0:00:00", date "2011年1月6日木曜日 0:00:00", date "2011年1月7日金曜日 0:00:00", date "2011年1月8日土曜日 0:00:00"}

–指定日が所属する月の中の指定週のリストを求める
on retTheListOfWeekInTheMonth(tDateObj, theWeek)
  –引数から年と月を求める
  
set theYear to year of tDateObj
  
set theMonth to month of tDateObj as number
  
set theDate to day of tDateObj
  
  
–指定月のリストを作成
  
set mList to makeMonthList(theYear, theMonth) of me
  
  
–得られた週リストから、指定週のリストを返す
  
set wList to contents of item theWeek of mList
  
return wList
  
end retTheListOfWeekInTheMonth

–指定日がその月の中で何週目かを求める
on retTheNumberOfWeekInTheMonth(tDateObj)
  –引数から年と月を求める
  
set theYear to year of tDateObj
  
set theMonth to month of tDateObj as number
  
set theDate to day of tDateObj
  
  
–指定月のリストを作成
  
set mList to makeMonthList(theYear, theMonth) of me
  
  
set wNum to getWeekNumInTheMonth(mList, tDateObj) of me
  
  
return wNum
  
end retTheNumberOfWeekInTheMonth

–指定のカレンダーから、指定日が何週目かを求める
on getWeekNumInTheMonth(yList, aDate)
  set weekCount to 1
  
  
repeat with i in yList
    repeat with ii in i
      set jj to contents of ii
      
if jj is equal to aDate then
        return weekCount
      end if
    end repeat
    
set weekCount to weekCount + 1
  end repeat
  
return 0
end getWeekNumInTheMonth

–指定の月を1月分リスト化
on makeMonthList(theYear, theMonth)
  
  
set yList to {}
  
set curList to {}
  
  
set curList to {"", "", "", "", "", "", ""}
  
  
–1か月分の日をリスト化
  
set aLen to getMlen(theYear, theMonth) of me
  
  
repeat with ii from 1 to aLen
    set aDateStr to (((theYear as string) & "/" & theMonth as string) & "/" & ii as string)
    
set aDate to date aDateStr
    
set aWD to weekday of aDate as number
    
set item aWD of curList to aDate
    
if aWD = 7 then
      set the end of yList to curList
      
set curList to {"", "", "", "", "", "", ""}
    end if
  end repeat
  
  
if curList is not equal to {"", "", "", "", "", "", ""} then
    set the end of yList to curList
  end if
  
  
return yList
  
end makeMonthList

–指定月の長さを得る(日数)
on getMlen(aYear, aMonth)
  
  
set aDat to (aYear as text) & "/" & (aMonth as text) & "/1"
  
if aMonth is not equal to 12 then
    set eDat to ((aYear as text) & "/" & (aMonth + 1) as text) & "/1"
  else
    set eDat to ((aYear + 1) as text) & "/" & (1 as text) & "/1"
  end if
  
  
–set sDat to date aDat
  
set eDat to date eDat
  
set eDat to eDat - 1
  
  
set mLen to day of eDat
  
return mLen
  
end getMlen

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/12 指定日がその月の中で何週目かを求める

指定日がその月の何週目かを求めるAppleScriptです。

スクリプト名:指定日がその月の中で何週目かを求める

set tDate to "2011/1/3"
set tDateObj to date tDate

set a to retTheNumberOfWeekInTheMonth(tDateObj) of me
–> 2

–指定日がその月の中で何週目かを求める
on retTheNumberOfWeekInTheMonth(tDateObj)
  –引数から年と月を求める
  
set theYear to year of tDateObj
  
set theMonth to month of tDateObj as number
  
set theDate to day of tDateObj
  
  
–指定月のリストを作成
  
set mList to makeMonthList(theYear, theMonth) of me
  
  
set wNum to getWeekNumInTheMonth(mList, tDateObj) of me
  
  
return wNum
  
end retTheNumberOfWeekInTheMonth

–指定のカレンダーから、指定日が何週目かを求める
on getWeekNumInTheMonth(yList, aDate)
  set weekCount to 1
  
  
repeat with i in yList
    repeat with ii in i
      set jj to contents of ii
      
if jj is equal to aDate then
        return weekCount
      end if
    end repeat
    
set weekCount to weekCount + 1
  end repeat
  
return 0
end getWeekNumInTheMonth

–指定の月を1月分リスト化
on makeMonthList(theYear, theMonth)
  
  
set yList to {}
  
set curList to {}
  
  
set curList to {"", "", "", "", "", "", ""}
  
  
–1か月分の日をリスト化
  
set aLen to getMlen(theYear, theMonth) of me
  
  
repeat with ii from 1 to aLen
    set aDateStr to (((theYear as string) & "/" & theMonth as string) & "/" & ii as string)
    
set aDate to date aDateStr
    
set aWD to weekday of aDate as number
    
set item aWD of curList to aDate
    
if aWD = 7 then
      set the end of yList to curList
      
set curList to {"", "", "", "", "", "", ""}
    end if
  end repeat
  
  
if curList is not equal to {"", "", "", "", "", "", ""} then
    set the end of yList to curList
  end if
  
  
return yList
  
end makeMonthList

–指定月の長さを得る(日数)
on getMlen(aYear, aMonth)
  
  
set aDat to (aYear as text) & "/" & (aMonth as text) & "/1"
  
if aMonth is not equal to 12 then
    set eDat to ((aYear as text) & "/" & (aMonth + 1) as text) & "/1"
  else
    set eDat to ((aYear + 1) as text) & "/" & (1 as text) & "/1"
  end if
  
  
–set sDat to date aDat
  
set eDat to date eDat
  
set eDat to eDat - 1
  
  
set mLen to day of eDat
  
return mLen
  
end getMlen

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/12 指定の月を1月分リスト化

指定日の属している月の日付を1か月分リスト化するAppleScriptです。

7日ペアになったリスト(1週分)を入れ子にしたリストを返します。

スクリプト名:指定の月を1月分リスト化
set tDate to "2011/1/3"
set tDateObj to date tDate

set theYear to year of tDateObj
set theMonth to month of tDateObj as number

set aList to makeMonthList(theYear, theMonth) of me
–> {{"", "", "", "", "", "", date "2011年1月1日土曜日 0:00:00"}, {date "2011年1月2日日曜日 0:00:00", date "2011年1月3日月曜日 0:00:00", date "2011年1月4日火曜日 0:00:00", date "2011年1月5日水曜日 0:00:00", date "2011年1月6日木曜日 0:00:00", date "2011年1月7日金曜日 0:00:00", date "2011年1月8日土曜日 0:00:00"}, {date "2011年1月9日日曜日 0:00:00", date "2011年1月10日月曜日 0:00:00", date "2011年1月11日火曜日 0:00:00", date "2011年1月12日水曜日 0:00:00", date "2011年1月13日木曜日 0:00:00", date "2011年1月14日金曜日 0:00:00", date "2011年1月15日土曜日 0:00:00"}, {date "2011年1月16日日曜日 0:00:00", date "2011年1月17日月曜日 0:00:00", date "2011年1月18日火曜日 0:00:00", date "2011年1月19日水曜日 0:00:00", date "2011年1月20日木曜日 0:00:00", date "2011年1月21日金曜日 0:00:00", date "2011年1月22日土曜日 0:00:00"}, {date "2011年1月23日日曜日 0:00:00", date "2011年1月24日月曜日 0:00:00", date "2011年1月25日火曜日 0:00:00", date "2011年1月26日水曜日 0:00:00", date "2011年1月27日木曜日 0:00:00", date "2011年1月28日金曜日 0:00:00", date "2011年1月29日土曜日 0:00:00"}, {date "2011年1月30日日曜日 0:00:00", date "2011年1月31日月曜日 0:00:00", "", "", "", "", ""}}

–指定の月を1月分リスト化
on makeMonthList(theYear, theMonth)
  
  
set yList to {}
  
set curList to {}
  
  
set curList to {"", "", "", "", "", "", ""}
  
  
–1か月分の日をリスト化
  
set aLen to getMlen(theYear, theMonth) of me
  
  
repeat with ii from 1 to aLen
    set aDateStr to (((theYear as string) & "/" & theMonth as string) & "/" & ii as string)
    
set aDate to date aDateStr
    
set aWD to weekday of aDate as number
    
set item aWD of curList to aDate
    
if aWD = 7 then
      set the end of yList to curList
      
set curList to {"", "", "", "", "", "", ""}
    end if
  end repeat
  
  
if curList is not equal to {"", "", "", "", "", "", ""} then
    set the end of yList to curList
  end if
  
  
return yList
  
end makeMonthList

–指定月の長さを得る(日数)
on getMlen(aYear, aMonth)
  
  
set aDat to (aYear as text) & "/" & (aMonth as text) & "/1"
  
if aMonth is not equal to 12 then
    set eDat to ((aYear as text) & "/" & (aMonth + 1) as text) & "/1"
  else
    set eDat to ((aYear + 1) as text) & "/" & (1 as text) & "/1"
  end if
  
  
–set sDat to date aDat
  
set eDat to date eDat
  
set eDat to eDat - 1
  
  
set mLen to day of eDat
  
return mLen
  
end getMlen

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/11 日本の月呼称を返す

数値で月を与えると、日本語の月呼称の文字列を返すAppleScriptです。

スクリプト名:日本の月呼称を返す
repeat with i from 1 to 15
  set aStr to retJapaneseMonthName(i) of me
  
log {i, aStr}
end repeat

–>
(*1, 睦月*)
(*2, 如月*)
(*3, 弥生*)
(*4, 卯月*)
(*5, 皐月*)
(*6, 水無月*)
(*7, 文月*)
(*8, 葉月*)
(*9, 長月*)
(*10, 神無月*)
(*11, 霜月*)
(*12, 師走*)
(*13, *)
(*14, *)
(*15, *)

–日本の月呼称を返す
on retJapaneseMonthName(aMonthNum)
  if aMonthNum < 1 or aMonthNum > 12 then return "" –エラーチェック
  
  
set aMonthNum to aMonthNum as integer
  
set mStrList to {"睦月", "如月", "弥生", "卯月", "皐月", "水無月", "文月", "葉月", "長月", "神無月", "霜月", "師走"}
  
return contents of item aMonthNum of mStrList
end retJapaneseMonthName

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/07 App Store.appをコントロール

Mac OS X 10.6.6アップデートが公開され、Mac App Storeがオープンになりました。ふとApp Store.appのAppleScript用語辞書を調べてみると……なんと、辞書がついています(=AppleScriptからコントロールできる)。

そこで、さっそくMac App Storeへのアクセスを司る「App Store」アプリケーションをAppleScriptからコントロールしてみました。

appstore.jpg

用語辞書を調べて時点で分かっていたのですが、何か面白いことができたりはしません。現状では起動と終了と印刷ぐらいしかできない状態です。何か有意義な情報にアクセスできたり、何らかのコマンドをキックすることも一切できません。

アプリケーションのプロパティを取得すると、あたりさわりのない結果が得られます。ただ、現在どこのURLをオープンしているとか、指定のIDでログインするとかいった処理はできません。

appstore2.jpg

Windowオブジェクトにアクセスしてみましたが、こちらも面白みのある(=使い物になりそうな)属性データはひとつもありません。AppleScriptの辞書は搭載しているものの、とくに何ができるというわけでもなさそうです。

ただし、URLを指定してAppStore上の指定のページをオープンすることだけはできるので、URLプロトコル「macappstore://」を指定してopen locationコマンドでオープンしてみると、指定URLをオープンできました。

AppStore.appのバンドル内のInfo.plistを読んでみると、「macappstore」のほかに「macappstores」というURLも定義されており、後者はsecureなURLだといった説明がなされています。

全体的に見て、AppStore.appはMac App StoreだけをブラウズできるWebブラウザ+課金サービスへのアクセスクライアントであり、それほど面白味のあるアプリケーションでもありません。

とりあえず、フォント指定がおかしいのか文字サイズ指定がおかしいのか圧倒的に文字が読みにくいのでなんとかしてほしいところです。

スクリプト名:AppStore.appをコントロール
tell application “App Store”
  properties
  
–> {frontmost:false, class:application, name:”App Store”, version:”1.0″}
  
  
tell window 1
    properties
    
–> {document:missing value, closeable:true, zoomed:false, class:window, index:1, visible:true, name:”", modal:false, miniaturizable:true, titled:true, miniaturized:false, floating:false, id:55, resizable:true, bounds:{356, 22, 1843, 1161}, zoomable:true}
  end tell
  
end tell

–指定のURLをオープンする
open location “macappstore://itunes.apple.com/jp/app/mindnode-for-mac/id402397683?mt=12″
–> App Storeで指定のURLを表示

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/05 リスト同士のdiffをとる

2つのリスト同士を比較して、相互に存在しない要素をピックアップします。いわゆる、リスト間のdiffをとるAppleScriptです。

正直なところ、相当昔(2〜3年ぐらい昔)に作ったので処理の細部を覚えていないのですが……なにげに途中に不思議な処理(なぜか同じ置換処理を2回行っている……)があったりします。1行だけにしても、置換処理そのものをコメントアウトしても問題なく動いているので、何か込み入ったデータを喰わせた際の対策だったのかもしれません。

<追記>
HTMLに書き出してはじめて分かりましたが、スペースの置換とタブの置換を行っていたようです。いやはや。
</追記ここまで>

例によって汎用サブルーチンを組み合わせて作ったため、「diffをとる」という単純で簡素な目的とはそぐわないほどの行数になっていますが、短時間で作ったためにそうなったものとご理解ください。

スクリプト名:リスト同士のdiffをとる
set aList to {1, 2, 3, 4, 0, 9, 10, 11}
set bList to {4, 3, 2, 1, 5, 10}
set aRes to diffList(aList, bList) of listDiffKit
–> {{0, 9, 11}, {5}}

set aList to {“abc”, “cde”, “def”}
set bList to {“abc”, “cde”, “def”, “ddd”}
set aRes to diffList(aList, bList) of listDiffKit
–> {{}, {”ddd”}}

set aList to {“ぴよ”, “ひよ”, “ビよ”, “よよ”}
set bList to {“ビよ”, “ひよ”, “ぴよ”, “ぱよ”}
set aRes to diffList(aList, bList) of listDiffKit
–>{{”よよ”}, {”ぱよ”}}

script listDiffKit
  
  
–リスト同士のdiffをとる
  
on diffList(aaList, bbList)
    copy {aaList, bbList} to {aList, bList} –fix?
    
set notExistInBlist to {}
    
    
if aList is equal to bList then
      return {{}, {}}
    end if
    
    
set aListText to (retDelimedText(aList, “|”) of me) as Unicode text
    
set aListText to repChar(aListText, “ ” as Unicode text, “”) of me
    
set aListText to repChar(aListText, ” “ as Unicode text, “”) of me –?????
    
    
set bListText to (retDelimedText(bList, “|”) of me) as Unicode text
    
set bListText to repChar(bListText, “ ” as Unicode text, “”) of me
    
set bListText to repChar(bListText, ” “ as Unicode text, “”) of me –?????
    
    
if aListText is equal to bListText then
      return {{}, {}}
    end if
    
    
repeat with i in aList
      set j to contents of i
      
if j is in bList or j is equal to bList then
        set bList to deleteSpecifiedItemFromList(bList, j) of me
      else
        set the end of notExistInBlist to j
      end if
    end repeat
    
    
return {notExistInBlist, bList}
  end diffList
  
  
–指定内容の要素をリストから削除して返す
  
on deleteSpecifiedItemFromList(aList, anItem)
    set iCount to 1
    
repeat with i in aList
      set j to contents of i
      
if j = anItem then
        set aaList to oneItemDelete(aList, iCount) of me
        
return aaList
      end if
      
set iCount to iCount + 1
    end repeat
    
    
return aList
    
  end deleteSpecifiedItemFromList
  
  
–リスト中の指定要素を削除して返す
  
on oneItemDelete(aList, chgNum)
    set newList to {}
    
set aLen to length of aList
    
    
if chgNum = 1 then
      set aLen to length of aList
      
if aLen > 1 then
        set maeList to items 2 thru aLen of aList
        
set newList to maeList
      else
        set newList to {}
      end if
    else if chgNum = aLen then
      set maeList to items 1 thru (aLen - 1) of aList
      
set newList to maeList
      
    else
      set maeList to items 1 thru (chgNum - 1) of aList
      
set atoList to items (chgNum + 1) thru -1 of aList
      
set newList to maeList & atoList
    end if
    
    
return newList
  end oneItemDelete
  
  
on retDelimedText(aList, aDelim)
    set aText to “”
    
set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to aDelim
    
set aText to aList as text
    
set AppleScript’s text item delimiters to curDelim
    
return aText
  end retDelimedText
  
  
–文字置換ルーチン
  
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
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に