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

指定文字のシフトJIS内文字かのチェック

Posted on 2月 28, 2021 by Takaaki Naganoya

指定の文字がシフトJISのコードの範囲に存在しているかどうかをチェックするAppleScriptです。

絵文字とか、日本国内で使われていない(CJK統合漢字のうち日本で使われていない)漢字を除外するために作ってみたものです。もともと、半角文字と全角文字の判定を行うためにNSASCIIStringEncodingに変換できるかどうかを調べるサンプルがあったので、「JIS第1/第2水準文字だけ調べるのに同様の処理で済むのでは?」と考えて試してみたものです。


▲実際のプログラムリスト。プログラムリスト下部のURL Linkをクリックすると、文字列が欠落していないすべての内容がスクリプトエディタ上に転送されます

AppleScript名:指定文字のシフトJIS内文字かのチェック.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/02/28
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set a1Res to chkSJISChar("微") of me
–> true

set a2Res to chkSJISChar("") of me
–> false

set a3Res to chkSJISChar("熙") of me
–> true

set a4Res to chkSJISChar("") of me
–> false

return {a1Res, a2Res, a3Res, a4Res}
–> {true, false, true, false}

on chkSJISChar(aChar as string)
  set aStr to current application’s NSString’s stringWithString:aChar
  
set tmpStr1 to (aStr’s canBeConvertedToEncoding:(current application’s NSShiftJISStringEncoding))
  
return tmpStr1 as boolean
end chkSJISChar

★Click Here to Open This Script 

Posted in Text | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy | Leave a comment

私はロボットではありません

Posted on 2月 25, 2021 by Takaaki Naganoya

Web上でクローリングロボットとユーザーが普通にWebブラウズしているのを区別するのに、複数の画像をクリックさせて判定するプログラムが広く利用されています。

AppleScript関連の画像でこれを作るとどうなるのか? と、考えて手短に作ってみたものです。激ムズです。

意外と難しいので、ほとんどの人類がこれをパスできないはずです。

下段、左:Google Apps Script、中央:Classic Mac OSのAppleScript、右:何か別のもの
上段、左:macOS 11.0上のAppleScript書類(たぶんバグ?)、中央:AppleScript書類、右:VBS

Posted in news | Leave a comment

指定した文字で囲まれたキーワードの色を置換する

Posted on 2月 24, 2021 by Takaaki Naganoya

Keynoteで現在オープン中の書類の現在表示中のスライド(ページ)中にあるtext itemのうち、開始文字、終了文字ではさまれているテキストを指定色に塗り替えるAppleScriptです。

用途はご覧の通り、現在作成中のCocoa Scripting本の資料の装飾のためであり、「|」と「|」で囲まれている箇所の色を変えたら見やすいのでは? と、考えて作成・実行したものです。

NSScannerを使えば楽に書けるかも? などと思っておりましたが、検出位置(文字数)を返す機能がないので、位置だけを返してほしいという用途に向いていないもよう。仕方なく、普通にAppleScriptで1文字ごとチェック&開始文字/終了文字のチェックをフラグ管理……という、高級言語らしからぬ泥臭いコードを書く羽目に(でも、こういうの書くケースが多いですよね)。


▲実行前


▲実行後

AppleScript名:指定した文字で囲まれたキーワードの色を置換する
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/02/24
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

set targCol to choose color –塗る文字色を選択

set headPickUpChar to "|"
set tailPickUpChar to "|"

–処理対象データの取得
tell application "Keynote"
  
  
–最前面の書類
  
tell front document
    
    
–現在表示中のスライド
    
tell current slide
      –text itemをすべて取得
      
set tList to every text item
      
if tList = {} then return –何もtext itemが存在しなかったら処理終了
      
      
–text itemの中に入っている文字列を取得
      
set objTList to object text of every text item
      
    end tell
  end tell
end tell

–出現判定しつつ色を塗る
tell application "Keynote"
  tell front document
    tell current slide
      
      
set posList to {}
      
set aCount to 1
      
      
–text itemでループ
      
repeat with i in objTList
        set j to contents of i
        
        
–ターゲット文字で囲まれている箇所を検出。複数箇所検出対応
        
set bCon to pickUpPositionPairsFromTo(j, headPickUpChar, tailPickUpChar) of me
        
        
if bCon is not equal to {} then
          
          
set aTarg to item aCount of tList
          
          
–出現位置でループ(複数検出対応)
          
repeat with ii in bCon
            copy ii to {aStart, anEnd}
            
            
–高速処理のために非同期実行
            
ignoring application responses
              tell aTarg
                set color of characters aStart thru anEnd of object text to targCol
              end tell
            end ignoring
            
          end repeat
          
        end if
        
        
set aCount to aCount + 1
      end repeat
      
    end tell
  end tell
end tell

–開始文字と終了文字に囲われた文字列のすべての位置情報を返す
on pickUpPositionPairsFromTo(aParamStr, fromStr, toStr)
  script hsAry
    property anArray : {}
    
property aList : {}
  end script
  
  
set (anArray of hsAry) to {}
  
set (aList of hsAry) to characters of aParamStr
  
  
set tmpPair to {}
  
set searchMode to 0 — 0:fromStr, 1:toStr
  
set aCount to 1
  
  
repeat with i in (aList of hsAry)
    set j to contents of i
    
    
if searchMode = 0 then
      if j = fromStr then
        set the end of tmpPair to aCount
        
set searchMode to 1
      end if
      
    else if searchMode = 1 then
      if j = toStr then
        set the end of tmpPair to aCount
        
set searchMode to 0
        
set the end of (anArray of hsAry) to tmpPair
        
set tmpPair to {}
      end if
    end if
    
    
set aCount to aCount + 1
  end repeat
  
  
return (anArray of hsAry)
end pickUpPositionPairsFromTo

★Click Here to Open This Script 

Posted in Color Text | Tagged 10.14savvy 10.15savvy 11.0savvy Keynote | 1 Comment

AVFAudioでオーディオ再生のじっけん

Posted on 2月 23, 2021 by Takaaki Naganoya

macOS 11.3で追加されたAVFAudio.frameworkを用いてオーディオ再生を行うAppleScriptです。

実行にはmacOS 11.3以降が必要です。オーディオファイル以外(ムービーなど)を渡すと終了します。

AppleScript名:AVFAudio test 1
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/02/23
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.7" — macOS 11.3 or later
use framework "Foundation"
use framework "AppKit"
use framework "AVFAudio"
use scripting additions

set posixPath to POSIX path of (choose file with prompt "Choose an Audio file:")
set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath
set aPlayer to current application’s AVAudioPlayer’s alloc()’s initWithContentsOfURL:theURL |error|:(missing value)
if aPlayer = missing value then return

aPlayer’s play()
delay 30
aPlayer’s |stop|()

★Click Here to Open This Script 

Posted in Sound | Tagged 11.0savvy | Leave a comment

構成要素を指定して漢字検索 v3

Posted on 2月 22, 2021 by Takaaki Naganoya

旧称「部首で漢字検索」のバージョンアップ版です。部首ではなく構成部品の文字を指定して漢字を検索するAppleScriptです。

便利な道具ではありますが、あくまでも子供の学習用以外の用途にお使いください。

–> Download kanjiSearchFromPartsV3.zip (AppleScript Bundle with library and JSON files in its bundle)

前バージョンでは常用漢字の範囲を超えるデータが出力されるという問題点があったため、常用漢字の一覧データを作成し、これに合致するものだけを出力するようにしました。

常用漢字との照合処理に時間がかかっており、v2ではAppleScriptのネイティブ機能でループして除外チェックを行なっておりました。これをv3ではCocoaの機能を用いて一括で重複部分の抽出を行うことで、v2の半分の時間で完了できることに。v2で0.6秒程度かかっていたものが、v3では0.3秒を下回る時間で処理できるようになりました(MacBook Pro Core i7 2.66GHz)。

そもそも論でいえば、元のJSONデータから常用漢字+人名漢字を超える文字の情報を削除すればいいだけの話なので、JSONデータから常用漢字+人名漢字を超える文字を削除するプログラムを書いて実行するのがよいのでしょう。

AppleScript名:構成要素を指定して漢字検索 v3.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/02/21
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.7"
use framework "Foundation"
use scripting additions
use jkLib : script "jyoyoKanjiLib" –常用漢字一覧を返してくるAppleScriptライブラリ

script jsonStr
  property aJsonDict : missing value –JSONから読み取ったNSDictionary
  
property jKanji : missing value –常用漢字データ(NSArray)
end script

property NSString : a reference to current application’s NSString
property NSCountedSet : a reference to current application’s NSCountedSet
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

–図形としての構成要素を指定して漢字検索(部首ではない)
–set aRes to searchKanjiFromElementJ("木") of me –きへん? のぎへんや他のものも返ってくるよ
–> {"椅", "植", "椎", "検", "頼", "漆", "鉢", …}

–set bRes to searchKanjiFromElementJ("氵") of me –さんずい
–> {"滴", "漁", "漂", "漆", "漏", "演", "漠",…}

set dRes to searchKanjiFromElementJ("⻖") of me
–>{"堕", "墜", "阪", "防", "阻", "附", "降"…}

–検索に使える部首のキー文字の一覧を返す
–set qList to listupQueryKeysForKanji() of me
–> {"工", "棘", "左", "位", "婁", "攴", …}

on searchKanjiFromElementJ(aQueryStr)
  if (aJsonDict of jsonStr) = missing value then my init()
  
if (jKanji of jsonStr) = missing value then my initJ()
  
set aRes to (aJsonDict of jsonStr)’s valueForKey:aQueryStr
  
if aRes = missing value then return missing value
  
  
set cArray to aRes’s arrayByAddingObjectsFromArray:(jKanji of jsonStr)
  
set cRes to returnDuplicatesOnly(cArray) of me
  
return cRes
end searchKanjiFromElementJ

on searchKanjiFromElement(aQueryStr)
  if (aJsonDict of jsonStr) = missing value then my init()
  
set aRes to (aJsonDict of jsonStr)’s valueForKey:aQueryStr
  
if aRes = missing value then return missing value
  
return aRes as list
end searchKanjiFromElement

on listupQueryKeysForKanji()
  if (aJsonDict of jsonStr) = missing value then my init()
  
set aRes to (aJsonDict of jsonStr)’s allKeys()
  
return aRes as list
end listupQueryKeysForKanji

on initJ()
  set (jKanji of jsonStr) to current application’s NSArray’s arrayWithArray:(retJyouyouKanji() of jkLib)
end initJ

on init()
  –https://github.com/yagays/kanjivg-radical
  
set aPath to (POSIX path of (path to me)) & "Contents/Resources/element2kanji.json"
  
set jsonString to NSString’s alloc()’s initWithContentsOfFile:(aPath) encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set (aJsonDict of jsonStr) to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
end init

on returnDuplicatesOnly(anArray)
  set aSet to NSCountedSet’s alloc()’s initWithArray:anArray
  
set bList to (aSet’s allObjects()) as list
  
  
set dupList to {}
  
repeat with i in bList
    set aRes to (aSet’s countForObject:i)
    
if aRes > 1 then
      set the end of dupList to (contents of i)
    end if
  end repeat
  
  
return dupList
end returnDuplicatesOnly

★Click Here to Open This Script 

Posted in JSON Record | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy | Leave a comment

部首で漢字検索

Posted on 2月 21, 2021 by Takaaki Naganoya

漢字の部首を指定して、漢字を検索するAppleScriptです。厳密にいえば「部首」の文字ではなく、それっぽい文字で探せます。用途や利用者を想定できれば(子供が勉強用に使わないのであれば)十分に有用だと思います(理由は後述)。

Unicodeのデータから検索できるのではないかと考え、Unicodeの規格を調べていたのですが、漢字のSVGデータから構成文字情報を抽出したとされる「kanjivg-radical」を偶然みつけ、これを利用することで、割と手軽に実現できました。

–> kanjiSearch.zip(Download Script Bundle included JSON in its bundle)

開発環境のMac(Intel Core i7 2.66GHz)で、キャッシュがヒットしていれば(JSONから変換したデータがpropertyに読み込まれていれば)0.02秒程度で検索できています。この手の処理はデータのローディング(読み込み)が命なので、SSD使用必須です。

同データはJSON形式なので、AppleScriptバンドル中にJSONのまま突っ込んで、Cocoaの機能を用いてNSDictionaryに読み込んで検索しています。

ほかにも、Mac OS Xへの移行時に散々紹介されたMac OS Xのビックリドッキリ機能「関連文字に変換」をAppleScriptで実現した「関連文字を検索」も作ってみました。

このあたりをまとめてAppleScriptライブラリにしておけば便利そうですが、まだ使い勝手をテストしている段階です。義務教育で習う漢字の構成要素(へん、つくり etc)の呼び名とkanjivg-radicalで利用できる構成パーツの間に不整合(kanjivg-radicalの方が柔軟)があるので、そのあたりを埋めないと使いにくそう(下手に子供が使うと間違った国語知識を持ってしまう)な危険があるので、そのあたりを補う必要性を感じます。

たとえば、「禾」(のぎへん)を持つ漢字を「木」で検索できてしまうところです。大人は「実用的で使いやすい!」と喜ぶところですが、義務教育課程では両者は厳密に区別されています。自分は使いやすいので喜んで使っていますが、用途によっては使わないほうがよいかもしれません。

追記:

へんやつくりを元に検索できるデータとして、同梱の「radical2kanji_left_right.json」や「radical2kanji_top_bottom.json」が存在していることに気づいたので、そちらをAppleScriptのバンドル中に入れて、同様に検索してみました。

ただ、こちらのデータは随分と粗が多く、「⻖」(こざとへん)で自分の名前に使われている「隆」を「radical2kanji_left_right.json」から検索したところヒットしません。

{"阨", "陵", "隈", "険", "陣", "院", "陲", "陦", "陽", "陳", "陬", "隧", "險", "除", "隍", "陜", "陀", "陏", "隗", "階", "障", "隕", "降", "陂", "隴", "隔", "際", "隅", "附", "限", "陸", "陟", "陌", "阮", "阡", "阯", "阻", "阿", "阪", "防"}

国語辞書や文字コード表との照合といいますか、きちんとした検証作業は行われておらず、機械的に処理しただけのデータという印象を受けます。

一方で、「element2kanji.json」を用いて「⻖」(こざとへん)で検索したところ、

{"嶐", "阨", "蔭", "橢", "薩", "隣", "婀", "陵", "隈", "窿", "険", "隠", "陷", "陣", "痾", "院", "陶", "隙", "陲", "陦", "陽", "陪", "陳", "隘", "陥", "陬", "墜", "隧", "陰", "險", "除", "隍", "陜", "陀", "陛", "陏", "隗", "階", "障", "隕", "降", "陂", "隨", "隴", "隔", "随", "際", "隋", "陞", "隰", "墮", "隱", "陝", "隅", "隊", "附", "限", "陋", "陸", "陟", "隲", "陌", "隆", "阮", "阡", "阯", "阻", "阿", "阪", "堕", "防"}

と、結果が返ってきており……どうも複数のJSONデータを用いて、へんやつくりを考慮したJSONデータで検索して、ヒットしなかったら「element2kanji.json」を用いて物量でダメ押しするように設計されているようです。つまり、「radical2kanji_left_right.json」や「radical2kanji_top_bottom.json」が粗いのを複数のデータで補うように使うものである、と。

無限の量とバリエーションを持つデータに対するアプローチとしては間違っていないと思いますが、文字コードという有限のデータに対しての処理としては少し疑問が残る実装です。本当に使い物になるデータにするには、実際に人間の手による検証と校正が必要な内容でしょう。そのことは明記されるべきです。

「element2kanji.json」は現状のままで有用だと思いますが、「radical2kanji_left_right.json」や「radical2kanji_top_bottom.json」については、実際に国語辞典と照合してデータを補わないと実用レベルにはならないと感じました。盲目的に信用しないで、手元で実際に評価・検証することが重要です。

データ自体、CJK(中国語、日本語、韓国語)の統合漢字をサポートする範囲で作成されているようで、日本語で日常的に利用する常用漢字よりも幅広い文字がデータ化されています。常用漢字の範囲内に含まれているかをチェックするデータを併用するのが妥当でしょう。

AppleScript名:部首で漢字検索.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/02/21
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.7"
use framework "Foundation"
use scripting additions

script jsonStr
  property aJsonDict : missing value
end script

property NSString : a reference to current application’s NSString
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

–部首を指定して漢字検索
set aRes to searchKanjiFromElement("木") of me –きへん
–> {"稾", "欅", "謀", "酥", "悚", "椁", "検"….}

–set bRes to searchKanjiFromElement("氵") of me–さんずい
–> {"溯", "湮", "漁", "漕", "濶", "懣", "添", "淨",…..}

–set cRes to searchKanjiFromElement("之") of me
–> {"芝", "泛", "貶", "乏"}

–set dRes to searchKanjiFromElement("⻖") of me
–> {"嶐", "阨", "蔭", "橢", "薩", "隣", "婀"…}

–検索に使える部首のキー文字の一覧を返す
–set qList to listupQueryKeysForKanji() of me
–> {"工", "棘", "左", "位", "婁", "攴", "巨", "攵"…}

on searchKanjiFromElement(aQueryStr)
  if (aJsonDict of jsonStr) = missing value then my init()
  
set aRes to (aJsonDict of jsonStr)’s valueForKey:aQueryStr
  
if aRes = missing value then return missing value
  
return aRes as list
end searchKanjiFromElement

on listupQueryKeysForKanji()
  if (aJsonDict of jsonStr) = missing value then my init()
  
set aRes to (aJsonDict of jsonStr)’s allKeys()
  
return aRes as list
end listupQueryKeysForKanji

on init()
  –https://github.com/yagays/kanjivg-radical
  
set aPath to (POSIX path of (path to me)) & "Contents/Resources/element2kanji.json"
  
set jsonString to NSString’s alloc()’s initWithContentsOfFile:(aPath) encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set (aJsonDict of jsonStr) to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
end init

★Click Here to Open This Script 

Posted in File path JSON Record | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy NSJSONSerialization NSString NSUTF8StringEncoding | Leave a comment

ページ範囲処理 v2

Posted on 2月 14, 2021 by Takaaki Naganoya

処理対象ページをユーザーに文字入力させた場合に、

X1,X2,X3,Y-Z

のようなフォーマットを解釈して、処理対象ページ番号をすべて展開するAppleScriptです。

もともと16年前に作成したScriptを書き換えたものです。オリジナルもとくに現行環境で問題なく動いているのですが、ソートルーチンを高速なものに差し替えています。ただし、処理データの量がたいして多くないことを前提としているため(数万ページ指定しないとCocoaのソートルーチンを利用するメリットがない)、Cocoaのソートルーチンは使っていません。

AppleScript名:ページ範囲処理 v2
—
–  Created by: Takaaki Naganoya
–  Created on: 2005/11/04
–  Modified on: 2021/02/14
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set parsedList to parsePageRangeString("1-10, 35, 37, 39, 100-110") of me
–> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 35, 37, 39, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110}

–ページ範囲指定のテキスト(多分)を展開して実際のページ数の一覧リストに
on parsePageRangeString(pageText as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to ("," as string)
  
set aList to text items of pageText
  
set AppleScript’s text item delimiters to curDelim
  
  
set eList to {}
  
repeat with i in aList
    set j to contents of i
    
if ("-" as string) is in j then
      set eList to eList & parseByHyphen(j) of me
    else
      set the end of eList to j as number
    end if
  end repeat
  
  
set eList to removeDuplicates(eList) of me
  
set eList to shellSortAscending(eList) of me
  
  
return eList
end parsePageRangeString

–重複部分を削除
on removeDuplicates(aList)
  set newList to {}
  
repeat with i from 1 to (length of aList)
    set anItem to item 1 of aList
    
set aList to rest of aList
    
if {anItem} is not in aList then set end of newList to anItem
  end repeat
  
return newList
end removeDuplicates

–ハイフンを実際の数値に変換
on parseByHyphen(aText)
  set aText to aText as string
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to ("-" as string)
  
set aList to text items of aText
  
set AppleScript’s text item delimiters to curDelim
  
  
set sList to {}
  
repeat with i from ((item 1 of aList) as number) to ((item 2 of aList) as number)
    set the end of sList to i
  end repeat
  
return sList
end parseByHyphen

–入れ子ではないリストの昇順ソート
on shellSortAscending(aSortList)
  script oBj
    property list : aSortList
  end script
  
  
set len to count oBj’s list’s items
  
set gap to 1
  
  
repeat while (gap ≤ len)
    set gap to ((gap * 3) + 1)
  end repeat
  
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len – 1)
        set temp to oBj’s list’s item (i + 1)
        
set j to i
        
repeat while ((j ≥ gap) and (oBj’s list’s item (j – gap + 1) > temp))
          set oBj’s list’s item (j + 1) to oBj’s list’s item (j – gap + 1)
          
set j to j – gap
        end repeat
        
set oBj’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
  
return oBj’s list
end shellSortAscending

★Click Here to Open This Script 

Posted in list Text | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy | Leave a comment

CotEditorの各Windowで選択しておいた内容を座標でソートして結合

Posted on 2月 11, 2021 by Takaaki Naganoya

CotEditorでオープン中の複数のウィンドウから、各ウィンドウ(書類)の選択範囲を取得し、各ウィンドウの画面上の位置情報をもとに、その順番(Y座標、X座標)にテキストを組み合わせて新規書類を作成するAppleScriptです。


▲DEMO


▲Live Coding

当初、ウィンドウの重ね合わせ順(windowのindex)も考慮していたのですが、実際にためしてみたところ、重ね合わせ順を使うのは無駄だったので、機能を外しました。

AppleScript名:CotEditorの各Windowで選択しておいた内容を重ね合わせ順と座標でソートして結合.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/02/10
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

set wList to {}

tell application "CotEditor"
  set wCount to count (every window whose visible is true)
  
if wCount < 2 then return
  
  
repeat with i from 1 to wCount
    tell window i
      set tmpBounds to bounds
      
      
set tmpProp to properties
    end tell
    
    
set tmpDoc to document of tmpProp
    
tell tmpDoc
      set aCon to contents of selection
    end tell
    
    
set tmpX to item 1 of tmpBounds
    
set tmpY to item 2 of tmpBounds
    
set tmpRec to {winIndex:i, winX:tmpX, winY:tmpY, selText:aCon}
    
    
set the end of wList to tmpRec
    
  end repeat
  
end tell

–座標値をもとにソートして選択テキストを返す
set sWList to sortRecListByLabel(wList, {"winY", "winX"}, {true, true}) of me
set anArray to current application’s NSArray’s arrayWithArray:sWList
set vList to (anArray’s valueForKey:"selText") as list
set jointStr to retArrowText(vList, return) of me

–CotEditor上で指定テキストでドキュメントを新規作成
makeNewCotEditorDoc(jointStr) of me

–リストを指定デリミタを追加しつつテキスト化
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList as list, aLabelStr as list, ascendF as list)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
  
set aCount to length of aLabelStr
  
set sortDescArray to current application’s NSMutableArray’s new()
  
repeat with i from 1 to aCount
    set aLabel to (item i of aLabelStr)
    
set aKey to (item i of ascendF)
    
set sortDesc to (current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabel ascending:aKey)
    (
sortDescArray’s addObject:sortDesc)
  end repeat
  
  
return (aArray’s sortedArrayUsingDescriptors:sortDescArray) as list
end sortRecListByLabel

–指定テキストでCotEditorの新規書類を作成
on makeNewCotEditorDoc(aCon)
  tell application "CotEditor"
    activate
    
set newDoc to make new document
    
tell newDoc
      set contents to aCon
    end tell
  end tell
end makeNewCotEditorDoc

★Click Here to Open This Script 

Posted in list Record | Tagged 10.14savvy 10.15savvy 11.0savvy CotEditor | Leave a comment

We released English edition of “FileMaker Pro Scripting Book with AppleScript”

Posted on 2月 9, 2021 by Takaaki Naganoya

Just we released English edition of ebook “FileMaker Pro Scripting Book with AppleScript”.

–> Download Sampler PDF

Title:FileMaker Pro Scripting Book with AppleScript English Edition
Author:Takaaki Naganoya@Piyomaru Software
Technical Supervisor:Masayuki Nii
Price: JPY 3,000 (About USD 30)@our ebook store, JPY 3,500+VAT 10%@PayPal
Delivery: Soon@our ebook store, 1 business day @ paypal (Check and return your URL on cloud storage via email)
Page:158
File format:PDF
Supplement : AppleScript files / RTF exported files / Piyomaru Script Assistant v2 (Japanese Version)

–> Online Store
–> Product Support page





Somebody asked me “Is there English version?” on twitter. I started translation project at that word.

At that point, I thought the translation project wouldn’t be too much hassle.But…it was wrong for me. It took more effort to translate it than write original Japanese version.

Japanese is a strange language. The subject can be omitted.Writing Japanese sentences makes a lot of effort to create a “good atmosphere” rather than facts.

It was very hard work. I added about 20 pages to explain the current status and history of AppleScript itself.

I hope this book will reach a large number of users.

Posted in PRODUCTS | Tagged 10.14savvy 10.15savvy 11.0savvy FileMaker Pro | Leave a comment

最前面のKeynote書類のテキストアイテムの英語化率を求める

Posted on 1月 28, 2021 by Takaaki Naganoya

Keynote書類内のテキストアイテムのうち、どの程度が英語で書かれているかを計算するAppleScriptです。macOS 10.14以降で動作します。

日本語で書いた本を英語に翻訳しているわけですが、進捗を確認するのに自分でページを見ながら確認する作業が地味に大変です。そこで、この大変な作業をAppleScriptで自動処理することにしました。最終的なチェックは目視で行う必要がありますが、翻訳済みのテキストがどの程度あるかをテキストアイテムの個数ベースで(文章の長さは考慮せず)自動計算します。

AppleScriptでKeynote書類中のテキストアイテム中のテキストをすべて取得し、言語を自動判定して英語化率(≒英訳作業の進捗率)を計算してみました。


▲Script Debugger v8で実行したところ。Dark Modeへの対応が嬉しいが、全体的に動作が重い

日本語と英語以外にいろいろ意図しない言語判定されているテキストアイテムが存在していますが、そんな言語は書いていないのでおおよそ英語ブロックでしょう。

いま英語化率は80%と出ていますが、誤判定もあるはずなので、最後の最後は目視判定が必要と思われます。あとは、日本語フォントが指定されている箇所をクリーニングして、英語フォントに指定し直す作業も必要です。

開発マシンでmacOS 10.14.6+Keynote 10.1の環境で、139ページある「FileMaker Pro Scripting Book」の全テキスト判定に3.9秒ほどかかります。速度面でとくに不満はありませんが、こういう処理をM1 Macで行うとどの程度の速度になるのかには興味があります。

FileMaker選手権に応募した作品が入賞すれば、開発マシンの更新も可能かもしれませんが……勝負は時の運ということで。


▲英語への翻訳が完了したページ(表紙)


▲まだ日本語の文章がまだらに残っているページ。ただ、オリジナルの日本語版をもとに日本語の本のルールでページ順を設定しているので、「本当にこれでいいのか?」(奥付が最終ページにある日本スタイルそのまま、とか)とは思っています

AppleScript名:最前面のKeynote書類のテキストアイテムの英語化率を求める.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/01/27
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.7" — High Sierra (10.13) or later
use framework "Foundation"
use framework "NaturalLanguage" –Mojave (10.14) or later
use scripting additions

tell application "Keynote"
  set dCount to count every document
  
if dCount = 0 then
    display notification "There is no Keynote document"
    
return {}
  end if
end tell

set tOut to {}
set erOut to {}

tell application "Keynote"
  tell front document
    set sCount to count every slide
    
repeat with i from 1 to sCount
      tell slide i
        set tList to every text item
        
        
repeat with i in tList
          set aTmpStr to object text of i
          
if aTmpStr is not equal to "" then
            set b1Res to guessLanguageCodeOf(aTmpStr) of me
            
set the end of tOut to b1Res
            
(*
            if b1Res is not equal to "en" then
              set the end of erOut to aTmpStr
            else
              set the end of tOut to b1Res
            end if
            *)

          end if
        end repeat
      end tell
    end repeat
  end tell
end tell

set tPercent to calcOneItemsPercent(tOut, "en") of me

on guessLanguageCodeOf(theString as string)
  set aNL to current application’s NLLanguageRecognizer’s alloc()’s init()
  
aNL’s processString:theString
  
set langRes to (aNL’s dominantLanguage()) as string
  
return langRes
end guessLanguageCodeOf

–true/falseで構成されるlistのうち、指定要素が占める割合を%で計算。小数点以下を四捨五入
on calcOneItemsPercent(aList, targItem)
  set aLen to length of aList
  
set theCountedSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set tRes to (theCountedSet’s countForObject:targItem)
  
if tRes < 1 then return 0
  
set pRes to (tRes / aLen) * 100
  
return (round pRes rounding as taught in school)
end calcOneItemsPercent

★Click Here to Open This Script 

Posted in Language Text | Tagged 10.14savvy 10.15savvy 11.0savvy Keynote | 1 Comment

Keynoteで選択中のテキストアイテムからテキスト取り出し

Posted on 1月 27, 2021 by Takaaki Naganoya

Keynoteで選択中のテキストアイテムからテキスト情報を抽出するAppleScriptです。

# 本内容は当時のKeynote v11.xの状況を反映したもので、その後リリースされたv12ではselectionを取得できるように変更されました

FileMaker Pro Scripting Bookの英語版を来る日も来る日も作っており、気づけばぜんぜんScriptを書いていないので「Piyomaru Software」ではなく「Piyomaru Publishing」だ、などと言っている今日このごろです。Keynoteを毎日使っていますが、微妙に痒いところに手が届かないので、使えば使うほどAppleScriptで機能を補いたくなってきます。

Keynoteに「selected objects」といった「選択中のオブジェクト」を求めるAppleScript用語が用意されていないため、本来やりたい「選択中の部品のデータを処理して元の部品に書き戻す」「選択中の部品からデータを抜き出す」といった処理ができません。selectionで取得できるのが「選択中のスライド」だというのが非常に残念です。

Keynote書類でテキストアイテムを選択し、コピーすると……テキスト情報は取り出せません。Finder上でクリップボード内容を確認してみると、あろうことか「PNGイメージ」と表示されます。

コピーされたクリップボードの内容を解析して、そのオブジェクト情報からテキストを抽出できるとよいだろうか、などとも考えたのですが、

Keynote内部オブジェクトで、ちょっと手強そうです。

というわけで、Keynote側には一切機能がないわけですが、選択中のオブジェクトをコピーし、新規ドキュメントにペーストしたうえで新規ドキュメント上のオブジェクトからテキストを取り出し、新規ドキュメントを破棄することにしました。

GUI Scriptingを用いているので、システム環境設定の「セキュリティとプライバシー」でGUI Scriptingを許可してから実行してください。

AppleScript名:選択中のテキストアイテムからテキスト取り出し.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/01/27
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set kList to getEveryTextFromCurrentKeynoteSlide() of me
set tRes to retDelimedText(kList, return) of me

on getEveryTextFromCurrentKeynoteSlide()
  tell application "Keynote"
    activate
    
    
set dCount to count every document
    
if dCount = 0 then
      display notification "There is no Keynote document"
      
return {}
    end if
    
    
tell front document
      set sCount to count every slide
    end tell
    
if sCount = 0 then
      display notification "There is no Slide in Keynote document"
      
return {}
    end if
    
  end tell
  
  
–Copy
  
tell application "System Events"
    keystroke "c" using {command down}
  end tell
  
  
  
tell application "Keynote"
    activate
    
set nDoc to make new document
    
tell nDoc
      set aMaster to master slide "空白"
      
–set aMaster to master slide "Blank"
      
      
tell current slide
        set base slide to aMaster
      end tell
    end tell
    
  end tell
  
  
–Paste
  
tell application "System Events"
    keystroke "v" using {command down}
  end tell
  
  
delay 0.1 –Important!!
  
  
set tOut to {}
  
tell application "Keynote"
    tell front document
      tell current slide
        set tList to every iWork item
        
        
repeat with i in tList
          set aTmpStr to object text of i
          
set the end of tOut to aTmpStr
        end repeat
      end tell
    end tell
    
    
–Dispose document
    
tell front document
      close without saving
    end tell
  end tell
  
  
return tOut
end getEveryTextFromCurrentKeynoteSlide

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

★Click Here to Open This Script 

Posted in GUI Scripting Text | Tagged 10.14savvy 10.15savvy 11.0savvy Keynote | Leave a comment

AppleScript disassembler

Posted on 1月 23, 2021 by Takaaki Naganoya

Twitterで一時期さんざん騒がれていた(一部のアカウントが情報を拡散していた)、AppleScript Disasemblerについて調べてみました。

いわく、

「Macには5年前からウィルス(マイニングツール?)が出回っている。というのも、実行専用のAppleScript appletはAppleのウィルスチェックの対象から外れており、中身を確認できないからである。この脅威に対処するためのツールはXXに問い合わせるとよい。aevt disassemblerなどのツールを用意している」

という内容のものでした。分かりやすい恫喝です。「5年前からウィルスが」云々の是非は知りませんし、それにAppleScriptが使われているのかどうかなども知りません。見たことがないものについては、批評も判断も不可能です。

実行専用のAppleScript AppletだとAppleのチェックを免れる、という点については疑問が残ります。ただ、仮にそうしたものがあったとして、その実行内容をいちいちOS側がチェックしているとも考えにくいので、その可能性は否定できません。

そして、「aevt disassemblerなどのツール」という点、ここが問題です。本当にできるのか? 冗談ツールみたいなもの(特定条件では使えるが実用性がない)はあるのかもしれませんが、そんなに、現代の高度化しているAppleScriptのプログラムの内容を、実行専用バイナリから元ソース取り出しができるものなのか?????? これは、試してみないとなんとも言えません。

えーーー、AppleScriptはAppleEventのバイトコードに翻訳されて実行されます。

この、AppleEventのバイトコードから元のAppleScriptを戻せるかどうかについては、かなり初期から「イベントのコードと実際のAppleScriptの対処表を作れば、元のコードを取り出すことは原理上不可能ではないだろう」という推測が行われてきました。

ただ、その対処表を作るという手間がバカバカしく、苦労の割に得るものが少ないため誰も本気で取り組んでこなかったテーマでもあります。

とりあえず実行専用のAppleScriptでなければ「osadecompile」コマンドがOSに標準装備されているので、これでソースを取得することは可能です。

では、実行専用のAppleScriptやAppletからソースを取得できるのでしょうか?

Github上でそれらしきソフトウェアをみつけました。aevt_decompileとapplescript-disassemblerです。それぞれ実際に試してみました。

確認対象ファイルは、

①普通の(スクリプトエディタで)読める通常形式のAppleScript(.scpt)
②「実行専用」の通常形式のAppleScript(.scpt)
③「実行専用」のAppleScriptアプレット
④「実行専用」のAppleScriptアプレット(コード署名つき)

の4つです。主に、decompilerについて(確認もしないで)騒いでいる連中が槍玉に挙げているのは、③④のはずなので、①②はあくまで比較用です。

aevt_decompile

まず、aevt_decompileを実際にXcode上でビルドし、/usr/local/binにコピーしたうえでTerminal上から実行してみました。

Mac:bin me$ ./aevt_decompile /Users/me/Desktop/copy\ files\ to\ target\ folder.app 
2021-01-23 20:39:21.622 aevt_decompile[10457:2398389] The file “copy files to target folder” couldn’t be opened because you don’t have permission to view it.
Mac:bin me$ ./aevt_decompile /Users/me/Desktop/copy\ files\ to\ target\ folder.app/Contents/Resources/Scripts/main.scpt 
2021-01-23 20:39:55.375 aevt_decompile[10469:2400520] The file “main.scpt” couldn’t be opened using text encoding Unicode (UTF-8).
Mac:bin me$ ./aevt_decompile /Users/me/Desktop/copy\ files\ to\ target\ folder_no_sign.app/Contents/Resources/Scripts/main.scpt 
2021-01-23 20:41:02.693 aevt_decompile[10482:2405472] The file “main.scpt” couldn’t be opened using text encoding Unicode (UTF-8).
Mac:bin me$ ./aevt_decompile /Users/me/Desktop/copy\ files\ to\ target\ folder.scpt 
2021-01-23 20:41:47.007 aevt_decompile[10488:2407982] The file “copy files to target folder.scpt” couldn’t be opened using text encoding Unicode (UTF-8).

結果は、ことごとく「couldn’t be opened」でデスクトップフォルダ上に置いた①〜④のScriptをオープンできませんでした。

applescript-disassembler

Pythonで書かれたこのツールは実行権限を与えるだけで簡単に動きました。また、①〜④のファイルに対してアクセスすることができました。

こちらは結果が出てきました。かなり膨大な内容です。オリジナルのAppleScriptが、

set fileTexts to paragraphs of (the clipboard)

set chkFol to choose folder with prompt "[From] Select Check folder"
set moveTargFol to choose folder with prompt "[To] Select Copy Trget folder"

repeat with i in fileTexts
	set j to contents of i
	set fromPath to (chkFol as string) & j
	try
		tell application "Finder"
			duplicate file fromPath to moveTargFol
		end tell
	end try
end repeat

の程度のひじょうに簡単なものであったのですが、実際に出力されたのは、

# 注:HTMLタグと間違えられてしまう<>については全角記号に置き換えました

--Applet without Code Sign③

Mac:applescript-disassembler-master me$ ./disassembler.py /Users/me/Desktop/copy\ files\ to\ target\ folder_no_sign.app/Contents/Resources/Scripts/main.scpt 
=== data offset 2 ===
Function name : <Value type=object value=<Value type=event_identifier value=b'aevt'-b'oapp'-b'null'-b'\x00\x00\x80\x00'-b'****'-b'\x00\x00\x90\x00'>>
Function arguments:  <empty or unknown>
 00000 PushIt 
 00001 Push0 
 00002 MessageSend 0 # <Value type=object value=<Value type=event_identifier value=b'Jons'-b'gClp'-b'****'-b'\x00\x00\x00\x00'-b'null'-b'\xff\xff\x80\x00'>> 
 00005 PushLiteral 1 # <Value type=object value=<Value type=constant value=0x63706172>> 
 00006 MakeObjectAlias 22 # GetEvery

 00007 GetData 
 00008 PopGlobal b'fileTexts' 
 00009 StoreResult 
 0000a PushIt 
 0000b PushLiteral 3 # <Value type=object value=<Value type=constant value=0x70726d70>> 
 0000c PushLiteral 4 # [<Value type=special value=nil>, <Value type=string value=b'\x00[\x00F\x00r\x00o\x00m\x00]\x00 \x00S\x00e\x00l\x00e\x00c\x00t\x00 \x00C\x00h\x00e\x00c\x00k\x00 \x00f\x00o\x00l\x00d\x00e\x00r'>] 
 0000d Push2 
 0000e MessageSend 5 # <Value type=object value=<Value type=event_identifier value=b'syso'-b'stfl'-b'alis'-b'\x00\x00\x00\x00'-b'null'-b'\xff\xff\x80\x00'>> 
 00011 GetData 
 00012 PopGlobal b'chkFol' 
 00013 StoreResult 
 00014 PushIt 
 00015 PushLiteral 3 # <Value type=object value=<Value type=constant value=0x70726d70>> 
 00016 PushLiteral 7 # [<Value type=special value=nil>, <Value type=string value=b'\x00[\x00T\x00o\x00]\x00 \x00S\x00e\x00l\x00e\x00c\x00t\x00 \x00C\x00o\x00p\x00y\x00 \x00T\x00r\x00g\x00e\x00t\x00 \x00f\x00o\x00l\x00d\x00e\x00r'>] 
 00017 Push2 
 00018 MessageSend 5 # <Value type=object value=<Value type=event_identifier value=b'syso'-b'stfl'-b'alis'-b'\x00\x00\x00\x00'-b'null'-b'\xff\xff\x80\x00'>> 
 0001b GetData 
 0001c PopGlobal b'moveTargFol' 
 0001d StoreResult 
 0001e LinkRepeat 0x64

 00021 PushGlobal b'fileTexts' 
 00022 Dup 
 00023 PushLiteral 9 # <Value type=object value=<Value type=constant value=0x6b6f636c>> 
 00024 PushLiteral 10 # <Value type=object value=<Value type=constant value=0x636f626a>> 
 00025 Push2 
 00026 MessageSend 11 # <Value type=object value=<Value type=event_identifier value=b'core'-b'cnte'-b'****'-b'\x00\x00\x00\x00'-b'****'-b'\x00\x00\x10\x00'>> 
 00029 Push1 
 0002a PushUndefined 
 0002b RepeatInCollection <disassembler not implemented> 
 0002c Equal 
 0002d Equal 
 0002e PushVariable [var_0] 
 0002f PushLiteral 12 # <Value type=object value=<Value type=constant value=0x70636e74>> 
 00030 MakeObjectAlias 21 # GetProperty

 00031 GetData 
 00032 PopGlobal b'j' 
 00033 StoreResult 
 00034 PushGlobal b'chkFol' 
 00035 PushLiteral 14 # <Value type=object value=<Value type=constant value=0x54455854>> 
 00036 Coerce 
 00037 PushGlobal b'j' 
 00038 Concatenate 
 00039 GetData 
 0003a PopGlobal b'fromPath' 
 0003b StoreResult 
 0003c ErrorHandler 87 
     0003f PushLiteralExtended 16 # <Descriptor type=b'alis' content=b'\x00\x00\x00\x00\x014\x00\x02\x00\x01\x06Cherry\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00BD\x00\x01\xff\xff\xff\xff\nFinder.app\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\n cu\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0cCoreServices\x00\x02\x00)/:System:Library:CoreServices:Finder.app/\x00\x00\x0e\x00\x16\x00\n\x00F\x00i\x00n\x00d\x00e\x00r\x00.\x00a\x00p\x00p\x00\x0f\x00\x0e\x00\x06\x00C\x00h\x00e\x00r\x00r\x00y\x00\x12\x00&System/Library/CoreServices/Finder.app\x00\x13\x00\x01/\x00\xff\xff\x00\x00'> 
     00042 Tell 16 
         00045 PushIt 
         00046 PushLiteralExtended 17 # <Value type=object value=<Value type=constant value=0x66696c65>> 
         00049 PushGlobal b'fromPath' 
         0004a MakeObjectAlias 24 # GetIndexed (item A of B)

         0004b PushLiteralExtended 18 # <Value type=object value=<Value type=constant value=0x696e7368>> 
         0004e PushGlobal b'moveTargFol' 
         0004f Push2 
         00050 MessageSend 19 # <Value type=object value=<Value type=event_identifier value=b'core'-b'clon'-b'****'-b'\x00\x00\x00\x00'-b'****'-b'\x00\x00\x90\x00'>> 
         00053 EndTell 
     00054 EndErrorHandler 93 
 00057 HandleError 20 21 
 0005c PushUndefined 
 0005d Dup 
 0005e StoreResult 
 0005f Jump 0x2b 
 00062 Return 

のような、膨大な内容です。まるで、アセンブラのニーモニックを読んでいるかのような感覚です。

10行程度のScriptから14倍の内容が出力されています。一応、一部の処理内容については(エラートラップ部分など)推測することは可能ですが、前半部分はさっぱりです。断片的に変数名などがわかったり、後半のインデント構造的なものが見えたりするあたりはソースのように見えなくもありませんが、この出力から元のAppleScriptの内容を理解できたりするのでしょうか?

もしかすると、Classic Mac OSの開発経験があるとこの内容を「読む」ことが可能なのかもしれませんが、この内容では自分にはさっぱり分かりません。

現状では、AppleEventを人間が読んでも理解できそうな命令語に置き換え、パラメータともども一覧表示しているというものに見えます。そのレベルの機能については間違いなく実現しているでしょう。ただ、そのAppleEventニーモニックの展開ができたからといって、元のAppleScriptのプログラムを復元できるようには見えません。

# じっと眺めていると「スタック操作を頻繁に行っている」ように見えますが、それでもそれ以上の情報は読み取れません

applescript-disassemblerの機能は同梱のドキュメントのとおりで、実行専用のアプレットから元のAppleScriptのプログラムソースが得られるといったものではありませんでした。その動作内容についても確認できましたし、処理レベルも確認できました。

自分が行った検証のかぎりでは(検証前からおぼろげにわかっていましたが)、一部の人間が他の多くのユーザーの警戒心を煽っているような状況では「ない」と思います。おそらく、その解決ツールという名目でそれらしい動作を行うツールを(AppleScriptを読めない顧客に)売りつけ、お金を巻き上げようという魂胆なのでしょう。

Posted in news Security | Tagged 10.14savvy 10.15savvy 11.0savvy | Leave a comment

macOS 11.2でスクリプトエディタのヘルプがBig Sur用に変更された

Posted on 1月 22, 2021 by Takaaki Naganoya

macOS 11.2 beta(20D53)でスクリプトエディタのヘルプが差し代わっていることを確認しました。あいかわらず「UserTalk」(Userland Frontier)に関する言及がある(もうないのに)など、無意味な記載内容はあらためられていません。

Posted in Update | Tagged 11.0savvy | Leave a comment

FileMaker Scripting Bookの英語版を作っています

Posted on 1月 22, 2021 by Takaaki Naganoya

英語版を作っています。とても真剣に。でも、英語版の本の「フォント感」がいまひとつ掴めなくて困ります。

本文にTimesはいまさら使ってない感じでサンセリフ系のフォントの幅の狭いものをタイトル部分に使っていたりするんでしょうし、各話の導入部分をイタリック体で装飾してメリハリ付けるんだろうな、などと手探りでやっています。

しょせんは英語ネイティブの人間が作っているわけではないので、違和感は残ると思っています。そこはこだわってもうまく違和感を消すことはできないでしょうから、しょーがないでしょう。

Posted in PRODUCTS | Tagged 10.14savvy 10.15savvy 11.0savvy FileMaker Pro | Leave a comment

AppleScript+Cocoa本などの企画が始動

Posted on 1月 17, 2021 by Takaaki Naganoya

AppleScript+Cocoaの解説本は、けっこう前からいろいろまとめていました。知り合い筋には、雑談のおりにちょいちょい見せています。本Blogにも断片を掲載しています。

→ Cocoa Scripting Course #1を販売開始


▲これとか。Cocoa Scripting本のために準備した説明図です


▲これもそうですね。全般的に図で説明する本です


▲これも

ただ、それが一定レベル以上の具体的なものにならないのは……読者層がまったく想定できないということと、そんなにそれを求めている人がいないのではないか、と想像されるからです。

日本国内でそれを読みたいと思っている人が10人いるのかいないのか。実際にアンケート調査を行なったわけではありませんが、「そんなにいないよね?」とは思っています。

なので、書籍とオンラインセミナーの中間形態を模索しています。

基本的な解説部分と、NSStringなどの1つのテーマがセット。購入後●か月間、理解できなかった点を3つまで補足説明することを求める権利を差し上げます。つまり、詳細な情報を提供して不明な点の補足説明が行われるというものです。

やってみないと分からないものの、やるとしたらこういう形態しかないだろうと思います。サンプルScriptなども大量に掲載するので、いわば2018年1月末に発生したXserveによる無断サーバー停止によるBlog消失後の、本Blog再開後のテーマ別の説明とアーカイブというものに近くなるはずです。


▲このシリーズのみ体裁が少し変わります(横長)。いつもの体裁だと入りきらない図形が多いもので


▲あまりに「おいしそう」に見えなかったので、表紙を変更してみました。まあ、おいしそう!

あとは、SafariのScripring Book計画。こちらは、FileMaker Pro本の前から構想があったものです。

表紙と章構成ぐらいを作ってみました。はたして……

Posted in PRODUCTS | 2 Comments

Script Debugger v8 日本語対応中

Posted on 1月 14, 2021 by Takaaki Naganoya

Script Debuggerのv8のPublic Betaが出たので、早速試していますが……まだ日本語環境で作ったAppleScript書類の表示に問題を抱えています。

今回のv8ではApple Silliconへの対応のほか、待望のDark Mode対応なども行われ……普通にAppleScriptを表示するうえにScript Debugger側で設定したDark Themeで表示するなど表示情報が多層化されているようです。

そのために、Roman Language以外のCJK環境のフォント表示で問題を抱えているもよう。とはいっても、LateNight SoftwareはこのジャンルではMac界最強の開発チームであるため、対応は行われることでしょう。

それが今日明日のうちに実現されるかと言われれば、まだ時間が必要といった印象を受けています。

なお、さまざまな仕様の多くはSD7に準じているもようです。

「as anything」は「as any」と解釈されます。これは、macOS 10.13までは「as list or list of string」という謎の解釈を行なっていた(any型は内部的に存在していたが予約語がなかったもよう)ものが、macOS 10.14でスクリプトエディタ側は「as anything」と解釈し、Script Debugger側では「as any」と解釈するようになりました。

自分が「as anything」を発見した顛末は、

as anything

にまとめたとおりです。欠点もありますが、自分はこの「any型cast」は言語仕様上必要だと思います。スクリプトエディタとScript Debuggerでこの解釈が統一されていないのは問題であると考えます。

あるいは、スクリプトエディタやScript Debugger以外の「何か」があったほうがよいのかもしれません。Apple側は機能については追加する考えはないようですし(削るばっかり)、Script Debuggerも生産性の向上にはさほど寄与しません(ないと困る道具ではあるものの、あったからといってものすごく効率が上がるわけでもありません。クラッシュ回数多すぎです)。

生産性を維持するために自分がやっていることは、いままでに組んだScriptを部品化して再利用すること、部品を探しやすくすること、スニペット(断片的なプログラム記述入力)を充実させることです。Script Debuggerのスニペットで高度なことができるわけではない(Script Debugger側が想定している範囲を超えられない)ので、本当に必要な時以外はインテリジェントなスニペット(Piyomaru Script Assistant)で魔改造しまくってあるスクリプトエディタを使っています。

Script Debuggerが提供しているデバッグ機能は、ブレークポイントの設定やステップ実行、トレースなどのまっとうで高度な機能ですが、正直なところそれって「入門者レベルに有用」なものばかり(初心者にScript Debuggerは有用)。普通に書いているScripterがそれを必要としているかといえば、ちょっとニーズがズレてしまっていると感じます。数千行クラスの大規模なScriptのデバッグでステップ実行みたいな悠長なことはしませんよね? モジュール単位で再テストしやすくするための仕組みのほうが大事ですよね?

正直なところ、自分はスクリプトエディタにもScript Debuggerにも満足できていないので、第3の選択肢はあるべきだと考えます。

Posted in news | Tagged 10.14savvy 10.15savvy 11.0savvy Script Debugger | Leave a comment

FileMaker Pro Scripting Book with AppleScript発売開始

Posted on 1月 12, 2021 by Takaaki Naganoya

AppleScriptからFileMaker Proをコントロールするやり方を基礎から実戦レベルまで紹介する電子ブック「FileMaker Pro Scripting Book with AppleScript」を発売いたしました。定価は3,000円です。

→ お試し版のダウンロード

→ 販売ページ

→ English Version SAMPLER

→ English Version

これまでに、「AppleScriptえほんシリーズ」を3冊出しています。Scriptについて理解していなくても、本のとおりに操作して入力すればGUIアプリケーションを動かせることから、余力があればもっと充実させたいコンテンツではあります。


▲コンテスト応募作品「Word Color Palette」。いつものthree.js回転UIなど、AppleScriptでおなじみのInterfaceをFileMaker Pro上に移植。シソーラス辞書検索やSVGサンプルデータへの自動配色などにAppleScriptを利用(iOSやWindows上では機能ダウンした処理を実行)

FileMaker Proはさすがに機能が多く、この「えほんシリーズ」フォーマットの計画もあったのですが、内容に無理を感じていました。同様にSafari本についても検討したものの「途中から急に技術レベルが上がって、入門者向けにはならない」(do javascriptコマンドが出てくるあたり)ということで塩漬け状態。そのジレンマを打開するための新たなシリーズが「徹底解説シリーズ」です。

「画面図多め+文章少なめ」の「えほんシリーズ」のフォーマットを踏襲しつつ、「えほんシリーズ」の特徴である難易度設定の厳重な管理により、急激に難易度が上がったり、そもそも記事の難しさがどの程度なのかわからないといったことのないように配慮しています。「初級」「中級」「上級」の3レベル分けを行っています。

「えほんシリーズ」ではページ数を少なめ(64ページ以下)に抑えていましたが、「徹底解説シリーズ」では分量を抑えるよりも対象のテーマを説明し切ることに重点を置き、対象レベルを若干上げています。分冊構成にすることも検討したのですが「では、検索をしたかったら下巻も買ってね」というのはさすがにご無体なので、1冊にまとめて139ページとなっています。

とくに、対象がFileMaker Proということで、同アプリケーションのエキスパートである新居雅行氏から監修していただき、内容の充実も図っています。


▲掲載デモScript。FileMaker Proのスキーマ定義を自動で行うAppleScript。リストで与えたフィールド名を自動作成。ちょっと手直しすればNumbersの表計算データからフィールド名を外部供給することも容易

これまで、プログラムリストをPDF本文にURLリンクで埋め込むという手法を用いていましたが、macOS 10.15以降のPDFViewにおいてどうもこのURL埋め込み式のPDFをApple側がセキュリティホール源と捉えており、とくに説明なしに機能をダウンさせています。このあたりの話は「専用のビューワーアプリケーションを作る」「リストを掲載しているBlogのページにURLリンクで飛ばす」などの対処が検討されてきましたが、どれもすべてを解決できるわけではありません。

そこで、おおもとの方式に差し戻してAppleScript書類のアーカイブを添付することにしました。AppleScript書類と、他のOS環境でも内容をオープンできるようRTF形式のファイルも添付しています。

また、最近の電子書籍購入者の方にはご案内していますが、「Piyomaru Script Assistant」のバージョン2を添付。Cocoaの機能呼び出しを意識した内容に再編し、macOS 10.13以降のOS環境をターゲットとしています。スクリプトエディタのコンテクストメニューからAppleScriptの主要構文を選択入力できるこのツールは、作った本人でもインストールしていないと作業性が大幅に低下してしまうほどの必携ツールです。

完成度については、さすがに屈強の筆者であり開発者であり編集者である自分が朝から晩まで作り込んだうえに、新居さんに監修していただいた(ダメ出しされまくった)だけあって、「手元に1冊置いておきたい出来」にはなっていると自負しています。

Posted in PRODUCTS | Tagged 10.14savvy 10.15savvy 11.0savvy FileMaker Pro | Leave a comment

FileMaker Proのテキストフィールドにスタイル付きテキストを代入

Posted on 1月 5, 2021 by Takaaki Naganoya

FileMaker Proのテキストフィールドにスタイル付きテキストを代入するAppleScriptです。

FileMaker Proには、v4の頃からかわらないとてもユニークな特徴があります。それは、テキストフィールドに書式つきテキストを突っ込めることです。こんなことができるデータベースは他に類を見ません。

# 書式付きテキストのほかに書式を持たないシャドーフィールドでも持たせているんじゃないかと推測

スタイル付きテキストについては、ワープロなどのソフトウェアを併用して作成する方法もありますが、AppleScriptだけで作成できれば、FileMaker Proのスクリプトステップ内に突っ込むことができて便利です。

ただし、当のAppleScript自体のスタイル付きテキストの作成能力に関しては昔から残念なレベルでした(Classic MacOS時代にはOSAXで作れたような気も)。風向きが変わってきたのは、macOS 10.10でCocoa呼び出しがすべてのランタイム環境で使えるようになったあたりです。当然、FileMaker Proのスクリプトステップ内でも呼べるようになっていました。

残念なことにmacOS 10.10登場当時、FileMaker Proが32ビットアプリケーションだったため、FileMaker Proのスクリプトステップ「AppleScriptを実行」の中で呼び出せるFrameworkも32ビットに限られていました。Cocoa Frameworkの多くは32bitアプリケーションからも呼び出せるようになっていましたが、そうでないものも多々ありました。

FileMaker Pro v12で64ビット化され、中に記述したAppleScriptからも64bit Frameworkを呼べるようになりました。

本Scriptはあくまでも実験的なものですが、AppleScriptからCocoaの機能を呼び出して自由にスタイル付きテキストを作成し、それをクリップボード経由でFileMaker Pro側に受け渡します。FileMaker Pro側では指定のフィールドに対してクリップボードの内容を「貼り付け」コマンドで代入します。


▲指定フォント、指定サイズ、指定テキストでスタイル付きテキストを生成してフィールドに代入


▲FileMaker Pro側にクリップボードから内容を受け取ってフィールドに入れるFileMaker Script

代入先のフィールド名については、FileMaker Proのスクリプト呼び出しをAppleScriptの「do script」コマンド経由で行う場合には、パラメータの指定ができないため、一切指定できません。

……ただし、AppleScriptからURL Event経由でもFileMaker Pro側のスクリプト実行ができ、その場合にはパラメータの受け渡しができます。そのため、URL Event経由で呼び出せば「クリップボードに入っているスタイル付きテキストの受け渡し先フィールド名」を随時指定することも可能です。

# FileMaker Proのdo scriptコマンドに素直にパラメータを受け渡す機能を付けてほしい

そろそろFileMaker Proのお試し版の期限が切れるので、FileMaker Pro関連のScriptingのまとまった情報について本Blog上への投稿は行えません。まとまった情報については、電子ブック新刊「FileMaker Pro Scripting Book」(予定)をお買い求めください。

AppleScript名:テキストフィールドにスタイル付きテキスト.scpt
— Created 2020-12-29 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

set attrStr to makeRTFfromParameters("ぴよまるソフトウェアだよーーん", 3.0, 72) of me
(
my restoreClipboard:{attrStr})

tell application "FileMaker Pro"
  tell database 1
    do script "getAttrFromClipboard" –クリップボードの内容をtextFieldにペーストする
  end tell
end tell

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

–クリップボードに内容を設定する
on restoreClipboard:theArray
  — get pasteboard
  
set thePasteboard to current application’s NSPasteboard’s generalPasteboard()
  
  
— clear it, then write new contents
  
thePasteboard’s clearContents()
  
thePasteboard’s writeObjects:theArray
end restoreClipboard:

★Click Here to Open This Script 

Posted in RTF | Tagged 10.14savvy 10.15savvy 11.0savvy FileMaker Pro | Leave a comment

クリップボードに入ったStyled Stringからフォントとサイズと文字内容の情報を取得

Posted on 1月 4, 2021 by Takaaki Naganoya

クリップボードに入ったStyled Stringから、フォント名とサイズと文字内容の情報を取得するAppleScriptです。

Keynoteのテキストオブジェクトのフォント名(フォントファミリー)を置換するAppleScriptを作ったときに、Keynoteが「選択中のオブジェクト」を取得する機能がないために、テキストオブジェクトの中(object text)をコピーして、AppleScript側にその情報を引き渡す必要がありました。


▲年末にコンテスト応募のために久しぶりにFileMaker Proにまとまった時間さわったので、そのノウハウを整理してまとめた本を作成中

こんなKeynote書類があったときに、タイトル部分の書式情報に該当するText Objectのみフォントを一括変更する、という処理です。

KeynoteのAppleScript用語辞書に、選択中のオブジェクトに対してアクセスできるオブジェクト(「selected items」のような)が定義されていれば、クリップボード経由で情報を受け取るような野蛮な処理はしないで済むのですが、、、、、

AppleScript名:クリップボードに入ったStyled Stringからフォントとサイズと文字内容の情報を取得.scptd
— Created 2021-01-03 by Takaaki Naganoya
— 2021 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSFont : a reference to current application’s NSFont
property NSColor : a reference to current application’s NSColor
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSDictionary : a reference to current application’s NSDictionary
property NSPasteboard : a reference to current application’s NSPasteboard
property NSCountedSet : a reference to current application’s NSCountedSet
property NSMutableArray : a reference to current application’s NSMutableArray
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSAttributedString : a reference to current application’s NSAttributedString
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
property NSKernAttributeName : a reference to current application’s NSKernAttributeName
property NSMutableParagraphStyle : a reference to current application’s NSMutableParagraphStyle
property NSLigatureAttributeName : a reference to current application’s NSLigatureAttributeName
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSUnderlineStyleAttributeName : a reference to current application’s NSUnderlineStyleAttributeName
property NSParagraphStyleAttributeName : a reference to current application’s NSParagraphStyleAttributeName
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName

–クリップボード内にスタイル付きテキストが入っているかチェック
set cRes to clipboard info for «class RTF »
if cRes = {} then return

–クリップボードに入っているスタイル付きテキストから情報を取得
set {aFontName, aFontSZNum, aString} to getFontNameAndSizeFromClipboard() of me
–> {"DINCondensed-Bold", 170.0, "FileMaker Pro Scripting Book"}

–クリップボードの内容を書式つきテキストとして解釈
on getFontNameAndSizeFromClipboard()
  –クリップボードの内容を文字列として取得
  
using terms from scripting additions
    set aStr to (the clipboard) as string
  end using terms from
  
  
if aStr = "" then
    display dialog "No Data in Clipboard" buttons {"OK"} default button 1
    
return
  end if
  
  
–クリップボードの内容をStyled Stringで取得して最頻出フォントを取得
  
set clipboardAttrStr to getClipboardASStyledText() of me
  
if clipboardAttrStr = missing value then
    display dialog "Can not get clipboard as Styled String" buttons {"OK"} default button 1
    
return
  end if
  
set attrList to getAttributeRunsFromAttrString(clipboardAttrStr) of me
  
  
set anArray to ((NSArray’s arrayWithArray:attrList)’s valueForKeyPath:"fontName") as {list, string}
  
set aFontList to (countItemsByItsAppearance(anArray) of me)
  
set aFontName to theName of first item of aFontList
  
  
set fSizes to ((NSArray’s arrayWithArray:attrList)’s valueForKeyPath:"fontSize") as {list, real}
  
set aFontSZList to (countItemsByItsAppearance(fSizes) of me)
  
set aFontSZNum to theName of first item of aFontSZList
  
  
set aString to ((NSArray’s arrayWithArray:attrList)’s valueForKeyPath:"stringVal") as string
  
  
return {aFontName, aFontSZNum, aString}
end getFontNameAndSizeFromClipboard

–1D Listを文字列長でソート v2
on sort1DListByIndicatedStringLength(aList as list, aSortKey as string, sortOrder as boolean)
  set aArray to NSArray’s arrayWithArray:aList
  
set descLabel1 to NSString’s stringWithString:(aSortKey & ".length")
  
set descLabel2 to NSString’s stringWithString:aSortKey
  
set desc1 to NSSortDescriptor’s sortDescriptorWithKey:descLabel1 ascending:sortOrder
  
set desc2 to NSSortDescriptor’s sortDescriptorWithKey:descLabel2 ascending:true selector:"localizedCaseInsensitiveCompare:"
  
set bArray to aArray’s sortedArrayUsingDescriptors:{desc1, desc2}
  
return bArray as list
end sort1DListByIndicatedStringLength

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

–書式つきテキストを組み立てる
on makeRTFfromParameters(aStr as string, fontName as string, aFontSize as real, aKerning as real, aLineSpacing as real)
  set aVal1 to NSFont’s fontWithName:fontName |size|:aFontSize
  
set aKey1 to (NSFontAttributeName)
  
  
set aVal2 to NSColor’s blackColor()
  
set aKey2 to (NSForegroundColorAttributeName)
  
  
set aVal3 to aKerning
  
set akey3 to (NSKernAttributeName)
  
  
set aVal4 to 0
  
set akey4 to (NSUnderlineStyleAttributeName)
  
  
set aVal5 to 2 –all ligature ON
  
set akey5 to (NSLigatureAttributeName)
  
  
set aParagraphStyle to NSMutableParagraphStyle’s alloc()’s init()
  
aParagraphStyle’s setMinimumLineHeight:(aLineSpacing)
  
aParagraphStyle’s setMaximumLineHeight:(aLineSpacing)
  
set akey7 to (NSParagraphStyleAttributeName)
  
  
set keyList to {aKey1, aKey2, akey3, akey4, akey5, akey7}
  
set valList to {aVal1, aVal2, aVal3, aVal4, aVal5, aParagraphStyle}
  
set attrsDictionary to NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
  
  
set attrStr to NSMutableAttributedString’s alloc()’s initWithString:aStr attributes:attrsDictionary
  
return attrStr
end makeRTFfromParameters

— クリップボードの内容をNSAttributedStringとして取り出して返す
on getClipboardASStyledText()
  set theNSPasteboard to NSPasteboard’s generalPasteboard()
  
set theAttributedStringNSArray to theNSPasteboard’s readObjectsForClasses:({NSAttributedString}) options:(missing value)
  
set theNSAttributedString to theAttributedStringNSArray’s objectAtIndex:0
  
return theNSAttributedString
end getClipboardASStyledText

–指定のNSAttributedStringから書式情報をlist of recordで取得
on getAttributeRunsFromAttrString(theStyledText)
  script aSpd
    property styleList : {}
  end script
  
  
set (styleList of aSpd) to {} —for output
  
  
set thePureString to theStyledText’s |string|() –pure string from theStyledText
  
  
set theLength to theStyledText’s |length|()
  
set startIndex to 0
  
  
repeat until (startIndex = theLength)
    set {theAtts, theRange} to theStyledText’s attributesAtIndex:startIndex longestEffectiveRange:(reference) inRange:{startIndex, theLength – startIndex}
    
    
set aText to (thePureString’s substringWithRange:theRange) as string
    
    
set aColor to (theAtts’s valueForKeyPath:"NSColor")
    
if aColor is not equal to missing value then
      set aSpace to aColor’s colorSpace()
      
      
set aRed to (aColor’s redComponent()) * 255
      
set aGreen to (aColor’s greenComponent()) * 255
      
set aBlue to (aColor’s blueComponent()) * 255
      
      
set colList to {aRed as integer, aGreen as integer, aBlue as integer}
      
set colStrForFind to (aRed as integer as string) & " " & (aGreen as integer as string) & " " & (aBlue as integer as string)
    else
      set colList to {0, 0, 0}
      
set colStrForFind to "0 0 0"
    end if
    
    
set aFont to (theAtts’s valueForKeyPath:"NSFont")
    
if aFont is not equal to missing value then
      set aDFontName to aFont’s fontName()
      
set aDFontSize to aFont’s pointSize()
    end if
    
    
set the end of (styleList of aSpd) to {stringVal:aText, colorStr:colStrForFind, colorVal:colList, fontName:aDFontName as string, fontSize:aDFontSize}
    
set startIndex to current application’s NSMaxRange(theRange)
  end repeat
  
  
return (styleList of aSpd)
end getAttributeRunsFromAttrString

–1D Listをアイテムの出現頻度順でソートして返す
on countItemsByItsAppearance(aList as list)
  set aSet to NSCountedSet’s alloc()’s initWithArray:aList
  
set bArray to NSMutableArray’s array()
  
set theEnumerator to aSet’s objectEnumerator()
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
bArray’s addObject:(NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{"theName", "numberOfTimes"})
  end repeat
  
  
set theDesc to NSSortDescriptor’s sortDescriptorWithKey:"numberOfTimes" ascending:false
  
bArray’s sortUsingDescriptors:{theDesc}
  
  
return bArray as list
end countItemsByItsAppearance

★Click Here to Open This Script 

Posted in Clipboard RTF | Tagged 10.14savvy 10.15savvy 11.0savvy | Leave a comment

日本語簡易パーサーeasyJParse v5

Posted on 12月 31, 2020 by Takaaki Naganoya

簡易日本語パーサー「easyJParse」のバージョンアップ版です。AppleScriptライブラリ「BridgePlus」を利用しないように改めました。

簡易日本語パーサーというのは、日本語の文を単語に分解するプログラムですが、品詞情報や係り受けの情報が得られるわけではなく、単に単語に分解するだけのもので、用途を日本語コマンド解釈などに限定した簡易版の形態素解析器もどきソフトウェアです。特定の人名など区切られて困る単語についてはカギ括弧などで括ることで(例:「ぴよまるソフトウェア」)まとまった単語として出力する機能を持たせています。

→ easyJParse v3
→ easyJParse v4

前バージョンまではBridgePlus Script Libraryを利用していましたが、同ライブラリがFrameworkを含んでいるために、確実に動かせるように設定するには技量(理解と慣れ)が必要です。自分の手元では動かせていますが、ユーザーによってはBridgePlusをmacOS 10.15以降のMacで利用できないケースも見られ(たぶん、操作間違い)、BridgePlusへの依存がマイナスポイントになりつつあるように感じられます。

本ScriptでBridgePlusから利用しているメソッドは2つ。どちらも既存のAppleScriptのルーチンの組み合わせで再現できる程度の簡単なもの。これらをすべて既存のルーチンの組み合わせで置き換えました。BridgePlus内蔵の機能を書き換える際に、扱うデータサイズはあまり大きくないものであることを前提に最適化しました。あまり巨大なデータを扱うのには向いていませんが、小さなデータを高速に処理できるようにしてあります。

MacBookPro10,1,  macOS Version 10.14.6 (Build 18G8005),  100 iterations
         First Run   Total Time    Average     Median    Maximum    Minimum   Std.Dev.
First       0.6685       0.6236     0.0062     0.0059     0.0083     0.0054     0.0008

正直なところ、この程度の極小データサイズだとCocoaの機能を利用するメリットがあまりないので、Cocoaを使わないように書き換えると高速化できます。高速化は必要に応じて行う程度でしょう。

外部ライブラリに依存しなくなったため、たとえばCotEditorのメニューから呼び出すScriptや、FileMaker Pro Scriptの中にまるごと日本語パーサーを突っ込むといった真似ができます。

AppleScript名:easyJParse v5.scptd
— Created 2018-09-26 by Takaaki Naganoya
— Modified 2020-12-31 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.5" — El Capitan (10.11) or later
use framework "Foundation"
use scripting additions

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

set aTargName to "Finderで選択中のAI書類上の「製品名」レイヤーから抜き出したコードをもとにスペック情報をGoogle Spreadsheet「製品コード表」から展開して保存。"
set aList to parseJ(aTargName, true) of me
–> {"Finder", "で", "選択", "中", "の", "AI", "書類", "上", "の", "「", "製品名", "」", "レイヤー", "から", "抜き出し", "た", "コード", "を", "もと", "に", "スペック", "情報", "を", "Google", " ", "Spreadsheet", "「", "製品コード表", "」", "から", "展開", "し", "て", "保存", "。"}–v4
–> {"Finder", "で", "選択", "中", "の", "AI", "書類", "上", "の", "「", "製品名", "」", "レイヤー", "から", "抜き出し", "た", "コード", "を", "もと", "に", "スペック", "情報", "を", "Google", " ", "Spreadsheet", "「", "製品コード表", "」", "から", "展開", "し", "て", "保存", "。"}–v5

return aList

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

–カッコのネスティングとクロス(エラー)については、処理せずにそのまま出力
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)
  
  
  
–リスト内のブラケット位置の検出
  
set aRes to (my indexesOfItems:bracketList inArray:aList base:0) as list
  
–> {9, 12, 15, 18, 22, 25, 27, 29}–0 based
  
  
if aRes = {} then return aList
  
  
–位置情報リストを開始位置, 終了位置のペアの2D Listに変換する
  
set cList to my subarraysFrom:(aRes) groupedBy:2
  
–> {{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

–BridgePlus内の命令を展開
on indexesOfItems:(iList as list) inArray:(aList as list) base:(baseNum as integer)
  return retIndexesOfNumInArray(iList, aList, baseNum) of me
end indexesOfItems:inArray:base:

–1Dリスト中のシーケンシャルサーチ(複数)
on retIndexesOfNumInArray(aTargetList, aList, baseNum)
  script obj
    property list : aList
    
property resList : {}
  end script
  
  
if baseNum is not in {0, 1} then return false
  
  
–set obj’s list to aList
  
set (resList of obj) to {}
  
set aCount to baseNum
  
set hitF to false
  
  
repeat with i in obj’s list
    set j to contents of i
    
if j is in aTargetList then
      set the end of (resList of obj) to aCount
    end if
    
    
set aCount to aCount + 1
  end repeat
  
  
return (resList of obj)
end retIndexesOfNumInArray

on subarraysFrom:(aList as list) groupedBy:(gNum as integer)
  script spdObj
    property list : aList
    
property bList : {}
  end script
  
  
  
–Group Num check
  
if gNum = 0 then return false
  
if length of aList < gNum then return false
  
  
if (length of aList) mod gNum is not equal to 0 then return
  
  
set (bList of spdObj) to {}
  
  
set tmpList to {}
  
set aCount to 1
  
  
repeat with i in aList
    set j to contents of i
    
set the end of tmpList to j
    
set aCount to aCount + 1
    
    
if aCount > gNum then
      set the end of (bList of spdObj) to tmpList
      
set tmpList to {}
      
set aCount to 1
    end if
  end repeat
  
  
return (bList of spdObj)
end subarraysFrom:groupedBy:

★Click Here to Open This Script 

Posted in Natural Language Processing Text | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy | Leave a comment

Post navigation

  • Older posts
  • Newer posts

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

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • macOS 15, Sequoia
  • 指定のWordファイルをPDFに書き出す
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • Numbersで選択範囲のセルの前後の空白を削除
  • メキシカンハットの描画
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AdobeがInDesign v19.4からPOSIX pathを採用
  • AppleScriptによる並列処理
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • macOS 14.xでScript Menuの実行速度が大幅に下がるバグ
  • AppleScript入門③AppleScriptを使った「自動化」とは?
  • macOS 15でも変化したText to Speech環境
  • Keynote/Pagesで選択中の表カラムの幅を均等割
  • デフォルトインストールされたフォント名を取得するAppleScript
  • macOS 15 リモートApple Eventsにバグ?
  • AppleScript入門① AppleScriptってなんだろう?
  • macOS 14で変更になったOSバージョン取得APIの返り値
  • Keynoteで2階層のスライドのタイトルをまとめてテキスト化
  • Script Debuggerの開発と販売が2025年に終了

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1391) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (212) 13.0savvy (194) 14.0savvy (147) 15.0savvy (132) CotEditor (66) Finder (51) iTunes (19) Keynote (117) 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 (55) 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
  • date
  • 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年5月
  • 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