Menu

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

AppleScriptの穴

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

タグ: 10.11savvy

iTunesライブラリ中の楽曲のみしぼりこんでアルバムのtitle一覧を取得

Posted on 12月 22, 2018 by Takaaki Naganoya

iTunesライブラリ(+Apple Book)のメディアから楽曲(mediaKind=ITLibMediaItemMediaKindSong)のみ抽出してアルバムのタイトル一覧を取得するAppleScriptです。

iTunesLibrary.framework経由でメデイアアイテムの情報にアクセスするため、iTunes.appが起動していてもいなくても関係ありません。開発環境のマシン(MacBook Pro Retina 2012 Core i7 2.66GHz)でiTunesに6,871曲の楽曲が存在している状態で0.03秒程度です。

iTunes.appとプロセス間通信していないため、macOS 10.14でSecurityダイアログが表示されることもありません。

AppleScript名:iTunesライブラリ中の楽曲のみしぼりこんでアルバムのtitle一覧を取得.scptd
— Created 2018-10-16 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "iTunesLibrary"

property ITLibrary : a reference to current application’s ITLibrary
property NSPredicate : a reference to current application’s NSPredicate

set library to ITLibrary’s libraryWithAPIVersion:"1.0" |error|:(missing value)
if library is equal to missing value then return

set playLists to library’s allPlaylists()
set gArray to (library’s allMediaItems())

set aPredicate to NSPredicate’s predicateWithFormat:"self.mediaKind = 2" –ITLibMediaItemMediaKindSong
set filteredArray to gArray’s filteredArrayUsingPredicate:aPredicate
set tArray to (filteredArray’s album’s title)
set bList to (tArray’s valueForKeyPath:"@distinctUnionOfObjects.self") as list
–> {"アニメる", "庄野真代ゴールデン☆ベスト: シングル・コレクション & 筒美京平作品集", "ウォンテッド(指名手配) [Original Cover Art] – Single", "君が人生の時…", "3年B組金八先生 THEME SONG COLLECTION", "HOLD ME", "Piano Stories", "にんじゃりばんばん – Single", …..}

★Click Here to Open This Script 

Posted in list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy ITLibrary iTunes NSPredicate | Leave a comment

Keynoteで指定の表をX LabelとY Labelの交差するセルにデータを設定する v2

Posted on 12月 22, 2018 by Takaaki Naganoya

オープン中のKeynote書類のうち、指定タイトルのスライド中の表の値を取得したり設定するAppleScriptです。

シート名(タイトル)、表Yラベル、表Xラベル

の3つのパラメータをもとに、Keynote書類中の指定スライドの表の中のセルにアクセスして、値を取得/設定します。

処理対象のKeynote書類はKeynoteでオープンしている必要があり、各スライド中の表は1つのみ存在していることを処理の前提条件としています。

一応、再利用性を高めるためにScriptオブジェクト化しています。これがベストな方法なわけではありませんが、こんなもんでしょう。

AppleScript名:Keynoteで指定の表をX LabelとY Labelの交差するセルに設定する v2
— Created 2018-12-20 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set targCellNameX to "Col2"
set targCellNameY to "Row4"
set storeVal to "9999"

set keynoteSlide to "Page 2 Title"

set keynoteSlideObj to getTitleStringFromFrontKeynoteDocumentFilterByString(keynoteSlide) of getKeynoteSlideKit
–set aRes to getValueOnKeynoteTableByXYLabels(targCellNameY, targCellNameX, keynoteSlideObj) of getKeynoteSlideKit
setValueOnKeynoteTableByXYLabels(targCellNameY, targCellNameX, storeVal, keynoteSlideObj) of getKeynoteSlideKit

script getKeynoteSlideKit
  –Keynote タイトル指定してslideを取得する
  
on getTitleStringFromFrontKeynoteDocumentFilterByString(targString)
    set repTargList to {string id 10, string id 11, string id 13} –LF,CR,VTab一括置換
    
    
tell application "Keynote"
      if (count every document) = 0 then return
      
      
tell front document
        set tList to object text of default title item of every slide
      end tell
    end tell
    
    
–タイトルごとにゴミ取り(改行文字の削除)
    
set outList to {}
    
set sCount to 1
    
set hitF to false
    
repeat with i in tList
      set j1 to contents of i
      
set jTmp to (paragraphs of j1) as string –しつこい改行文字(?)を除去するための処理
      
      
set j2 to replaceTextMultiple(jTmp, repTargList, "") of me as string
      
if j2 is equal to targString then
        set hitF to true
        
exit repeat
      end if
      
      
set sCount to sCount + 1
    end repeat
    
    
if hitF = false then return false
    
    
tell application "Keynote"
      tell front document
        return item sCount of (every slide)
      end tell
    end tell
    
  end getTitleStringFromFrontKeynoteDocumentFilterByString
  
  
  
–リストを指定デリミタで区切ったテキストに変換
  
on listToStringUsingTextItemDelimiter(sourceList as list, textItemDelimiter as string)
    set anArray to current application’s NSArray’s arrayWithArray:sourceList
    
set aString to anArray’s componentsJoinedByString:textItemDelimiter
    
return (aString as string)
  end listToStringUsingTextItemDelimiter
  
  
  
–任意のデータから特定の文字列を複数パターン一括置換
  
on replaceTextMultiple(origData as string, origTexts as list, repText as string)
    set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to origTexts
    
set origData to text items of origData
    
set AppleScript’s text item delimiters to {repText}
    
set origData to origData as text
    
set AppleScript’s text item delimiters to curDelim
    
return origData
  end replaceTextMultiple
  
  
–行ラベルと列ラベルを個別に指定し、交点のセルに指定の値を入れる
  
on setValueOnKeynoteTableByXYLabels(targCellNameY, targCellNameX, storeVal, keynoteSlideObj)
    tell application "Keynote"
      tell keynoteSlideObj
        tell table 1
          
          
tell row 1
            set cList to value of every cell
            
set xRes to getOffsetFromList(targCellNameX, cList) of me
          end tell
          
          
tell column 1
            set dList to value of every cell
            
set yRes to getOffsetFromList(targCellNameY, dList) of me
          end tell
          
          
tell row yRes
            tell cell xRes
              set its value to storeVal
            end tell
          end tell
          
        end tell
      end tell
    end tell
  end setValueOnKeynoteTableByXYLabels
  
  
  
–行ラベルと列ラベルを個別に指定し、交点のセルに指定の値を入れる
  
on getValueOnKeynoteTableByXYLabels(targCellNameY, targCellNameX, keynoteSlideObj)
    tell application "Keynote"
      tell keynoteSlideObj
        tell table 1
          
          
tell row 1
            set cList to value of every cell
            
set xRes to getOffsetFromList(targCellNameX, cList) of me
          end tell
          
          
tell column 1
            set dList to value of every cell
            
set yRes to getOffsetFromList(targCellNameY, dList) of me
          end tell
          
          
tell row yRes
            tell cell xRes
              set tmpFormat to format
              
set its format to text
              
set aRes to its value
              
set its format to tmpFormat
              
              
if aRes = missing value then
                return ""
              else
                return aRes
              end if
            end tell
          end tell
          
        end tell
      end tell
    end tell
  end getValueOnKeynoteTableByXYLabels
  
  
  
on getOffsetFromList(aTarg, aList)
    using terms from scripting additions
      set aRes to offset of aTarg in aList
    end using terms from
    
return aRes
  end getOffsetFromList
  
  
  
  
—-Offset command overwrapper
  
on offset of bArg in anArg
    set aClass to class of anArg
    
set bClass to class of bArg
    
    
if {aClass, bClass} = {text, text} then –case 1
      return getOffset(anArg, bArg) of me
    else if {aClass, bClass} = {list, list} then –case 2 (The target case)
      return execOffsetList(bArg, anArg) of me
    else if {aClass, bClass} = {text, list} then –case 3 (Illegular case)
      return execOffsetList(bArg, {anArg}) of me
    else if {aClass, bClass} = {list, text} then –case 4 (Illegular case)
      return execOffsetList({bArg}, anArg) of me
    end if
  end offset
  
  
  
–1D List同士のoffset演算を行うルーチンの本体
  
on execOffsetList(aList as list, bList as list)
    set resList to {}
    
repeat with i in aList
      set j to contents of i
      
set aCount to 1
      
      
repeat with ii in bList
        set jj to contents of ii
        
if jj = j then
          set the end of resList to aCount
          
exit repeat
        end if
        
set aCount to aCount + 1
      end repeat
    end repeat
    
    
–見つかったItem No.が連続値かどうかチェック
    
set sRes to chkSequential(resList) of me
    
if sRes = true then
      return contents of first item of resList
    else
      return false
    end if
  end execOffsetList
  
  
  
–与えられた1D Listが連続値かどうかをチェックする
  
on chkSequential(aList)
    if length of aList = 1 then return true
    
if aList = {} then return false
    
    
set aFirst to first item of aList
    
set aList to rest of aList
    
    
repeat with i in aList
      set j to contents of i
      
if j is not equal to (aFirst + 1) then
        return false
      end if
      
copy j to aFirst
    end repeat
    
    
return true
  end chkSequential
  
  
  
–テキスト同士のoffset ofを(2.5x fasterで)実行する
  
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
  
end script

★Click Here to Open This Script 

Posted in list Text | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote NSArray | Leave a comment

タイトルを指定して該当するKeynoteのスライドにアクセス

Posted on 12月 22, 2018 by Takaaki Naganoya

オープン中のKeynote書類のうち、指定タイトルのスライドを取得するAppleScriptです。

Keynoteには、ページにScript Labelを付ける機能が用意されておらず、一意にスライドを指定する方法がありません。先頭から●ページ目、というアクセスはできますが、それだけのことです。

そこで、各スライドのタイトルを指定して、該当するタイトルを持つスライドを取得するAppleScriptを作成して使用しています。ただし、タイトルについては途中に強制改行が入っていたりするケースもあるので、改行を削除した状態に変換してから指定文字列とのマッチングを行っています。

ただし、表紙のタイトルに長い題名を入力した場合など、ユーザーが意図して入れたものではない改行が途中で入ることもあるため、そのあたりでいろいろゴニョゴニョと改行削除のための悪あがきをしています。

さらに、スライド上の表(table)の指定文字のヘッダーのセルのデータを取り出したり、設定したりするScriptを作成し、最終的にはこれらを配列変数のようにパラメータを指定するだけでストレージ的にアクセスできるようにルーチンを整備しました。

AppleScript名:タイトルを指定して該当するスライドにアクセス.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/12/21
—
–  Copyright © 2018 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5" — El Capitan (10.11) or later
use framework "Foundation"
use scripting additions

set keynoteSlideObj to getSlideFromFrontKeynoteDocumentByTitleString("用途別のフレームワークを知ろう") of me
–> slide 4 of document id "EFC0FE62-C92E-471E-82C7-DE7298AB083C"

if keynoteSlideObj = false then return

tell application "Keynote"
  tell keynoteSlideObj
    properties
  end tell
end tell

–Keynote タイトル指定してslideを取得する
on getSlideFromFrontKeynoteDocumentByTitleString(targString)
  set repTargList to {string id 10, string id 11, string id 13} –LF,CR,VTab一括置換
  
  
tell application "Keynote"
    if (count every document) = 0 then return false
    
    
tell front document
      set tList to object text of default title item of every slide
    end tell
  end tell
  
  
–タイトルごとにゴミ取り(改行文字の削除)
  
set outList to {}
  
set sCount to 1
  
set hitF to false
  
  
repeat with i in tList
    set j1 to contents of i
    
set jTmp to (paragraphs of j1) as string –しつこい改行文字(?)を除去するための処理
    
    
set j2 to replaceTextMultiple(jTmp, repTargList, "") of me as string
    
if j2 is equal to targString then
      set hitF to true
      
exit repeat
    end if
    
    
set sCount to sCount + 1
  end repeat
  
  
if hitF = false then return false
  
  
tell application "Keynote"
    tell front document
      return item sCount of (every slide)
    end tell
  end tell
  
end getSlideFromFrontKeynoteDocumentByTitleString

–リストを指定デリミタで区切ったテキストに変換
on listToStringUsingTextItemDelimiter(sourceList as list, textItemDelimiter as string)
  set anArray to current application’s NSArray’s arrayWithArray:sourceList
  
set aString to anArray’s componentsJoinedByString:textItemDelimiter
  
return (aString as string)
end listToStringUsingTextItemDelimiter

–任意のデータから特定の文字列を複数パターン一括置換
on replaceTextMultiple(origData as string, origTexts as list, repText as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to origTexts
  
set origData to text items of origData
  
set AppleScript’s text item delimiters to {repText}
  
set origData to origData as text
  
set AppleScript’s text item delimiters to curDelim
  
return origData
end replaceTextMultiple

★Click Here to Open This Script 

Posted in list Text | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote | Leave a comment

InputManagerでIMを切り換える v2

Posted on 12月 20, 2018 by Takaaki Naganoya

InputManager.frameworkを呼び出して、日本語入力Input Methodの入力文字の切り替えを行うAppleScriptです。

–> Demo Movie

macOS標準装備のスクリプトエディタ上ではControl-Command-Rで実行できましたが、Script Debugger上で動かなかった(メインスレッド上で強制実行する必要があった)ので、切り替えメソッドを強制的にメインスレッド上で実行するように変更してみました。

–> InputManager.framework (To ~/Library/Frameworks)

macOS 10.14上で実行する場合には、(フレームワーク呼び出しの都合上)Script Debugger上で実行してください。

AppleScript名:InputManagerでIMを切り換える v2
— Created 2017-01-22 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "InputManager" –https://github.com/jensnockert/input-manager

–Caution: This script runs on only Japanese language environment

set cList to current application’s CSInputSource’s all()
set dList to (cList’s valueForKey:"localizedName")
set aRes to ((dList’s indexOfObject:"ひらがな") as integer) –"Hiragana" in Japanese
set bRes to ((dList’s indexOfObject:"英字") as integer) –"English Letters" in Japanese

set hiraKey to cList’s objectAtIndex:aRes
set engKey to cList’s objectAtIndex:bRes

repeat 3 times
  my performSelectorOnMainThread:"selectInputCharMode:" withObject:(hiraKey) waitUntilDone:true
  
delay 1
  
my performSelectorOnMainThread:"selectInputCharMode:" withObject:(engKey) waitUntilDone:true
  
delay 1
end repeat

–Force execute on Main Thread
on selectInputCharMode:aModeObj
  aModeObj’s |select|()
end selectInputCharMode:

★Click Here to Open This Script 

Posted in Input Method Language | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy | 1 Comment

1D Listのうち指定文字種で構成される要素のみ抽出

Posted on 12月 20, 2018 by Takaaki Naganoya

1D List(配列)に入れた文字要素を文字種類で該当するものだけ抽出するAppleScriptです。

文字種類でデータ抽出する、という用途はけっこう多いので、単体で使えるようにしておきました。プログラムを見ていただくとわかるとおり、

 数字:”9″
 英字:”A”
 半角記号:”$”
 ひらがな:”ひ”
 カタカナ:”カ”
 漢字:”漢”

で文字種類を指定します。

以前のバージョンではありもののルーチンを組み合わせただけなので、全体的に無駄があって処理速度についてはあまり感心できないレベルだったので、若干の高速化を図りました(繰り返し処理部分で無駄な演算を省略)。

ただし、「ひらがな+カタカナは許容する」というふうに、複数の文字種を許可する例が多いので、これではまだ実用レベルには達していないと思います。

AppleScript名:1D Listのうち指定文字種で構成される要素のみ抽出
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/12/20
—
–  Copyright © 2018 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property NSString : a reference to current application’s NSString
property NSScanner : a reference to current application’s NSScanner
property NSNumber : a reference to current application’s NSNumber
property NSDictionary : a reference to current application’s NSDictionary
property NSCountedSet : a reference to current application’s NSCountedSet
property NSCharacterSet : a reference to current application’s NSCharacterSet
property NSMutableArray : a reference to current application’s NSMutableArray
property NSNumberFormatter : a reference to current application’s NSNumberFormatter
property NSMutableCharacterSet : a reference to current application’s NSMutableCharacterSet
property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch
property NSNumberFormatterRoundUp : a reference to current application’s NSNumberFormatterRoundUp
property NSStringTransformFullwidthToHalfwidth : a reference to current application’s NSStringTransformFullwidthToHalfwidth

set aList to {"Naganoya", "ながのや", "ナガノヤ", "長野谷"} –Alphabet, Hiragana, Katakana, Kanji

set aRes to filterByCharKind(aList, "A") of me –アルファベットで構成される要素のみ抽出
–> {"Naganoya"}

set bRes to filterByCharKind(aList, "ひ") of me –ひらがなだけで構成される要素のみ抽出
–> {"ながのや"}

set cRes to filterByCharKind(aList, "カ") of me –カタカナだけで構成される要素のみ抽出
–> {"ナガノヤ"}

set dRes to filterByCharKind(aList, "漢") of me –漢字だけで構成される要素のみ抽出
–> {"長野谷"}

–文字種別を判定して指定文字種のみから構成されるものを抽出
on filterByCharKind(aList as list, targCharKind as string)
  set dList to {}
  
repeat with i in aList
    set j to contents of i
    
set tmpPat to retAtrPatternFromStr(j) of me
    
if tmpPat is equal to {targCharKind} then
      set the end of dList to j
    end if
  end repeat
  
  
return dList
end filterByCharKind

–Objective-Cライクなパラメータ記述
on makeUniqueListOf:theList
  set theSet to current application’s NSOrderedSet’s orderedSetWithArray:theList
  
return (theSet’s array()) as list
end makeUniqueListOf:

–Pure AS風のパラメータ記述
on makeUniqueListFrom(theList)
  set aList to my makeUniqueListOf:theList
  
return aList
end makeUniqueListFrom

–1D Listを文字列長でソート v2
on sort1DListByStringLength(aList as list, sortOrder as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:aList
  
set desc1 to current application’s NSSortDescriptor’s sortDescriptorWithKey:"length" ascending:sortOrder
  
set desc2 to current application’s NSSortDescriptor’s sortDescriptorWithKey:"self" ascending:true selector:"localizedCaseInsensitiveCompare:"
  
set bArray to aArray’s sortedArrayUsingDescriptors:{desc1, desc2}
  
return bArray as list of string or string
end sort1DListByStringLength

–文字種別の判定
on retAtrPatternFromStr(aText as string)
  set b1List to {"9", "A", "$", "漢", "ひ", "カ"} –数字、アルファベット、記号、全角漢字、全角ひらがな、全角カタカナ
  
  
–set cStr to zenToHan(aText) of me
  
  
set outList to {}
  
set cList to characters of (aText)
  
  
repeat with i in cList
    set j to contents of i
    
    
set chk1 to ((my chkNumeric:j) as integer) * 1
    
set chk2 to ((my chkAlphabet:j) as integer) * 2
    
set chk3 to ((my chkSymbol:j) as integer) * 3
    
set chk4 to ((my chkKanji:j) as integer) * 4
    
set chk5 to ((my chkHiragana:j) as integer) * 5
    
set chk6 to ((my chkKatakana:j) as integer) * 6
    
    
set itemVal to (chk1 + chk2 + chk3 + chk4 + chk5 + chk6)
    
    
–if itemVal > 0 then
    
set aVal to (contents of item itemVal of b1List)
    
    
if aVal is not in outList then
      set the end of outList to aVal
    end if
    
–end if
  end repeat
  
  
return outList
end retAtrPatternFromStr

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

–数字か
on chkNumeric:checkString
  set digitCharSet to NSCharacterSet’s characterSetWithCharactersInString:"0123456789"
  
set ret to my chkCompareString:checkString baseString:digitCharSet
  
return ret as boolean
end chkNumeric:

–記号か
on chkSymbol:checkString
  set muCharSet to NSCharacterSet’s alloc()’s init()
  
muCharSet’s addCharactersInString:"$\"!~&=#[]._-+`|{}?%^*/’@-/:;(),"
  
set ret to my chkCompareString:checkString baseString:muCharSet
  
return ret as boolean
end chkSymbol:

–漢字か
on chkKanji:aChar
  return detectCharKind(aChar, "[一-龠]") of me
end chkKanji:

–ひらがなか
on chkHiragana:aChar
  return detectCharKind(aChar, "[ぁ-ん]") of me
end chkHiragana:

–カタカナか
on chkKatakana:aChar
  return detectCharKind(aChar, "[ァ-ヶ]") of me
end chkKatakana:

–半角スペースか
on chkSpace:checkString
  set muCharSet to NSCharacterSet’s alloc()’s init()
  
muCharSet’s addCharactersInString:" " –半角スペース(20h)
  
set ret to my chkCompareString:checkString baseString:muCharSet
  
return ret as boolean
end chkSpace:

— アルファベットか
on chkAlphabet:checkString
  set aStr to NSString’s stringWithString:checkString
  
set allCharSet to NSMutableCharacterSet’s alloc()’s init()
  
allCharSet’s addCharactersInRange:({location:97, |length|:26}) –97 = id of "a"
  
allCharSet’s addCharactersInRange:({location:65, |length|:26}) –65 = id of "A"
  
set aBool to my chkCompareString:aStr baseString:allCharSet
  
return aBool as boolean
end chkAlphabet:

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

on detectCharKind(aChar, aPattern)
  set aChar to NSString’s stringWithString:aChar
  
set searchStr to NSString’s stringWithString:aPattern
  
set matchRes to aChar’s rangeOfString:searchStr options:(NSRegularExpressionSearch)
  
if matchRes’s location() = (current application’s NSNotFound) or (matchRes’s location() as number) > 9.99999999E+8 then
    return false
  else
    return true
  end if
end detectCharKind

★Click Here to Open This Script 

Posted in list regexp Text | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSCharacterSet NSCountedSet NSDictionary NSMutableArray NSMutableCharacterSet NSNumber NSNumberFormatter NSNumberFormatterRoundUp NSRegularExpressionSearch NSScanner NSString NSStringTransformFullwidthToHalfwidth | Leave a comment

住所録から苗字を抽出して1文字以上の苗字をリスト出力

Posted on 12月 20, 2018 by Takaaki Naganoya

固有名詞を抽出するために、住所録から苗字を抽出して1文字以上の長さの苗字をリスト出力するAppleScriptです。

簡易形態素解析を行うさいに、みのまわりの人物の苗字を認識してくれないと知性を感じられないため(例:”長野”,”谷”)、逆に住所録に登録があるぐらい身の回りの人物の苗字を固有名詞として認識してくれるよう、住所録から苗字を抽出させてみました。

抽出した苗字は、missing valueが返ってきたものを除去し、重複を排除し、文字列長でソートして長いものから短いものへと並べ替え。

さらに、文字種別を判定して漢字のみで構成されているものを抽出。さらに、1文字の苗字を排除。

こうして得られたリストの先頭に自分の苗字を入れて、真っ先に自分の名前が認識されるようにしてみました。

住所録へのアクセスは、macOS標準装備の「連絡先.app」にアクセスしてみました。最近はmacOS標準装備のFrameworkにアクセスしてこの手のデータを取得していたりしましたが、その際に利用していたAddressBook.frameworkが廃止になる見込みであるため、新設されたContacts.frameworkを使ったほうが好ましいところです。

ただ、Contacts.frameworkの各種メソッドはObjective-CのBlocks構文の記述を必要とするため、AppleScriptからそのまま呼び出すことができません。

そのため、連絡先.app(Contacts.app)にアクセスすることになった次第です。

固有名詞抽出については、簡易形態素解析を実行するたびに実行するのではなく、1日に1回ぐらいの頻度で実行すればよいと考えています。

AppleScript名:住所録から苗字を抽出して1文字以上の苗字をリスト出力
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/12/20
—
–  Copyright © 2018 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use bPlus : script "BridgePlus"

property NSString : a reference to current application’s NSString
property NSScanner : a reference to current application’s NSScanner
property NSNumber : a reference to current application’s NSNumber
property NSDictionary : a reference to current application’s NSDictionary
property NSCountedSet : a reference to current application’s NSCountedSet
property NSCharacterSet : a reference to current application’s NSCharacterSet
property NSMutableArray : a reference to current application’s NSMutableArray
property NSNumberFormatter : a reference to current application’s NSNumberFormatter
property NSMutableCharacterSet : a reference to current application’s NSMutableCharacterSet
property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch
property NSNumberFormatterRoundUp : a reference to current application’s NSNumberFormatterRoundUp
property NSStringTransformFullwidthToHalfwidth : a reference to current application’s NSStringTransformFullwidthToHalfwidth

tell application "Contacts"
  set lastNames to last name of every person
  
set myName to last name of my card
end tell

load framework

–Remove missing value (Cleaning)
set aList to (current application’s SMSForder’s arrayByDeletingBlanksIn:(lastNames)) as list

–重複部分の削除
set bList to makeUniqueListFrom(aList) of me

–文字列長でソート。長い文字列→短い文字列
set cList to sort1DListByStringLength(bList, false) of me –降順

–文字種別を判定して漢字のみから構成されるものを抽出し、1文字のものを除外
set dList to {}
repeat with i in cList
  set j to contents of i
  
set tmpPat to retAtrPatternFromStr(j) of me
  
if tmpPat is equal to "漢" then
    –1文字以上の苗字のみ出力
    
if length of j > 1 then
      set the end of dList to j
    end if
  end if
end repeat

set the beginning of dList to myName
return dList
–> {"長野谷", "久保田", "三津田", "小笠原", "上田平", "大久保", "長谷川", "長野谷", "伊賀", "伊勢","伊東", "伊藤", "井上", "稲葉" …}

–Objective-Cライクなパラメータ記述
on makeUniqueListOf:theList
  set theSet to current application’s NSOrderedSet’s orderedSetWithArray:theList
  
return (theSet’s array()) as list
end makeUniqueListOf:

–Pure AS風のパラメータ記述
on makeUniqueListFrom(theList)
  set aList to my makeUniqueListOf:theList
  
return aList
end makeUniqueListFrom

–1D Listを文字列長でソート v2
on sort1DListByStringLength(aList as list, sortOrder as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:aList
  
set desc1 to current application’s NSSortDescriptor’s sortDescriptorWithKey:"length" ascending:sortOrder
  
set desc2 to current application’s NSSortDescriptor’s sortDescriptorWithKey:"self" ascending:true selector:"localizedCaseInsensitiveCompare:"
  
set bArray to aArray’s sortedArrayUsingDescriptors:{desc1, desc2}
  
return bArray as list of string or string
end sort1DListByStringLength

–文字種別の判定
on retAtrPatternFromStr(aText)
  set a1List to {"100000", "010000", "001000", "000100", "000010", "000001"}
  
set b1List to {"9", "A", "$", "漢", "あ", "ア"} –数字、アルファベット、記号、全角漢字、全角ひらがな、全角カタカナ
  
set aDict to NSDictionary’s dictionaryWithObjects:b1List forKeys:a1List
  
  
set aStr to NSString’s stringWithString:aText
  
set bStr to aStr’s stringByDeletingPathExtension()
  
set cStr to zenToHan(bStr) of me
  
  
set outList to {}
  
set cList to characters of cStr
  
  
repeat with i in cList
    set j to contents of i
    
set chk1 to ((my chkNumeric:j) as integer) as string
    
set chk2 to ((my chkAlphabet:j) as integer) as string
    
set chk3 to ((my chkSymbol:j) as integer) as string
    
set chk4 to ((my chkKanji:j) as integer) as string
    
set chk5 to ((my chkHiragana:j) as integer) as string
    
set chk6 to ((my chkKatakana:j) as integer) as string
    
    
set allKey to (chk1 & chk2 & chk3 & chk4 & chk5 & chk6) as string
    
set aVal to (aDict’s valueForKeyPath:allKey) as string
    
    
if aVal is not in outList then
      set the end of outList to aVal
    end if
  end repeat
  
  
return outList as string
end retAtrPatternFromStr

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

–数字か
on chkNumeric:checkString
  set digitCharSet to NSCharacterSet’s characterSetWithCharactersInString:"0123456789"
  
set ret to my chkCompareString:checkString baseString:digitCharSet
  
return ret as boolean
end chkNumeric:

–記号か
on chkSymbol:checkString
  set muCharSet to NSCharacterSet’s alloc()’s init()
  
muCharSet’s addCharactersInString:"$\"!~&=#[]._-+`|{}?%^*/’@-/:;(),"
  
set ret to my chkCompareString:checkString baseString:muCharSet
  
return ret as boolean
end chkSymbol:

–漢字か
on chkKanji:aChar
  return detectCharKind(aChar, "[一-龠]") of me
end chkKanji:

–ひらがなか
on chkHiragana:aChar
  return detectCharKind(aChar, "[ぁ-ん]") of me
end chkHiragana:

–カタカナか
on chkKatakana:aChar
  return detectCharKind(aChar, "[ァ-ヶ]") of me
end chkKatakana:

–半角スペースか
on chkSpace:checkString
  set muCharSet to NSCharacterSet’s alloc()’s init()
  
muCharSet’s addCharactersInString:" " –半角スペース(20h)
  
set ret to my chkCompareString:checkString baseString:muCharSet
  
return ret as boolean
end chkSpace:

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

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

on detectCharKind(aChar, aPattern)
  set aChar to NSString’s stringWithString:aChar
  
set searchStr to NSString’s stringWithString:aPattern
  
set matchRes to aChar’s rangeOfString:searchStr options:(NSRegularExpressionSearch)
  
if matchRes’s location() = (current application’s NSNotFound) or (matchRes’s location() as number) > 9.99999999E+8 then
    return false
  else
    return true
  end if
end detectCharKind

★Click Here to Open This Script 

Posted in list Natural Language Processing Record Sort | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Contacts | Leave a comment

easyJParse v4

Posted on 12月 14, 2018 by Takaaki Naganoya

簡易的な日本語テキストのParse(辞書なし)を行うAppleScriptです。

詳細な説明はこちら。

本バージョンでは、かっこ( “「”, “」”, “『”, “』”, “【”, “】”, “《”, “》”, “〈”, “〉”, “(”, “))で区切られた文字列を区分けしないで1かたまりで出力させたものです。

コマンド解釈用に作成した本Script、パラメーターとして区分けしてほしくない情報(フィールド情報やデータベース名など)をかたまりのまま出力する必要があって、そのように処理させてみました。

かっこがクロスしたりネスティング(入れ子)していることは検出していますが、そのまま連結せずに出力しています。

このプログラムを作ったことにより、固有名詞への対応のメドが立ちました。

前処理で何かの記号で固有名詞を囲えばいいんじゃないか、などと思っています。何を固有名詞とするか、ということになりますが、とりあえず住所録(Contacts.app)から人名(Last Name)や会社名をすべて出力させるのがよいだろうか、といったところです。

AppleScript名:easyJParse v4(かぎかっこ内の単語を1つの単語としてみなす)
— Created 2018-09-26 by Takaaki Naganoya
— Modified 2018-12-14 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5" — El Capitan (10.11) or later
use framework "Foundation"
use scripting additions
use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

property NSArray : a reference to current application’s NSArray
property NSSortDescriptor : a reference to current application’s NSSortDescriptor

load framework
set aTargName to "曲のアーティスト名を変更"
–set aTargName to "<満喜子>さんの実家から半径300メートル以内にあるコンビニを取得"
–set aTargName to "Finderで選択中のAI書類上の「製品名」レイヤーから抜き出したコードをもとにスペック情報をGoogle Spreadsheet「製品コード表」から展開して保存。"
set aList to parseJ(aTargName, true) of me
–> {"Finder", "で", "選択", "中", "の", "AI", "書類", "上", "の", "「", "製品名", "」", "レイヤー", "から", "抜き出し", "た", "コード", "を", "もと", "に", "スペック", "情報", "を", "Google", " ", "Spreadsheet", "「", "製品コード表", "」", "から", "展開", "し", "て", "保存", "。"}
return aList

set aTargName to "私の名前は「長野谷」です。"
set aList to parseJ(aTargName, true) of me
–> {"私", "の", "名前", "は", "「", "長野谷", "」", "です", "。"}

–カッコのネスティングとクロス(エラー)については、処理せずにそのまま出力
on parseJ(aTargStr as string, pickupPhraseByBracketPair as boolean)
  copy aTargStr to tStr
  
  
set cList to characters of tStr
  
set wList to words of tStr
  
  
set cLen to length of cList
  
  
set w2List to {}
  
set w3List to {}
  
set aCount to 0
  
  
set lastPos to 0
  
  
repeat with i in wList
    set j to contents of i
    
    
using terms from scripting additions
      set anOffset to offset of j in tStr
    end using terms from
    
    
if anOffset is not equal to 1 then
      set aChar to character (lastPos + 1) of aTargStr
      
      
set the end of w3List to {wordList:aChar, characterList:{aChar}, startPos:(lastPos + 1), endPos:(lastPos + 1)}
    end if
    
    
set aLen to length of j
    
    
set w2List to w2List & (characters of j)
    
set startPointer to (anOffset + aCount)
    
set endPointer to (anOffset + aCount + aLen – 1)
    
    
set the end of w3List to {wordList:j, characterList:(characters of j), startPos:startPointer, endPos:endPointer}
    
    
set trimStart to (anOffset + aLen)
    
    
if trimStart > (length of tStr) then
      set trimStart to 1
    end if
    
    
set tStr to text trimStart thru -1 of tStr
    
    
set aCount to aCount + anOffset + aLen – 1
    
copy endPointer to lastPos
  end repeat
  
  
–句読点など。文末の処理
  
if endPointer is not equal to cLen then
    set the end of w3List to {wordList:tStr, characterList:(characters of tStr), startPos:(lastPos + aCount), endPos:aLen}
  end if
  
  
set bArray to sortRecListByLabel((w3List), "startPos", true) of me
  
set cArray to (bArray’s valueForKeyPath:"wordList") as list
  
  
–カッコでくくった範囲を1つの塊として連結する
  
set bracketList to {"「", "」", "『", "』", "【", "】", "《", "》", "〈", "〉", "(", ")"}
  
set bList to jointItemsBetweenBrackets(cArray, bracketList) of me
  
  
return bList
end parseJ

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

on offset of bArg in anArg
  set aClass to class of anArg
  
set bClass to class of bArg
  
  
if {aClass, bClass} = {text, text} then –case 1
    return getOffset(anArg, bArg) of me
  else if {aClass, bClass} = {list, list} then –case 2 (The target case)
    return execOffsetList(bArg, anArg) of me
  else if {aClass, bClass} = {text, list} then –case 3 (Illegular case)
    return execOffsetList(bArg, {anArg}) of me
  else if {aClass, bClass} = {list, text} then –case 4 (Illegular case)
    return execOffsetList({bArg}, anArg) of me
  end if
end offset

–1D List同士のoffset演算を行うルーチンの本体
on execOffsetList(aList as list, bList as list)
  set resList to {}
  
repeat with i in aList
    set j to contents of i
    
set aCount to 1
    
    
repeat with ii in bList
      set jj to contents of ii
      
if jj = j then
        set the end of resList to aCount
        
exit repeat
      end if
      
set aCount to aCount + 1
    end repeat
  end repeat
  
  
–見つかったItem No.が連続値かどうかチェック
  
set sRes to chkSequential(resList) of me
  
if sRes = true then
    return contents of first item of resList
  else
    return false
  end if
end execOffsetList

–与えられた1D Listが連続値かどうかをチェックする
on chkSequential(aList)
  if length of aList = 1 then return true
  
if aList = {} then return false
  
  
set aFirst to first item of aList
  
set aList to rest of aList
  
  
repeat with i in aList
    set j to contents of i
    
if j is not equal to (aFirst + 1) then
      return false
    end if
    
copy j to aFirst
  end repeat
  
  
return true
end chkSequential

–テキスト同士のoffset ofを(2.5x fasterで)実行する
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

–カッコでくくった範囲を1つの塊として連結する
on jointItemsBetweenBrackets(aList as list, bracketList as list)
  load framework
  
  
–リスト内のブラケット位置の検出
  
set aRes to (current application’s SMSForder’s indexesOfItems:bracketList inArray:aList inverting:false) as list
  
–> {9, 12, 15, 18, 22, 25, 27, 29}–0 based
  
  
if aRes = {} then return aList
  
  
–位置情報リストを開始位置, 終了位置のペアの2D Listに変換する
  
set cList to (current application’s SMSForder’s subarraysFrom:(aRes) groupedBy:2 |error|:(missing value)) as list
  
–> {{9, 12}, {15, 18}, {22, 25}, {27, 29}}–0 based
  
  
–カッコの位置がクロスしていないかチェック(入れ子状態はエラーになる)
  
set dRes to checkCrossRange(cList) of me
  
if dRes = false then return aList
  
  
set ccList to reverse of cList –順次、ブラケットに囲まれた要素を連結していくので、アイテム数が随時変化する。アイテム番号が狂わないよう後方から処理する必要がある。そのために、リストの要素を逆順に組み替える
  
–> {{27, 29}, {22, 25}, {15, 18}, {9, 12}}–0 based
  
  
—
  
copy aList to aaList
  
  
repeat with i in ccList
    copy i to {s2Dat, e2Dat}
    
    
set s2Dat to s2Dat + 1 –Array index conversion from 0 to 1 based
    
set e2Dat to e2Dat + 1 –Array index conversion from 0 to 1 based
    
    
set tmp1 to items 1 thru s2Dat of aaList
    
set tmp2 to (items (s2Dat + 1) thru (e2Dat – 1) of aaList) as string
    
set tmp3 to items e2Dat thru -1 of aaList
    
    
set aaList to tmp1 & tmp2 & tmp3
  end repeat
  
  
return aaList
end jointItemsBetweenBrackets

–{始点, 終点}のペアの2D Listが違いにクロスしていないかチェック
on checkCrossRange(aList as list)
  set rList to {}
  
repeat with i in aList
    copy i to {sRange, eRange}
    
set tmpRange to current application’s NSMakeRange(sRange, eRange – sRange + 1)
    
set the end of rList to tmpRange
  end repeat
  
  
repeat with ii in rList
    set jj to contents of ii
    
repeat with i in rList
      set j to contents of i
      
      
if jj is not equal to j then
        set aRes to current application’s NSIntersectionRange(jj, j)
        
        
if aRes is not equal to {location:0, |length|:0} then
          return false
        end if
      end if
      
    end repeat
  end repeat
  
  
return true
end checkCrossRange

★Click Here to Open This Script 

Posted in list Natural Language Processing Text | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy 10.15savvy 11.0savvy | 1 Comment

{始点, 終点}の2D Listがお互いにクロスしていないかチェック

Posted on 12月 14, 2018 by Takaaki Naganoya

{始点, 終点}のペアからなる2D Listがお互いにクロスしていないかチェックするAppleScriptです。

{{9, 12}, {15, 18}, {17, 25}, {27, 29}}

のような場合には、NG(false)。

 {{9, 12}, {15, 18}, {19, 25}, {27, 29}}

のような場合には、OK(true)と判定します。

{{9, 12}, {15, 18}, {18, 25}, {27, 29}}

のように、接している場合にもNG(false)と判定します。

もともとの用途は、

あいうえお「かきく『けこ」さしす』せそ

のように、本来記述してはいけないカッコの記法が行われたことを検出するものです。

ただし、文法的には本来許容すべきカッコのネスティング

あいうえお「かきく『けこ』さしす」せそ

についてもエラー検出してしまっているので、その点は一考の余地がありそうです。

AppleScript名:{始点, 終点}の2D Listがお互いにクロスしていないかチェック.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/12/14
—
–  Copyright © 2018 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set aList to {{9, 12}, {15, 18}, {17, 25}, {27, 29}}
set aRes to checkCrossRange(aList) of me
–> false

set bList to {{9, 12}, {15, 18}, {18, 25}, {27, 29}}
set bRes to checkCrossRange(bList) of me
–> false

set cList to {{9, 12}, {15, 18}, {19, 25}, {27, 29}}
set cRes to checkCrossRange(cList) of me
–> true

–{始点, 終点}のペアの2D Listが違いにクロスしていないかチェック
on checkCrossRange(aList as list)
  set rList to {}
  
repeat with i in aList
    copy i to {sRange, eRange}
    
set tmpRange to current application’s NSMakeRange(sRange, eRange – sRange + 1)
    
set the end of rList to tmpRange
  end repeat
  
  
repeat with ii in rList
    set jj to contents of ii
    
repeat with i in rList
      set j to contents of i
      
      
if jj is not equal to j then
        set aRes to current application’s NSIntersectionRange(jj, j)
        
        
if aRes is not equal to {location:0, |length|:0} then
          return false
        end if
      end if
      
    end repeat
  end repeat
  
  
return true
end checkCrossRange

★Click Here to Open This Script 

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

offset of list in list v3

Posted on 12月 14, 2018 by Takaaki Naganoya

1D List(Array)中における指定項目の出現位置(offset)を求めるAppleScriptです。標準命令「offset of ① in ②」を拡張して、本来はテキスト同士の処理であったものを、リスト同士で処理するようにしています。

サポートしているのは4つのパターンです。

(1)offset of string1 in string2

標準パターンですが、例によって標準命令よりも2.5倍速に高速化してあります。

(2)offset of list1 in list2

想定ターゲットのパターンです。1D Listと1D Listのoffsetを計算します。

(3)offset of list1 in string2

(2)を指定しようとして間違ったケースです。

(4)offset of string1 in list2

ASOC(use framework “Foundation”宣言時)では、そのままではoffset命令がだましにくくなるので(パラメータが文字列ではないとしてエラーになる)、using terms from scripting additionsで囲う必要がありました。

パラメータにヌルリストを指定した場合に、エラーになる件を修正(chkSequential)してあります。

AppleScript名:offset of list in list v3
— Created 2018-09-18 by Takaaki Naganoya
— Modified 2018-12-14 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

–case 1
using terms from scripting additions –ここ、AppleScriptObjC(use framework "Foundation"宣言時)では必要になる
  set bRes to offset of "a" in "bcdefa"
end using terms from
–> 6

–case 2 (The target case)
set aTargList to {"Finder", "で", "選択", "中", "の", "AI", "書類", "上", "の", "「", "製品", "名", "」", "レイヤー", "から", "抜き出し", "た", "コード", "を", "もと", "に", "スペック", "情報", "を", "Google", " ", "Spreadsheet", "から", "展開", "し", "て", "保存", "。"}
set bList to {"の", "メニュー", "で"}
using terms from scripting additions
  set aRes to offset of bList in aTargList
end using terms from
–> 2

–case 3 (Illegular case)
set aTargList to {"Finder", "で", "選択", "中", "の", "AI", "書類", "上", "の", "「", "製品", "名", "」", "レイヤー", "から", "抜き出し", "た", "コード", "を", "もと", "に", "スペック", "情報", "を", "Google", " ", "Spreadsheet", "から", "展開", "し", "て", "保存", "。"}
set bList to "で"
using terms from scripting additions
  set aRes to offset of bList in aTargList
end using terms from
–> 4

–case 4 (Illegular case)
set aTargList to "で"
set bList to {"で"}
using terms from scripting additions
  set aRes to offset of bList in aTargList
end using terms from
—> 1

–case 3a (Illegular case)
set aTargList to {}
set bList to "で"
using terms from scripting additions
  set aRes to offset of bList in aTargList
end using terms from
–> false

–case 2a (The target case)
set aTargList to {"Finder", "で", "選択", "中", "の", "AI", "書類", "上", "の", "「", "製品", "名", "」", "レイヤー", "から", "抜き出し", "た", "コード", "を", "もと", "に", "スペック", "情報", "を", "Google", " ", "Spreadsheet", "から", "展開", "し", "て", "保存", "。"}
set bList to {}
using terms from scripting additions
  set aRes to offset of bList in aTargList
end using terms from
–> false

on offset of bArg in anArg
  set aClass to class of anArg
  
set bClass to class of bArg
  
  
if {aClass, bClass} = {text, text} then –case 1
    return getOffset(anArg, bArg) of me
  else if {aClass, bClass} = {list, list} then –case 2 (The target case)
    return execOffsetList(bArg, anArg) of me
  else if {aClass, bClass} = {text, list} then –case 3 (Illegular case)
    return execOffsetList(bArg, {anArg}) of me
  else if {aClass, bClass} = {list, text} then –case 4 (Illegular case)
    return execOffsetList({bArg}, anArg) of me
  end if
end offset

–1D List同士のoffset演算を行うルーチンの本体
on execOffsetList(aList as list, bList as list)
  set resList to {}
  
repeat with i in aList
    set j to contents of i
    
set aCount to 1
    
    
repeat with ii in bList
      set jj to contents of ii
      
if jj = j then
        set the end of resList to aCount
        
exit repeat
      end if
      
set aCount to aCount + 1
    end repeat
  end repeat
  
  
–見つかったItem No.が連続値かどうかチェック
  
set sRes to chkSequential(resList) of me
  
if sRes = true then
    return contents of first item of resList
  else
    return false
  end if
end execOffsetList

–与えられた1D Listが連続値かどうかをチェックする
on chkSequential(aList)
  if length of aList = 1 then return true
  
if aList = {} then return false
  
  
set aFirst to first item of aList
  
set aList to rest of aList
  
  
repeat with i in aList
    set j to contents of i
    
if j is not equal to (aFirst + 1) then
      return false
    end if
    
copy j to aFirst
  end repeat
  
  
return true
end chkSequential

–テキスト同士のoffset ofを(2.5x fasterで)実行する
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 

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

1Dリストの内容が連続値かどうかチェック v2

Posted on 12月 14, 2018 by Takaaki Naganoya

1D List(Array)の内容が数値の連続値かどうかチェックするAppleScriptです。

地味ですが、超一級に重要な部品です。このルーチンが存在することで、1D List同士の要素の存在確認を手軽に行えています。

いろいろ便利に使っていたのですが、引数のリストが要素数=0のヌルリスト({})を渡した場合にエラーになることがわかったので、そのエラー対処を追加しています。

AppleScript名:1Dリストの内容が連続値かどうかチェック v2
set aList to {2, 3, 4}
set aRes to chkSequential(aList) of me
–> true

set aList to {}
set aRes to chkSequential(aList) of me
–> false

–与えられた1D Listが連続値かどうかをチェックする
on chkSequential(aList as list)
  if length of aList = 1 then return true
  
if aList = {} then return false
  
  
set aFirst to first item of aList
  
set aList to rest of aList
  
  
repeat with i in aList
    set j to contents of i
    
if j is not equal to (aFirst + 1) then
      return false
    end if
    
copy j to aFirst
  end repeat
  
  
return true
end chkSequential

★Click Here to Open This Script 

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

(POST) Google Translate APIで翻訳

Posted on 12月 10, 2018 by Takaaki Naganoya

Google Translate API(REST API)を呼び出して、指定のテキストを別の言語に翻訳するAppleScriptです。

Google Cloud Consoleにお持ちのGoogleアカウントでログインし、プロジェクトを作成して、プロジェクト用のAPIを個別に許可(この場合にはGoogle Translate API)し、API Keyを発行してScript中に記述して呼び出します(retAPIKeyハンドラ中にハードコーディングするのが嫌であれば、Keychainに登録して呼び出すことも可能です)。

処理内容自体は、REST API呼び出しのいつものやつなんでとくに解説はしません。コピペで作れるぐらい退屈で簡単です(本Scriptも呼び出せることを確認するだけして放置していました)。

ただ、本Scriptは同期処理用のNSURLConnectionを使って呼び出しているバージョンで、このNSURLConnectionが将来的に廃止される見込みなので、curlコマンドで呼び出すか、NSURLSessionを使って呼び出すように書き換えるか、といったところです。

単体だとただ翻訳できるだけで、あまり面白味はありません。本ScriptはMicrosoft Azure Computer Vision APIで画像認識を行なったときに、その画像認識テキストが英文で返ってきており、その内容を日本語に自動翻訳するときに使用してみました。翻訳精度は悪くないと思うのですが、画像のシーン認識テキストの英文がいまひとつだったので、「英文で出力してくれた方がまだわかりやすい」というところで、個人的にはあまり活躍していません。

Translate APIを売り物の本の翻訳に使うことが許可されていないなど、利用許諾が割と厳しいので使いどころが多そうに見えつつもそうでもない、といったところでしょうか。

AppleScript名:(POST) Google Translate APIで翻訳
— Created 2016-03-03 by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

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

set aSentense to "a birthday cake with lit candles"
set bSentense to retTranslatedString("en", "ja", aSentense) of me
–> "キャンドルライト付きの誕生日ケーキ"–Japanese

set cSentense to retTranslatedString("en", "de", aSentense) of me
–> "eine Geburtstagstorte mit brennenden Kerzen"–Deutsch

on retTranslatedString(fromLang, toLang, aSentense)
  set myAPIKey to retAPIKey() of me
  
set aRec to {|key|:myAPIKey, source:fromLang, |format|:"text", target:toLang, q:aSentense}
  
set aURL to "https://www.googleapis.com/language/translate/v2"
  
set bURL to retURLwithParams(aURL, aRec) of me
  
set aRes to callRestPOSTAPIAndParseResults(bURL) of me
  
  
set aRESCode to responseCode of aRes
  
if aRESCode is not equal to 200 then return ""
  
set aRESHeader to responseHeader of aRes
  
set aRESTres to (translatedText of (first item of translations of |data| of json of aRes)) as string
  
return aRESTres
end retTranslatedString

–POST methodのREST APIを呼ぶ
on callRestPOSTAPIAndParseResults(aURL)
  set aRequest to NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:"POST"
  
aRequest’s setValue:"application/x-www-form-urlencoded" forHTTPHeaderField:"Content-Type"
  
  
set aRes to NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to NSString’s alloc()’s initWithData:bRes encoding:(NSUTF8StringEncoding)
  
  
set jsonString to NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestPOSTAPIAndParseResults

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

on retAPIKey()
  return "XXxxXxXXXxXxX-XxXXxXXXxxxxXXXXxXxXXxXXX"
end retAPIKey

★Click Here to Open This Script 

Posted in JSON Network Record REST API Text | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSMutableDictionary NSMutableURLRequest NSString NSURLComponents NSURLConnection NSURLQueryItem NSUTF8StringEncoding | Leave a comment

Keynoteでオープン中の最前面の現在のページのテキストアイテムを取得してテキスト化

Posted on 12月 6, 2018 by Takaaki Naganoya

Keynoteでオープン中の最前面の書類の、現在表示中のスライド(ページ)上に存在する文字情報を取得して、macOS標準装備のテキストエディタ「テキストエディット」の新規書類上に取得した文字情報をすべて転送するAppleScriptです。

Keynote書類上に配置できるオブジェクトには、

このようなものがあります。

これらのうち文字情報が直接入力可能なtext itemおよびshapeを包括したiWork itemというオブジェクト、およびtableオブジェクトから文字情報を取得し、いろいろごみ取り(改行文字削除)を行なったりしたものをmacOS標準装備のテキストエディタに出力するものです。

Keynoteで作業中に編集中の書類内から文字情報を再利用したい場合のために作成したものです。


▲このようなKeynoteのスライド(ページ)上の文字情報を


▲一括で取得してテキストエディタの新規書類上に転送

macOS標準装備のスクリプトメニューに入れて呼び出しています。

AppleScript名:Keynoteでオープン中の最前面の現在のページのテキストアイテムを取得してテキスト化
— Created 2018-11-28 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set repTargList to {string id 10, string id 11, string id 13} –LF,CR,VTab一括置換

set t1List to {}
set t2List to {}

tell application "Keynote"
  if (count every document) = 0 then return
  
  
tell front document
    tell current slide
      if (count every iWork item) > 0 then
        set t1List to object text of every iWork item –text item, shapeなどを包括したオブジェクト
      end if
      
      
if (count every table) > 0 then
        set t2List to value of every cell of every table
      end if
      
    end tell
  end tell
end tell

set tList to t1List & t2List
set tList to FlattenList(tList) of me –force lists to 1D list

–タイトルごとにゴミ取り(改行文字の削除)
set outList to {}
repeat with i in tList
  set j1 to contents of i
  
  
if (j1 is not equal to missing value) and (j1 is not equal to "") then
    set jTmp to (paragraphs of j1) as string –しつこい改行文字(?)を除去するための処理
    
    
set j2 to replaceTextMultiple(jTmp, repTargList, "") of me as string
    
if j2 is not equal to "" then
      set the end of outList to j2
    end if
  end if
end repeat

–リストを改行で区切ったテキストに変換
set aStr to listToStringUsingTextItemDelimiter(outList, return) of me

–得られたテキストをTextEditの新規書類上に出力
tell application "TextEdit"
  activate
  
make new document
  
set text of front document to aStr
end tell

–リストを指定デリミタで区切ったテキストに変換
on listToStringUsingTextItemDelimiter(sourceList as list, textItemDelimiter as string)
  set anArray to current application’s NSArray’s arrayWithArray:sourceList
  
set aString to anArray’s componentsJoinedByString:textItemDelimiter
  
return (aString as string)
end listToStringUsingTextItemDelimiter

–任意のデータから特定の文字列を複数パターン一括置換
on replaceTextMultiple(origData as string, origTexts as list, repText as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to origTexts
  
set origData to text items of origData
  
set AppleScript’s text item delimiters to {repText}
  
set origData to origData as text
  
set AppleScript’s text item delimiters to curDelim
  
return origData
end replaceTextMultiple

–多次元配列の強制1次元配列化 By Paul Berkowitz
on FlattenList(aList as list)
  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

★Click Here to Open This Script 

Posted in list Text | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote | Leave a comment

Keynoteでオープン中の最前面の書類のすべてのページのタイトルを取得してテキスト化 v2

Posted on 12月 6, 2018 by Takaaki Naganoya

オープン中の最前面のKeynoteの書類の各スライド(ページ)のタイトルを取得して、改行文字を削除し、テキストエディット上の新規書類にタイトル一覧文字を入れるAppleScriptです。

Keynote書類は、きちんと各スライドのマスタースライドでタイトル入りのものを使用し、各スライドでタイトル用のテキストアイテムにタイトルを入れてあれば、AppleScriptからタイトルを取得できます。

もしも、スライド(ページ)上にタイトルが存在しない場合には、座標がどこどこ以上で文字サイズがXXXポイント以上のテキストアイテムのうち、もっとも上の方に存在しているものをタイトルとみなして取得する、といった処理も可能なので、そういう対策を行なってもよいでしょう。

ここでは、単にタイトル内容の再利用や内容確認などのためOS標準装備のテキストエディタに出力していますが、Keynote書類上に目次を作成するといった処理も普通に行なっています(仕様書の目次をつける場合など)。

Keynote書類に対する処理は、割と自分的に業務の効率化に寄与しています。毎月作成する説明用資料を、さまざまな書類のデータから数値を集めてKeynote書類を自動作成するといったAppleScriptも実際に存在しています。


▲このようなKeynote書類を……


▲本Scriptで処理するとテキストエディット上にタイトル一覧が展開される

AppleScript名:Keynoteでオープン中の最前面の書類のすべてのページのタイトルを取得してテキスト化 v2
— Created 2018-11-28 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set repTargList to {string id 10, string id 11, string id 13} –LF,CR,VTab一括置換

tell application "Keynote"
  if (count every document) = 0 then return
  
  
tell front document
    set tList to object text of default title item of every slide
  end tell
end tell

–タイトルごとにゴミ取り(改行文字の削除)
set outList to {}
repeat with i in tList
  set j1 to contents of i
  
set jTmp to (paragraphs of j1) as string –しつこい改行文字(?)を除去するための処理
  
  
set j2 to replaceTextMultiple(jTmp, repTargList, "") of me as string
  
if j2 is not equal to "" then
    set the end of outList to j2
  end if
end repeat

–リストを改行で区切ったテキストに変換
set aStr to listToStringUsingTextItemDelimiter(outList, return) of me

–得られたテキストをTextEditの新規書類上に出力
tell application "TextEdit"
  activate
  
make new document
  
set text of front document to aStr
end tell

–リストを指定デリミタで区切ったテキストに変換
on listToStringUsingTextItemDelimiter(sourceList as list, textItemDelimiter as string)
  set anArray to current application’s NSArray’s arrayWithArray:sourceList
  
set aString to anArray’s componentsJoinedByString:textItemDelimiter
  
return (aString as string)
end listToStringUsingTextItemDelimiter

–任意のデータから特定の文字列を複数パターン一括置換
on replaceTextMultiple(origData as string, origTexts as list, repText as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to origTexts
  
set origData to text items of origData
  
set AppleScript’s text item delimiters to {repText}
  
set origData to origData as text
  
set AppleScript’s text item delimiters to curDelim
  
return origData
end replaceTextMultiple

★Click Here to Open This Script 

Posted in list Text | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote | Leave a comment

Keynoteの表セルに計算式を入れる

Posted on 12月 5, 2018 by Takaaki Naganoya

Keynoteの最前面の書類の現在表示中のスライド(ページ)上の表の指定セルに計算式を入れ、表示フォーマットを指定するAppleScriptです。

計算式については、Keynote上で実際に入力して、AppleScriptから指定セルのpropertyを取得して、記入方法を確認しました。

tell application "Keynote"
  tell front document
    tell current slide
      tell table 1
        tell column 2
          tell cell 3
            properties
            
–> {vertical alignment:center, row:row "3" of table 1 of slide 1 of document id "11E9C7CA-50E5-4360-A26D-C8B14BAE004D" of application "Keynote", class:cell, font name:"HiraKakuProN-W3", formatted value:"50%", background color:{65527, 65533, 65524}, formula:"=B2÷B1", name:"B3", text wrap:true, text color:{0, 0, 0}, alignment:center, column:column "B" of table 1 of slide 1 of document id "11E9C7CA-50E5-4360-A26D-C8B14BAE004D" of application "Keynote", format:percent, font size:22.0, value:0.5}            
          end tell
        end tell
      end tell
    end tell
  end tell
end tell

★Click Here to Open This Script 

このような状態で、

実際に実行すると、

のようになります。セルに指定できるformatの種類は、KeynoteのAppleScript用語辞書にあるように、

automatic/‌checkbox/‌currency/‌date and time/‌fraction/‌number/‌percent/‌pop up menu/‌scientific/‌slider/‌stepper/‌text/‌duration/‌rating/‌numeral system

のとおりです。実際に指定してみるとわかるのですが、Keynoteのアプリケーション仕様にない予約語があり(checkbox、pop up menu、slider、stepper)これらを指定してもKeynoteがサポートしている範囲内のformatでしか表示されません。

なお、掲載Scriptではわかりやすいように確認処理を省略していますが、実行の前提条件としてKeynote書類がオープンされていて、表示中のスライド(ページ)上に表オブジェクトが存在する状態になっていることが必要です。これらの前提条件を満たしていない場合には、エラーになります。

AppleScript名:Keynoteの表セルに計算式を入れる
tell application "Keynote"
  tell front document
    tell current slide
      tell table 1
        tell column 2
          tell cell 3
            set its value to "=B2÷B1"
            
set its format to percent
          end tell
        end tell
      end tell
    end tell
  end tell
end tell

★Click Here to Open This Script 

Posted in How To | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote | Leave a comment

WebView+ボタンを作成 v3.1(URLから読み込み)

Posted on 12月 3, 2018 by Takaaki Naganoya

WkWebViewを動的に生成して、YouTube上の指定ムービーを再生するAppleScriptの改良版です。とくにYouTube限定ではなく、Webコンテンツのブラウズを単体で行うための実験的なScriptです。

# AppleScriptでは、Webブラウザに命令を出せば数行のコマンドで簡単に任意のURLのWebコンテンツを表示させられますが、本ScriptはAppleScriptから他のアプリケーションを介さずに直接Cocoaの機能を呼び出して自前でWebコンテンツを表示させるものです。

NSWindow+NSSplitView+WKWebViewを作成して、Webサーバー上の内容を表示します。v3.0からの改良点は、再生中のWebコンテンツのクリアを明示的に行えるようになったことです。

スクリプトエディタ上で実行し、「OK」ボタンをクリックすると、ウィンドウがクローズし、Webコンテンツの再生も停止します(前バージョンではこれができなかった)。Script MenuおよびScript Debugger上では実行できるもののWebコンテンツ操作はできず、OKボタンも反応しません。

AppleScript Appletとして書き出して実行すると、そのままではインターネットへのアクセスが許可されていないため、表示できません。Info.plistのエントリを書き換える必要があるものと思われます。

再生中のWebコンテンツのクリアについては、US Appleが主催しているCocoa-Dev MLにFritz Andersonが2012年4月11日に投稿した、

On 11 Apr 2012, at 7:51 AM, Koen van der Drift wrote:

> Is there a way to empty or clear a webview when I close the popover,
> so that next time it is opened it doesn't show the previous page? I
> don't want to clear the cache, because when the webview is opened for
> an item that was already selected, it can be loaded from the cache.

What works for me on iOS is having the UIWebView load about:blank. Maybe it works the same in Mac OS.

	— F

が参考になりました。Google検索しても見つからなかったのに、MLの過去ログを漁ってみたら割と簡単に発見。あらかじめMLのログをAppleScriptのロボットでテーマごとに自動フォルダ分けして整理してあったのが効きました。

あとは、実行環境がかなり限定される(Script DebuggerやScript Menuから実行すると、Webコンテンツ操作やボタンのクリックができなくなる)点をなんとかしたいところです。AppleScriptアプレットだとそのまま書き出した状態ではネットワーク接続自体ができない(Info.plist書き換えでなんとか?)とか。

Script Menuからの実行時に無反応になる件をなんとかしたいところです。個人的には、Script Menuが主力実行(ランタイム)環境だと思っているので。

AppleScript名:WebView+ボタンを作成 v3.1(URLから読み込み)
— Created 2018-11-27 by Takaaki Naganoya
— Modified 2018-12-03 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property NSSplitView : a reference to current application’s NSSplitView
property NSTextView : a reference to current application’s NSTextView
property NSScrollView : a reference to current application’s NSScrollView
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSMutableString : a reference to current application’s NSMutableString
property NSWindowController : a reference to current application’s NSWindowController
property NSTitledWindowMask : a reference to current application’s NSTitledWindowMask
property NSRoundedBezelStyle : a reference to current application’s NSRoundedBezelStyle
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property WKUserContentController : a reference to current application’s WKUserContentController
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property NSScreenSaverWindowLevel : a reference to current application’s NSScreenSaverWindowLevel
property NSWindowStyleMaskResizable : a reference to current application’s NSWindowStyleMaskResizable
property NSWindowStyleMaskMiniaturizable : a reference to current application’s NSWindowStyleMaskMiniaturizable
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property windisp : false
property wController : false

set aWidth to 1100
set aHeight to 700

set aTitle to "WkWebView test2"
set aButtonMSG to "OK"

set aURL to "https://www.youtube.com/embed/GP_tVXTYdmY?autoplay=1&hd=1"

set paramObj to {aWidth, aHeight, aTitle, aURL, aButtonMSG, "600"}
my performSelectorOnMainThread:"dispWebView:" withObject:(paramObj) waitUntilDone:true

on dispWebView:paramObj
  set my windisp to false
  
copy (paramObj as list) to {aWidth, aHeight, aTitle, tmpURL, aButtonMSG, timeOutSecs}
  
  
set (my windisp) to true
  
  
set aWidth to aWidth as integer
  
set aHeight to aHeight as integer
  
set tmpURL to tmpURL as string
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定URLのJavaScriptをFetch
  
set jsSource to my fetchJSSourceString(tmpURL)
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight – 100)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
  
set bURL to |NSURL|’s URLWithString:tmpURL
  
set aReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:aReq –Webコンテンツのローディング
  
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, 40)))
  
bButton’s setTitle:aButtonMSG
  
bButton’s setTarget:me
  
bButton’s setAction:("clicked:")
  
bButton’s setKeyEquivalent:(return)
  
  
–SplitViewをつくる
  
set aSplitV to NSSplitView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
aSplitV’s setVertical:false
  
  
aSplitV’s addSubview:aWebView
  
aSplitV’s addSubview:bButton
  
aSplitV’s setNeedsDisplay:true
  
  
set aWin to makeWinWithView(aSplitV, aWidth, aHeight, aTitle, 1.0)
  
  
–NSWindowControllerを作ってみた
  
set my wController to NSWindowController’s alloc()
  
my (wController’s initWithWindow:aWin)
  
  
my (wController’s showWindow:me)
  
  
set aCount to (timeOutSecs as string as number) * 10 –timeout seconds * 10
  
repeat aCount times
    if (my windisp) = false then
      exit repeat
    end if
    
delay 0.1
  end repeat
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
my closeWin:bButton
end dispWebView:

–Button Clicked Event Handler
on clicked:aSender
  set (my windisp) to false
  
my closeWin:aSender
end clicked:

–make Window for Input
on makeWinWithView(aView, aWinWidth, aWinHeight, aTitle, alphaV)
  set aScreen to NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
set aBacking to NSTitledWindowMask –NSBorderlessWindowMask
  
set aDefer to NSWindowStyleMaskMiniaturizable
  
  
— Window
  
set aWin to NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
  
aWin’s setTitle:aTitle
  
aWin’s setDelegate:me
  
aWin’s setDisplaysWhenScreenProfileChanges:true
  
aWin’s setHasShadow:true
  
aWin’s setIgnoresMouseEvents:false
  
aWin’s setLevel:(NSScreenSaverWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setAlphaValue:alphaV –append
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
— Set Custom View
  
aWin’s setContentView:aView
  
  
return aWin
end makeWinWithView

–close win
on closeWin:aSender
  set tmpWindow to aSender’s |window|()
  
  
repeat with n from 10 to 1 by -1
    (tmpWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
  
my wController’s |close|()
end closeWin:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

★Click Here to Open This Script 

Posted in URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSBackingStoreBuffered NSButton NSMomentaryLightButton NSMutableString NSRoundedBezelStyle NSScreen NSSplitView NSString NSTitledWindowMask NSURL NSURLRequest NSUTF8StringEncoding NSWindow NSWindowController WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | 1 Comment

Numbersで選択中のデータを2D Listで取得し、ユニーク化

Posted on 12月 3, 2018 by Takaaki Naganoya

Numbersの最前面の書類の選択中のシートの選択中のセルの値を2D List(Array)で取り出して、ユニーク化するAppleScriptです。

上記のような状態で本AppleScriptを実行すると、

{{"iMac4,1", "Yonah"}, {"iMac4,2", "Yonah"}, {"iMac5,2", "Merom"}, {"iMac5,1", "Merom"}, {"iMac6,1", "Merom"}, {"iMac7,1", "Merom"}, {"iMac8,1", "Penryn"}, {"iMac9,1", "Penryn"}, {"iMac10,1", "Wolfdale"}, {"iMac11,1", "Wolfdale, Lynnfield"}......} 

のような2D Listで結果が得られます。Numbersの選択中のセルからそのまま情報を取得すると1D Listとして結果が返ってきますが、別途selection rangeの情報を取得し、それをもとに2D Listに変換。得られた2D Listに対して重複データの除去をCocoaの機能を用いて行なっています。

特定のフィールド上の選択中のデータを1D Listとして取得し、重複データを検出するようなScriptは日常的に使っていますが、行データをすべて取得して2D Listとして取り出し、重複データ部分を除去するようなものは使っていませんでした。

AppleScript名:Numbersで選択中のデータを2D Listで取得し、ユニーク化
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set aList to get2DListFromNumbersSelection() of me
if aList = "" then return "No Selection"

set bList to uniquifyList(aList) of me

on get2DListFromNumbersSelection()
  –Numbersで選択範囲を縦に区切ったリストを返す
  
tell application "Numbers"
    tell front document
      tell active sheet
        try
          set theTable to first table whose class of selection range is range
        on error
          return "" –何も選択されてなかった場合
        end try
        
        
tell theTable
          set selList to value of every cell of selection range –選択範囲のデータを取得
          
          
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
  
  
set aLen to length of selList
  
set aaLen to selHeight
  
  
set bList to {}
  
repeat with i from 1 to aaLen
    set aHoriList to {}
    
    
repeat with ii from 1 to selWidth
      set j1 to ii + (i – 1) * selWidth
      
set tmpCon to contents of item j1 of selList
      
      
set aClass to class of tmpCon
      
if aClass = number or aClass = integer or aClass = real then
        set tmpCon to tmpCon as integer
      end if
      
      
set the end of aHoriList to tmpCon
    end repeat
    
    
set the end of bList to aHoriList
  end repeat
  
  
return bList
end get2DListFromNumbersSelection

–テキストを指定デリミタでリスト化
on parseByDelim(aData, aDelim)
  set aText to current application’s NSString’s stringWithString:aData
  
set aList to aText’s componentsSeparatedByString:aDelim
  
return aList as list
end parseByDelim

–1D/2D Listのユニーク化
on uniquifyList(aList as list)
  set aArray to current application’s NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquifyList

★Click Here to Open This Script 

Posted in list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSString Numbers | Leave a comment

CPU Family Nameを取得する

Posted on 12月 3, 2018 by Takaaki Naganoya

実行中のMacのMachine ID(MacBookPro10,1など)からIntel CPUのFamily Name(Ivy Bridgeなど)を取得するAppleScriptです。

Macの各モデルの搭載CPUについては、MacTrackerを参照しました。

MacTrackerのデータをコピー&ペーストでNumbers上に製品データを作成し(手動)、

ユニーク化(重複データの除去)処理を行なって(ASで処理)、プログラム上に展開しました(手動)。

実用性とか意味については、とくに考えていません。Machine IDとCPU Family Nameのデータについてはplistに記述してプログラム外部に追い出して独自でメンテナンスできるようにしたほうがよいと思われます。

AppleScript名:CPU Family Nameを取得する.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/12/03
—
–  Copyright © 2018 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set macID to do shell script "sysctl -n hw.model" –get machine ID
–set macID to "MacBookPro99,1"–Error case

set myName to getIntelCoreProcessorFamilyName(macID) of me
—> "Ivy Bridge"

on getIntelCoreProcessorFamilyName(macID)
  –Machine ID & CPU Core Model Names (uniquefied)
  
set macList to {{"iMac4,1", "Yonah"}, {"iMac4,2", "Yonah"}, {"iMac5,2", "Merom"}, {"iMac5,1", "Merom"}, {"iMac6,1", "Merom"}, {"iMac7,1", "Merom"}, {"iMac8,1", "Penryn"}, {"iMac9,1", "Penryn"}, {"iMac10,1", "Wolfdale"}, {"iMac11,1", "Wolfdale, Lynnfield"}, {"iMac11,2", "Clarkdale"}, {"iMac11,3", "Clarkdale, Lynnfield"}, {"iMac12,1", "Sandy Bridge"}, {"iMac12,2", "Sandy Bridge"}, {"iMac13,1", "Ivy Bridge"}, {"iMac13,2", "Ivy Bridge"}, {"iMac14,1", "Haswell"}, {"iMac14,3", "Haswell"}, {"iMac14,2", "Haswell"}, {"iMac14,4", "Haswell"}, {"iMac15,1", "Haswell"}, {"iMac16,1", "Broadwell"}, {"iMac16,2", "Broadwell"}, {"iMac17,1", "Skylake"}, {"iMac18,1", "Kaby Lake"}, {"iMac18,2", "Kaby Lake"}, {"iMac18,3", "Kaby Lake"}, {"iMacPro1,1", "Skylake"}, {"Macmini1,1", "Yonah"}, {"Macmini2,1", "Merom"}, {"Macmini3,1", "Penryn"}, {"Macmini4,1", "Penryn"}, {"Macmini5,1", "Sandy Bridge"}, {"Macmini5,2", "Sandy Bridge"}, {"Macmini5,3", "Sandy Bridge"}, {"Macmini6,1", "Ivy Bridge"}, {"Macmini6,2", "Ivy Bridge"}, {"Macmini7,1", "Haswell"}, {"Macmini8,1", "Coffe Lake"}, {"MacPro1,1", "Woodcrest"}, {"MacPro2,1", "Clovertown"}, {"MacPro3,1", "Harpertown"}, {"MacPro4,1", "Bloomfield, Gainestown"}, {"MacPro5,1", "Bloomfield, Gulftown, Westmere"}, {"MacPro5,1", "Bloomfield, Westmere, Gulftown"}, {"MacPro6,1", "Ivy Bridge"}, {"MacBook1,1", "Yonah"}, {"MacBook2,1", "Merom"}, {"MacBook3,1", "Merom"}, {"MacBook4,1", "Penryn"}, {"MacBook5,1", "Penryn"}, {"MacBook5,2", "Penryn"}, {"MacBook6,1", "Penryn"}, {"MacBook7,1", "Penryn"}, {"MacBook8,1", "Broadwell"}, {"MacBook9,1", "Skylake"}, {"MacBook10,1", "Kaby Lake"}, {"MacBookAir1,1", "Merom"}, {"MacBookAir2,1", "Penryn"}, {"MacBookAir3,1", "Penryn"}, {"MacBookAir3,2", "Penryn"}, {"MacBookAir4,1", "Sandy Bridge"}, {"MacBookAir4,2", "Sandy Bridge"}, {"MacBookAir5,1", "Ivy Bridge"}, {"MacBookAir5,2", "Ivy Bridge"}, {"MacBookAir6,1", "Haswell"}, {"MacBookAir6,2", "Haswell"}, {"MacBookAir7,1", "Broadwell"}, {"MacBookAir7,2", "Broadwell"}, {"MacBookAir8,1", "Amber Lake Y"}, {"MacBookPro1,1", "Yonah"}, {"MacBookPro1,2", "Yonah"}, {"MacBookPro2,2", "Merom"}, {"MacBookPro2,1", "Merom"}, {"MacBookPro3,1", "Merom"}, {"MacBookPro4,1", "Penryn"}, {"MacBookPro5,1", "Penryn"}, {"MacBookPro5,2", "Penryn"}, {"MacBookPro5,5", "Penryn"}, {"MacBookPro5,4", "Penryn"}, {"MacBookPro5,3", "Penryn"}, {"MacBookPro7,1", "Penryn"}, {"MacBookPro6,2", "Arrandale"}, {"MacBookPro6,1", "Arrandale"}, {"MacBookPro8,1", "Sandy Bridge"}, {"MacBookPro8,2", "Sandy Bridge"}, {"MacBookPro8,3", "Sandy Bridge"}, {"MacBookPro9,2", "Ivy Bridge"}, {"MacBookPro9,1", "Ivy Bridge"}, {"MacBookPro10,1", "Ivy Bridge"}, {"MacBookPro10,2", "Ivy Bridge"}, {"MacBookPro11,1", "Haswell"}, {"MacBookPro11,2", "Haswell"}, {"MacBookPro11,3", "Haswell"}, {"MacBookPro12,1", "Broadwell"}, {"MacBookPro11,4", "Haswell"}, {"MacBookPro11,5", "Haswell"}, {"MacBookPro13,1", "Skylake"}, {"MacBookPro13,2", "Skylake"}, {"MacBookPro13,3", "Skylake"}, {"MacBookPro14,1", "Kaby Lake"}, {"MacBookPro14,2", "Kaby Lake"}, {"MacBookPro14,3", "Kaby Lake"}, {"MacBookPro15,2", "Coffee Lake"}, {"MacBookPro15,1", "Coffee Lake"}}
  
  
–2D List内の検索
  
set gList to searchInListByIndexItem(macList, 1, macID) of me
  
if gList = missing value or gList = {} then
    error "Error:" & macID & "is newer Machine than I expected in Dec 2018 or Older PowerPC Mac , may be"
  end if
  
  
set g2List to FlattenList(gList) of me –複数の結果が得られた場合に備える
  
return contents of second item of g2List
end getIntelCoreProcessorFamilyName

–2Dリストから、指定インデックスアイテムで、指定データが該当する最初のものを返す
on searchInListByIndexItem(aList as list, itemNum as integer, hitData as string)
  set setKey to current application’s NSMutableSet’s setWithArray:aList
  
  
if itemNum < 1 then return {}
  
set aPredicateStr to ("SELF[" & (itemNum – 1) as string) & "] == ’" & hitData & "’"
  
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicateStr
  
set aRes to (setKey’s filteredSetUsingPredicate:aPredicate)
  
set bRes to aRes’s allObjects()
  
  
set cRes to bRes as list of string or string –as anything
  
return cRes
end searchInListByIndexItem

–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

★Click Here to Open This Script 

Posted in shell script System | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSMutableSet NSPredicate | Leave a comment

teratailの指定IDのユーザー情報を取得する_curl

Posted on 11月 27, 2018 by Takaaki Naganoya

プログラミング系質問サイトteratailのREST APIを呼び出して、指定ユーザー名の情報を取得するAppleScriptです。

TeratailのREST APIは、タグ、ユーザー、質問の3ジャンルの情報取得を行えるように整備されており、特定カテゴリ(タグで分類)の新規質問が投稿されたかどうかを定期的に確認するようなAppleScriptを作って運用することもできます(そこまでやっていないですけれども)。

REST API呼び出しにはNSURLConnectionからNSURLSessionに移行していますが、どうもNSURLSessionだと呼び出せない(AppleScriptからの呼び出し処理が完了しない)サービスがあったりするので、結局shellのcurlコマンドを呼び出すのが手短にすむケースが多いようです。

Teratailの場合も、NSURLSessionで呼び出せるAPIもあれば、結果が返ってこないAPIもあり、NSURLConnectionよりも使い勝手がよくないと感じています(個人の感想です)。

このあたり、将来的なmacOSのアップデートでNSURLConnectionが使えなくなる日が来るのかもしれませんが、curlコマンドを使うように集約するべきなのか、NSURLSessionで書き換えるべきなのか悩ましいところです。

AppleScript名:teratailの指定IDのユーザー情報を取得する_curl
— Created 2018-11-26 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

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

set aUserRes to searchOneUserByDisplayName("Piyomaru") of me
–> {meta:{limit:20, message:"success", hit_num:1, total_page:1, page:1}, users:{{score:43, photo:"https://teratail.storage.googleapis.com/uploads/avatars/u6/66639/MSIS21by_thumbnail.jpg", display_name:"Piyomaru"}}}

on searchOneUserByDisplayName(aName)
  set aRec to {q:aName}
  
set reqURLStr to "https://teratail.com/api/v1/users/search"
  
set bURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set tmpData to (do shell script "curl -X GET \"" & bURL & "\"")
  
set jsonString to NSString’s stringWithString:tmpData
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
if aJsonDict = missing value then return false
  
return (aJsonDict as record)
end searchOneUserByDisplayName

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

★Click Here to Open This Script 

Posted in Network Record REST API shell script URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSMutableDictionary NSString NSURL NSURLComponents NSURLQueryItem | 1 Comment

Mail.appで選択中のフォルダ以下に存在する全メールの添付ファイルの拡張子のバリエーションを集計

Posted on 11月 25, 2018 by Takaaki Naganoya

Mail.appで選択中のフォルダ(メールボックス)以下に存在する全メールの添付ファイルの拡張子のバリエーションを集計するAppleScriptです。

階層フォルダで管理しているメールボックス(フォルダ)のうち、選択しているメールフォルダ以下のすべてのメッセージに添付されているファイルの拡張子を取得して結果を表示します。

何のために作ったとかいうことはなくて、ただ単に調査のために作ったものです。処理するメールの数にもよりますが、CPU負荷も大きく、時間もそれなりに(数分ぐらい?)かかります。

AppleScript名:Mail.appで選択中のフォルダ以下に存在する全メールの添付ファイルの拡張子のバリエーションを集計
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/11/25
—
–  Copyright © 2018 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

script spd
  property fullSubPath : {}
  
property tmpMesList : {}
  
property outList : {}
end script

property aFullPath : ""
property tmpFullPath : ""
property extList : {}

–変数の初期化
set tmpFullPath to ""
set aFullPath to ""
set extList to {}
set (fullSubPath of spd) to {}
set (tmpMesList of spd) to {}
set (outList of spd) to {}

–選択中のメールボックス(フォルダ)のフルパスを文字列で取得(dir1/dir2/dir3)
set targMBObj to getSelectedOneMailBox() of me
extraxctTextFullPathOfMBObject(targMBObj) of me

copy aFullPath to targMB

if targMB = "" then
  display notification "Mail.app上で選択中のメールボックス(フォルダ)はありません。" –"No Mail.app folder selection" in Japanese
  
return
end if

–指定メールボックス(フォルダ)以下のすべてのメールボックス(フォルダ)を取得する
tell application "Mail"
  tell mailbox targMB
    set aList to name of every mailbox
  end tell
end tell

–指定フォルダ以下のMailboxをサブフォルダまで再帰ですべて取得する
repeat with i in aList
  set j to contents of i
  
set tmpPath to targMB & "/" & j
  
set the end of (fullSubPath of spd) to tmpPath
  
getEverySubMailbox(tmpPath) of me
end repeat

–全サブフォルダからメールを取得し、添付ファイルの確認を行なって、添付ファイルの拡張子を取得して集計
repeat with i in (fullSubPath of spd)
  set tmpBox to contents of i
  
  
tell application "Mail"
    tell mailbox tmpBox
      set mesList to (every message)
    end tell
    
    
–指定フォルダ中のMailでループ
    
repeat with ii in mesList
      set jj to contents of ii
      
      
try
        set attS to mail attachment of jj
      on error
        set attS to {}
      end try
      
      
if attS is not equal to {} then
        
        
–Mailの添付ファイルの拡張子を集計する
        
try
          repeat with iii in attS
            set jjj to contents of iii
            
set aName to name of jjj
            
            
set aExt to getPathExtension(aName) of me
            
            
if (aExt is not in extList) and (aExt is not equal to "") then
              set the end of extList to aExt
            end if
            
          end repeat
        end try
      end if
    end repeat
  end tell
end repeat

choose from list extList with prompt "選択中のメールフォルダ「" & targMB & "」中のメールに添付されているファイルの種別です" with title "添付ファイルの拡張子一覧"

–指定のメールボックス(フォルダ)以下にあるすべてのサブフォルダを(propertyに)追記して返す
on getEverySubMailbox(aPath)
  tell application "Mail"
    tell mailbox aPath
      set aaList to name of every mailbox
      
if aaList is not equal to {} then
        repeat with i in aaList
          set j to contents of i
          
set tmpFullPath to aPath & "/" & j
          
copy tmpFullPath to newPath
          
set the end of (fullSubPath of spd) to newPath
          
getEverySubMailbox(newPath) of me
        end repeat
      end if
    end tell
  end tell
end getEverySubMailbox

–Message Viewerで現在表示中のメールボックスの情報を1つのみ返す
on getSelectedOneMailBox()
  tell application "Mail"
    tell message viewer 1
      set mbList to selected mailboxes
    end tell
  end tell
  
if length of mbList is equal to 0 then
    return ""
  end if
  
  
set aMailBox to contents of (item 1 of mbList)
  
return aMailBox
end getSelectedOneMailBox

–Mail.appのメールボックスオブジェクトを渡すと、テキストのフルパスに変換
on extraxctTextFullPathOfMBObject(aPath)
  tell application "Mail"
    try
      set parentPath to container of aPath
    on error
      return
    end try
    
    
set meName to name of aPath
    
if aFullPath = "" then –1回目のみスラッシュを入れないで処理
      set aFullPath to meName
    else
      –通常処理はこちら
      
set aFullPath to meName & "/" & aFullPath
    end if
    
    
extraxctTextFullPathOfMBObject(parentPath) of me –再帰呼び出し
  end tell
end extraxctTextFullPathOfMBObject

on getPathExtension(aStr as string)
  set pathString to current application’s NSString’s stringWithString:aStr
  
return (pathString’s pathExtension()) as string
end getPathExtension

★Click Here to Open This Script 

Posted in file list recursive call | Tagged 10.11savvy 10.12savvy Mail | Leave a comment

Mail.appで選択中のフォルダ以下に存在する全メールの指定形式の添付ファイルを指定フォルダにコピー v2

Posted on 11月 25, 2018 by Takaaki Naganoya

Mail.appで選択中のフォルダ(メールボックス)以下に存在する全メールに添付されているファイルのうち、指定形式のファイルのみ指定フォルダに保存するAppleScriptです。

・Mail.appで選択中のフォルダを求め、フォルダの(Mail.app上の)フルパス文字列を再帰処理で取得
・書き出し先フォルダを指定(choose folder)
・指定のMail.app上の選択中のフォルダ以下の全メールフォルダ、およびそれらの中に入っているメールを再帰処理で取得
・取得した全メールをループで調査し、添付ファイルが存在するかチェック
・1メールあたりの添付ファイルはリストで返ってくるので、すべて求めてループで処理
・添付ファイルの拡張子を求め、書き出し許可リスト {“txt”, “gv”, “dot”} に入っていれば、指定フォルダ内に保存


▲書き出したファイル

たまーに、添付ファイルがよく出回っているメーリングリスト(QuartzComposer MLとかGraphViz MLとか)で、メール添付されているファイルを一括で取得するために作成しました。

AppleScript名:Mail.appで選択中のフォルダ以下に存在する全メールの指定形式の添付ファイルを指定フォルダにコピー v2
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

script spd
  property fullSubPath : {}
  
property tmpMesList : {}
end script

property aFullPath : ""
property tmpFullPath : ""

set targList to {"txt", "gv", "dot"} –書き出し対象拡張子

–変数の初期化
set tmpFullPath to ""
set aFullPath to ""
set (fullSubPath of spd) to {}
set (tmpMesList of spd) to {}

–選択中のメールボックス(フォルダ)のフルパスを文字列で取得(dir1/dir2/dir3)
set targMBObj to getSelectedOneMailBox() of me
extraxctTextFullPathOfMBObject(targMBObj) of me

copy aFullPath to targMB

if targMB = "" then
  display notification "Mail.app上で選択中のメールボックス(フォルダ)はありません。"
  
return
end if

tell current application
  set targFol to choose folder with prompt "添付ファイルの書き出し先フォルダを指定してください"
end tell

–指定メールボックス(フォルダ)以下のすべてのメールボックス(フォルダ)を取得する
tell application "Mail"
  tell mailbox targMB
    set aList to name of every mailbox
  end tell
end tell

–指定フォルダ以下のMailboxをサブフォルダまで再帰ですべて取得する
repeat with i in aList
  set j to contents of i
  
set tmpPath to targMB & "/" & j
  
set the end of (fullSubPath of spd) to tmpPath
  
getEverySubMailbox(tmpPath) of me
end repeat

–全サブフォルダから指定文字列をSubjectに含むものをすべて取得する
repeat with i in (fullSubPath of spd)
  set tmpBox to contents of i
  
  
tell application "Mail"
    tell mailbox tmpBox
      set mesList to (every message)
    end tell
    
    
–指定フォルダ中のMailでループ
    
repeat with ii in mesList
      set jj to contents of ii
      
set attS to mail attachment of jj
      
      
if attS is not equal to {} then
        
        
–Mailの添付ファイルを順次指定フォルダに保存する
        
repeat with iii in attS
          set jjj to contents of iii
          
set aName to name of jjj
          
          
set aExt to getPathExtension(aName) of me
          
if aExt is in targList then
            set savePath to (targFol as string) & aName
            
            
–指定パスに添付ファイルを保存
            
save jjj in file savePath
          end if
        end repeat
        
      end if
    end repeat
  end tell
  
end repeat

–指定のメールボックス(フォルダ)以下にあるすべてのサブフォルダを(propertyに)追記して返す
on getEverySubMailbox(aPath)
  tell application "Mail"
    tell mailbox aPath
      set aaList to name of every mailbox
      
if aaList is not equal to {} then
        repeat with i in aaList
          set j to contents of i
          
set tmpFullPath to aPath & "/" & j
          
copy tmpFullPath to newPath
          
set the end of (fullSubPath of spd) to newPath
          
getEverySubMailbox(newPath) of me
        end repeat
      end if
    end tell
  end tell
end getEverySubMailbox

–Message Viewerで現在表示中のメールボックスの情報を1つのみ返す
on getSelectedOneMailBox()
  tell application "Mail"
    tell message viewer 1
      set mbList to selected mailboxes
    end tell
  end tell
  
if length of mbList is equal to 0 then
    return ""
  end if
  
  
set aMailBox to contents of (item 1 of mbList)
  
return aMailBox
end getSelectedOneMailBox

–Mail.appのメールボックスオブジェクトを渡すと、テキストのフルパスに変換
on extraxctTextFullPathOfMBObject(aPath)
  tell application "Mail"
    try
      set parentPath to container of aPath
    on error
      return
    end try
    
    
set meName to name of aPath
    
if aFullPath = "" then –1回目のみスラッシュを入れないで処理
      set aFullPath to meName
    else
      –通常処理はこちら
      
set aFullPath to meName & "/" & aFullPath
    end if
    
    
extraxctTextFullPathOfMBObject(parentPath) of me –再帰呼び出し
  end tell
end extraxctTextFullPathOfMBObject

–ファイル名から拡張子を取得する
on getPathExtension(aStr as string)
  set pathString to current application’s NSString’s stringWithString:aStr
  
return (pathString’s pathExtension()) as string
end getPathExtension

★Click Here to Open This Script 

Posted in list | Tagged 10.11savvy 10.12savvy Mail NSString | Leave a comment

Post navigation

  • Older posts
  • Newer posts

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

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • CotEditorで2つの書類の行単位での差分検出
  • macOS 15, Sequoia
  • 指定のWordファイルをPDFに書き出す
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • Numbersで選択範囲のセルの前後の空白を削除
  • メキシカンハットの描画
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AdobeがInDesign v19.4からPOSIX pathを採用
  • AppleScriptによる並列処理
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • Cocoa Scripting Course 続刊計画
  • macOS 14.xでScript Menuの実行速度が大幅に下がるバグ
  • AppleScript入門③AppleScriptを使った「自動化」とは?
  • NaturalLanguage.frameworkでNLEmbeddingの処理が可能な言語をチェック
  • Keynote/Pagesで選択中の表カラムの幅を均等割
  • Keynote、Pages、Numbers Ver.14.0が登場
  • macOS 15 リモートApple Eventsにバグ?
  • デフォルトインストールされたフォント名を取得するAppleScript
  • AppleScript入門① AppleScriptってなんだろう?

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1391) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (212) 13.0savvy (193) 14.0savvy (145) 15.0savvy (126) CotEditor (66) Finder (51) iTunes (19) Keynote (116) NSAlert (61) NSArray (51) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (53) NSDictionary (28) NSFileManager (23) NSFont (21) NSImage (41) NSJSONSerialization (21) NSMutableArray (63) NSMutableDictionary (22) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (119) NSURL (98) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (76) Pages (54) Safari (44) Script Editor (27) WKUserContentController (21) WKUserScript (20) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • Beginner
  • Benchmark
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • check sum
  • Clipboard
  • Cocoa-AppleScript Applet
  • Code Sign
  • Color
  • Custom Class
  • dialog
  • diff
  • drive
  • Droplet
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • Font
  • GAME
  • geolocation
  • GUI
  • GUI Scripting
  • Hex
  • History
  • How To
  • iCloud
  • Icon
  • Image
  • Input Method
  • Internet
  • iOS App
  • JavaScript
  • JSON
  • JXA
  • Keychain
  • Keychain
  • Language
  • Library
  • list
  • Locale
  • Localize
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • parallel processing
  • PDF
  • Peripheral
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • rectangle
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • Review
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • selection
  • shell script
  • Shortcuts Workflow
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Telephony
  • Text
  • Text to Speech
  • timezone
  • Tools
  • Update
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2024年2月
  • 2024年1月
  • 2023年12月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年12月
  • 2019年11月
  • 2019年10月
  • 2019年9月
  • 2019年8月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年11月
  • 2018年10月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年5月
  • 2018年4月
  • 2018年3月
  • 2018年2月

https://piyomarusoft.booth.pm/items/301502

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org

Forum Posts

  • 人気のトピック
  • 返信がないトピック

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org
Proudly powered by WordPress
Theme: Flint by Star Verte LLC