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

カテゴリー: Text

指定画像をbase64エンコード文字列に変換

Posted on 10月 27, 2019 by Takaaki Naganoya

指定画像をbase64エンコーディング文字列に変換するAppleScriptです。

用途は、sdef(AppleScript用語辞書)に画像を突っ込む(ためのデータを作る)こと。それだけです。

ただ、あまりにでかい画像をbase64文字化して取得すると、スクリプトエディタが結果を表示したときに不安定になったり処理が返ってこなくなったりするので、文字列を取得する前にデータサイズを計算し、リサイズしてから文字列化するとか、他の形式(GIFなど)を用いてエンコードするなどのケアが必要になります。ねんのため。

元画像が何であっても、NSImageに読み込める画像なら(OSでサポートしている画像なら)読み込んで、PNG形式に変換したのちにBase64エンコード文字列に変換しています。


▲エンコードするにしても数10KBとかそのぐらいのファイルサイズの画像にしておかないと後がつらい


▲4K解像度の画像をbase64エンコードするとこんなに結果が巨大に

AppleScript名:指定画像をbase64エンコード文字列に変換.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/10/25
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property NSPNGFileType : a reference to current application’s NSPNGFileType
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSDataBase64EncodingEndLineWithLineFeed : a reference to current application’s NSDataBase64EncodingEndLineWithLineFeed

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

set aFile to choose file of type {"public.image"}
set aStr to base64StringFromImageFile(aFile) of me

–Base64 Encode
on base64StringFromImageFile(aFile)
  set aPOSIX to POSIX path of aFile
  
set anImage to NSImage’s alloc()’s initWithContentsOfFile:aPOSIX
  
set imageRep to NSBitmapImageRep’s alloc()’s initWithData:(anImage’s TIFFRepresentation())
  
set aPNGdat to imageRep’s representationUsingType:(NSPNGFileType) |properties|:(missing value)
  
set base64Str to aPNGdat’s base64EncodedDataWithOptions:(NSDataBase64EncodingEndLineWithLineFeed)
  
set bStr to (NSString’s alloc()’s initWithData:base64Str encoding:(NSUTF8StringEncoding))
  
return bStr as string –or return NSString (delete as string) for speedy processing
end base64StringFromImageFile

★Click Here to Open This Script 

Posted in Image Text | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy NSBitmapImageRep NSDataBase64EncodingEndLineWithLineFeed NSImage NSPNGFileType NSString NSUTF8StringEncoding | Leave a comment

CotEditorの最前面のドキュメントの選択範囲を伏せ字に

Posted on 10月 22, 2019 by Takaaki Naganoya

CotEditorの最前面のドキュメントの選択範囲を、簡易形態素解析ルーチンeasyJparseを用いて、いい感じに伏せ字にするAppleScriptです。

–> Download makeSelectionToFuseji(Code-Signed AppleScript applet with libraries in its bundle, co-work with CotEditor)

easyJparseは日本語のコマンド解析用にでっちあげた作った超簡易形態素解析プログラムです。単語(形態素)ごとに分割しますが、品詞まではわかりません。コマンド解釈用ではあるものの、少し他の用途にも使えないかと思い、このような用途に使ってみました。

# 本Scriptは、CotEditor用のScript Pack v2.0に収録されています


▲CotEditorの選択範囲を伏せ字にする。形態素解析して単語化して、単語単位で伏せ字にするかの判断を実行

テキストエディタ上で伏せ字処理というのは、個人的によく使います。たいていは、オリジナルの文章に対して同様の分量の文章を作らなくてはならないようなケースで、文字数の感覚をつかむために使います。一種のダミーレイアウトのようなものです。

本スクリプトのような伏せ字処理については、ニーズがあるんだかないんだか不明なものですが、とりあえず掲載してみました。自分で使ってみたところ、たしかに面白いものの、実用性については未知数という印象です。

(minusList of parseSPD) に入れている語群は、どこかからか拾ってきたもののようではあるものの、すでに何か方向性を見失っているような気がしないではありません。

AppleScript名:選択範囲を伏せ字に(簡易形態素解析でそれっぽく).scptd
— Created 2018-09-26 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5" — El Capitan (10.11) or later
use framework "Foundation"
use scripting additions
use jParser : script "easyJParse"

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

property fuesejiChar : "□"

script parseSPD
  property pList : {}
  
property p2List : {}
  
property oneLine : {}
  
property outStr : ""
  
property minusList : {}
end script

–伏せ字化しない助詞などの単語リスト。名詞だけを残すように整備。単語(形態素)単位で照合する
set (minusList of parseSPD) to {"", " ", "ー", "あ", "で", "も", "に", "と", "の", "は", "へ", "さ", "が", "せ", "か", "た", "だ", "だっ", "ば", "つ", "な", "い", "き", "お", "ら", "る", "れ", "なっ", "それ", "これ", "あれ", "どれ", "この", "どの", "あの", "その", "まで", "こと", "もの", "いつ", "いく", "たち", "ただ", "たい", "そう", "いる", "よう", "れる", "ない", "なら", "なる", "なけれ", "から", "する", "たら", "たり", "だけ", "って", "られ", "的", "化", "いくら", "そんな", "どんな", "あんな", "者", "陰", "時", "事", "こんな", "つれ", "けど", "ああ", "ある", "あっ", "あり", "しかし", "きっと", "すっかり", "例えば", "たとえば", "さっぱり", "たとえ", "だろう", "かつ", "ところ", "まるで", "だが", "全て", "すべて", "なり", "いい", "つれ", "つけ", "ながら", "せいぜい", "そうそう", "さらに", "もっと", "まだ", "なく", "し", "を", "て", "いけ", "行く", "また", "まま", "まぁ", "『", "』", "、", "。", "。。", "……。", "【", "】", "「", "」", "(", ")", "最近", "今度", "中", "チカチカ", "グラグラ", "ふわふわ", "少し", "ついで", "より", "っぽい", "ぐらい", "何", "とき", "ため", "そっくり", "そして", "やがて", "じきに", "すぐ", "今", "次", "できる", "出来る", "いや", "そう", "おそらく", "いえ", "らしい", "とも", "ほぼ", "つい", "もう", "きっかけ", "ころ", "頃", "早々", "そこ", "どこ", "なんか", "じゃ", "くれ", "ください", "こそ", "あいつ", "だれ", "誰", "おぼしき", "らしき", "らしい", "しか", "でき", "よっ", "確か", "どう", "こう", "そう", "ああ", "くる", "ざま", "ごとく", "きれ", "はず", "さらに", "さらなる", "更なる", "など", "ごと", "とても", "たく", "いう", "とっ", "いっ", "えっ", "おっ", "ここ", "そこ", "どこ", "なかっ", "ごく", "やる", "ゆい", "ふと", "たび", "ほど", "もた", "よし", "ぜひ", "いら", "よい", "ま", "み", "む", "め", "も", "や", "けれど", "だけど", "したがっ", "すごく", "そもそも", "ほしい", "なれる", "すぎ", "もふもふ", "モフモフ", "さん", "おと", "とー", "えっと", "け", "っけ", "なん", "よ", "ね", "しっくり", "くれる", "くれた", "なぜ", "まあ", "まぁ", "ん", "なんて", "!」"}

set (pList of parseSPD) to {}
set (p2List of parseSPD) to {}
set (oneLine of parseSPD) to {}
set (outStr of parseSPD) to {}

tell application "CotEditor"
  tell front document
    –選択部分が存在しているかどうかチェック
    
set aCon to contents of selection
    
if aCon = "" then return
    
    
set (pList of parseSPD) to paragraphs of aCon
  end tell
end tell

–伏せ字にする対象単語を、助詞などを消し込むことでピックアップ
repeat with i in (pList of parseSPD)
  if length of i > 1 then
    –簡易形態素解析
    
set tempList to parseJ(i) of jParser
    
    
–簡易形態素解析したリストと助詞などのリストの差分を計算
    
set cList to clacListDiff(tempList, (minusList of parseSPD)) of me
    
    
set (oneLine of parseSPD) to {}
    
repeat with ii in tempList
      set aLen to length of ii
      
if ii is in cList then
        –伏せ字化する場合
        
set bCon to multipleChar(fuesejiChar, aLen) of me
        
      else
        –そのまま出力する場合
        
set bCon to contents of ii
      end if
      
set the end of (oneLine of parseSPD) to bCon
    end repeat
    
    
–1つの文章ぶんの単語を連結
    
set cStr to retDelimedText((oneLine of parseSPD), "") of me
  else
    set cStr to ""
  end if
  
  
set the end of (p2List of parseSPD) to cStr
  
end repeat

–すべての文章を連結して配列からテキストに
set (outStr of parseSPD) to retDelimedText((p2List of parseSPD), return) of me

tell application "CotEditor"
  tell front document
    set contents of selection to (outStr of parseSPD)
  end tell
end tell

–指定文字を指定回数繰り返して連結して出力
on multipleChar(aChar as string, aLen as integer)
  set aList to {}
  
repeat aLen times
    set the end of aList to aChar
  end repeat
  
  
return retDelimedText(aList, "") of me
end multipleChar

–1D Listを要素間に指定デリミタをはさんで文字列化
on retDelimedText(aList as list, aDelim as string)
  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

–2つの1D Listの差分を計算
on clacListDiff(aList as list, bList as list)
  set aSet to NSMutableSet’s setWithArray:aList
  
set bSet to NSMutableSet’s setWithArray:bList
  
  
aSet’s minusSet:bSet –補集合
  
set aRes to aSet’s allObjects() as list
  
  
return aRes
end clacListDiff

★Click Here to Open This Script 

Posted in list Natural Language Processing Text | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy CotEditor NSArray NSMutableSet NSSortDescriptor | 1 Comment

ゼロパディングのサンプルを生成してパディング桁数を選択

Posted on 10月 18, 2019 by Takaaki Naganoya

数値に対して「何桁分のゼロパディングを行うか」を選択するダイアログを表示するAppleScriptです。

数値に対して任意の桁数のゼロパディング(9–> 0009)を行うときに、桁数と実際にゼロパディングしたサンプルを生成してchoose from listによるダイアログで選択するようにしてみました。

本来であれば、ゼロパディングの桁数だけ文字入力させたり一覧から選択させるだけでよいのですが、よりわかりやすいように処理サンプルを同時に表示させています。また、サンプルは任意の範囲で乱数を表示させることで「それっぽい」「本物っぽい」雰囲気を醸し出すようにしてみました。

気分の問題なので、実用性とかそういうものを追求したものではありません。

最近は、AppleScriptもマシンの速度向上やCocoa Frameworkを利用することで高速処理が行えるようになり、何らかの処理を選択する際に「結果ごと表示して選択」するような処理を書くことが増えてきました。さすがに処理に数分かかるような処理ではそんな真似はできませんが、高速に処理できたぶんだけ使い勝手を考慮するとよいだろうかというところです。

AppleScript名:ゼロパディングのサンプルを生成.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/10/18
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property NSMutableArray : a reference to current application’s NSMutableArray

set aList to makeSampleList(1, 8) of me
set aRes to choose from list aList with prompt "Digit Samples" with title "Zero padding digits" default items first item of aList without empty selection allowed
if aRes = false then return false
set dRes to contents of first item of aRes
set nRes to search1DList(aList, dRes) of me

on makeSampleList(aMin as integer, aMax as integer)
  set sampleList to {}
  
set aSampleMaxDigit to length of (characters of (aMax as string))
  
  
repeat with i from aMin to aMax
    set aSample to makeFN(i, aSampleMaxDigit + 1) of me
    
    
set aRand to random number from (10 ^ aMin) to (10 ^ (i – 2) – 1)
    
set aTmpStr to makeFN(aRand, i) of me
    
    
set bSample to aSample & " Sample: " & aTmpStr
    
set the end of sampleList to bSample
  end repeat
  
  
return sampleList
end makeSampleList

on makeFN(aNum as integer, aDigit as integer)
  set aText to "00000000000" & (aNum as text)
  
set aLen to length of aText
  
set aRes to text (aLen – aDigit + 1) thru -1 of aText
  
return aRes
end makeFN

on search1DList(aList, aTarg)
  set anArray to NSMutableArray’s arrayWithArray:aList
  
set anIndex to anArray’s indexOfObject:aTarg
  
if (anIndex = current application’s NSNotFound) or (anIndex > 9.99999999E+8) then –macOS 10.12.x—10.13.0はNSNotFoundの定義値が間違っているので対処
    return false
  end if
  
return (anIndex as integer) + 1 –convert index base (0 based to 1 based)
end search1DList

★Click Here to Open This Script 

Posted in dialog Number Text | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy NSMutableArray | Leave a comment

Safariで現在見えている表を抽出してCSV書き出しv3

Posted on 10月 8, 2019 by Takaaki Naganoya

Safariの最前面のウィンドウで表示中のページのうち、現在ウィンドウ内に表示中の表要素をCSV書き出ししてNumbersでオープンするAppleScriptの改良版です。HTMLのtable中にrowspan(複数セルを行方向に連結)とcolspan(複数セルを列方向に連結)の属性値が指定されていた場合に対応します。

–> Download table2CSV_visibleonly_v2 (Code-Signed AppleScript applet with Framework and Library in its bundle)

各DOM ElementsのWebコンテンツ中の表示座標を取得して、絞り込みを行なっています。ただし、各DOM座標はWebブラウザのスクロールにしたがって数値が変わる(相対座標)ため、少々手こずりました。また、本Scriptでは上下スクロールのみ考慮してDOM要素の抽出を行なっており、横に長いページの横方向スクロールは考慮しておりません。

このバージョンではrowspan / colspanへの対処を追加しました。

行単位で(1次元配列ベースで)表を作っていてはとても対処できなかったので、HTMLの表と同じセル数のヌル文字が入った2次元配列を作成し、そこにX座標/Y座標を指定してセルを埋めるように処理内容を変更しました。また、rowspan/colspanの属性を見つけた場合には、結合されていた複数セルを個別の(同じ値を入れた)セルに分解しています。

本バージョンでは、1つのセル(td)でrowspanとcolspanを同時に指定しないことが処理の前提条件となっています。また、一番上の行がヘッダーの場合を想定しており、一番左の列がヘッダーになっているケースには対処しておりません。

AppleScript名:Safariで現在見えている表を抽出してCSV書き出しv3.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/09/22
–  Modified on: 2019/10/07
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader
use aLib : script "arrayLib"

property NSUUID : a reference to current application’s NSUUID
property NSString : a reference to current application’s NSString
property HTMLDocument : a reference to current application’s HTMLDocument
property NSMutableArray : a reference to current application’s NSMutableArray
property NSJSONSerialization : a reference to current application’s NSJSONSerialization

set aTag to "table"

set indRes to getVisibleElementIndexList(aTag) of me
if indRes = false or indRes = {} then
  display notification "No Visible Table in Web browser"
  
return
end if

tell application "Safari"
  tell front document
    set aSource to source
  end tell
end tell

repeat with i in indRes
  set inList to filterATableAndPaseCells(aSource, i, aTag) of me
  
  
if inList = false or inList = {} then return
  
set aUUID to current application’s NSUUID’s UUID()’s UUIDString() as text
  
set aNewFile to ((path to desktop) as string) & aUUID & ".csv"
  
saveAsCSV(inList, aNewFile) of me
  
  
tell application "Numbers"
    activate
    
open (aNewFile as alias)
  end tell
end repeat

on filterATableAndPaseCells(aSource as string, targInd as integer, aTag as string)
  set aHTML to current application’s HTMLDocument’s documentWithString:(aSource as string)
  
  
–Table要素をリストアップ
  
set eList to (aHTML’s nodesMatchingSelector:aTag) as list
  
set aObj to contents of item (targInd + 1) of eList
  
  
–Count columns of Table Header (Count only)
  
set aTableHeader to (aObj’s nodesMatchingSelector:"tr")’s firstObject()
  
set hList to aTableHeader’s nodesMatchingSelector:"th"
  
set hStrList to {}
  
repeat with i1 in hList
    set hCellStr to i1’s textContent() as string
    
set the end of hStrList to (hCellStr)
  end repeat
  
set hLen to length of hStrList –count columns
  
  
  
–Acquire whole table body contents
  
set aTableBody to (aObj’s nodesMatchingSelector:"tbody")’s firstObject()
  
set bList to (aTableBody’s nodesMatchingSelector:"tr") as list
  
  
set rCount to (length of bList) –count rows
  
  
–行単位ループ
  
set yCount to 1
  
set attrList to make2DBlankArray(hLen, rCount) of aLib
  
  
repeat with i2 in bList
    set bb2List to {}
    
set i3 to (i2’s nodesMatchingSelector:"th") as list
    
if i3 = {} then
      set i3 to (i2’s nodesMatchingSelector:"td") as list
    end if
    
    
–カラム単位ループ
    
set xCount to 1
    
repeat with i4 in i3
      set anAttr to i4’s attributes()
      
set colAtr to (anAttr’s valueForKey:"colspan")
      
set rowAttr to (anAttr’s valueForKey:"rowspan")
      
set cellStr to i4’s textContent() as string
      
      
if colAtr is not equal to missing value then
        –colspan処理
        
set colNum to colAtr as integer
        
set attrList to xFill(xCount, yCount, attrList, cellStr, colNum) of aLib
        
      else if rowAttr is not equal to missing value then
        –rowspan処理
        
set rowNum to rowAttr as integer
        
set attrList to yFill(xCount, yCount, attrList, cellStr, rowNum) of aLib
        
      else if cellStr is not equal to "" then
        –通常処理
        
repeat with ii from xCount to hLen
          set aRes to getItemByXY(ii, yCount, attrList, "") of aLib
          
if aRes = "" then
            set attrList to setItemByXY(ii, yCount, attrList, cellStr) of aLib
            
exit repeat
          else
            set xCount to xCount + 1
          end if
        end repeat
        
      end if
      
      
set xCount to xCount + 1
    end repeat
    
    
set yCount to yCount + 1
  end repeat
  
  
return attrList
end filterATableAndPaseCells

–Safariのウィンドウ上で表示中のDOM Elementsを座標計算して返す
on getVisibleElementIndexList(aTag as string)
  tell application "Safari"
    set dCount to count every document
    
if dCount = 0 then return false
    
    
set jRes to do JavaScript "var winWidth = window.innerWidth,
winHeight = window.innerHeight,
winLeft = window.scrollX,
winTop = window.scrollY,
winBottom = winTop + winHeight,
winRight = winLeft + winWidth,
    elementsArray = document.body.getElementsByTagName(’" & aTag & "’),
    elemLen = elementsArray.length,
inView = [];
      
    var step;
    for (step = 0 ; step < elemLen ; step++) {
      var tmpElem = document.body.getElementsByTagName(’" & aTag & "’)[step];
      var bVar = tmpElem.getBoundingClientRect();
      if (bVar.top > 0 && bVar.top < winHeight) {
        inView.push(step);
      }
    }
    JSON.stringify(inView);"
in front document
    
    
set jList to parseJSONAsList(jRes) of me
    
return jList
    
  end tell
end getVisibleElementIndexList

on parseJSONAsList(jsRes as string)
  set jsonString to NSString’s stringWithString:jsRes
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict as list
end parseJSONAsList

–Save 2D List to CSV file
on saveAsCSV(aList as list, aPath)
  set crlfChar to (string id 13) & (string id 10)
  
set LF to (string id 10)
  
set wholeText to ""
  
  
repeat with i in aList
    set newLine to {}
    
    
–Sanitize (Double Quote)
    
repeat with ii in i
      set jj to ii as text
      
set kk to repChar(jj, string id 34, (string id 34) & (string id 34)) of me –Escape Double Quote
      
set the end of newLine to kk
    end repeat
    
    
–Change Delimiter
    
set aLineText to ""
    
set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to "\",\""
    
set aLineList to newLine as text
    
set AppleScript’s text item delimiters to curDelim
    
    
set aLineText to repChar(aLineList, return, "") of me –delete return
    
set aLineText to repChar(aLineText, LF, "") of me –delete lf
    
    
set wholeText to wholeText & "\"" & aLineText & "\"" & crlfChar –line terminator: CR+LF
  end repeat
  
  
if (aPath as string) does not end with ".csv" then
    set bPath to aPath & ".csv" as Unicode text
  else
    set bPath to aPath as Unicode text
  end if
  
  
writeToFileAsUTF8(wholeText, bPath, false) of me
  
end saveAsCSV

on writeToFileAsUTF8(this_data, target_file, append_data)
  tell current application
    try
      set the target_file to the target_file as text
      
set the open_target_file to open for access file target_file with write permission
      
if append_data is false then set eof of the open_target_file to 0
      
write this_data as «class utf8» to the open_target_file starting at eof
      
close access the open_target_file
      
return true
    on error error_message
      try
        close access file target_file
      end try
      
return error_message
    end try
  end tell
end writeToFileAsUTF8

on repChar(origText as text, targChar as text, repChar as text)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

★Click Here to Open This Script 

Posted in file JavaScript JSON list Record Text | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSJSONSerialization NSMutableArray NSString NSUUID Numbers Safari | 4 Comments

TTSで日本語数値読み上げ

Posted on 9月 26, 2019 by Takaaki Naganoya

桁数の大きな数値のText To Speech(TTS)読み上げのAppleScriptです。

# 日本語環境における枝葉的な(マニアックな)数値表現の仕様に関する話であり、他の言語では関係ない話です。漢字文化圏で使われる数値表現のようですが、たとえば中国や韓国で使われている数値桁表現との間で厳密な互換性があるかといった確認は行なっておりません

実行前に日本語TTS読み上げ音声の「Otoya」あるいは「Kyoko」をインストールしておいてください。

まず、AppleScriptが指数表示なしに表現できる数値は10^9程度で、それを超えると指数表示になります。

ただし、指数表示になった数値を数値文字列に変換するノウハウは全世界的に共有されており、そのためのサブルーチン(Stringify)を呼び出すだけで済みます。

AppleScriptのsayコマンドでは「100兆」までの読み上げはそれっぽく実行してくれますが、「1000兆」になると読み上げ内容が数字の羅列になってしまいます。

これについても、大きな数値を日本語数値エンコーディング文字列に変換するサブルーチンを昔から公開しており(本Blog開設当初の11年前に掲載)、それを呼び出すだけで日本語数値表現文字列に変換できるため、読み上げられることでしょう。

Number Japanese English
1 一(いち) one
10 十(じゅう) ten
100 百(ひゃく) hundred
1000 千(せん) thousand
10000 万(まん) 10 thousand
100000 十万(じゅうまん) 100 thousand
1000000 百万(ひゃくまん) million
10000000 千万(せんまん) 10 million
100000000 億(おく) 100million
1000000000000 兆(ちょう) villion
1000000000000000 京(けい) thousand villion
100000000000000000 100京(ひゃっけい) trillion
10^24 丈(じょ)
10^28 穣(じょう)
10^52 恒河沙(ごうがしゃ)
10^56 阿僧祇(あそうぎ)
10^60 那由他(なゆた)
10^64 不可思議(ふかしぎ)
10^68 無量大数(むりょうたいすう)

とはいえ、「阿僧祇(あそうぎ、10^56)「那由多(なゆた、10^60)」といった数値桁を読み上げさせるとTTSが正しく読み上げてくれません。さすがにこんなにマニアックな数値表現はカバーしなくてよいでしょう。「丈(じょ)」「穣(じょう)」など似た音の桁が存在するあたり、これらは口に出して読み上げるものではなく、文字で読むためだけのものだと強く感じるものです。

AppleScript名:TTSで日本語数値読み上げ
repeat with i from 0 to 15
  set aNum to (10 ^ i)
  
say Stringify(aNum) of me using "Kyoko" –or "Otoya"
end repeat

on Stringify(x) — for E+ numbers
  set x to x as string
  
set {tids, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, {"E+"}}
  
if (count (text items of x)) = 1 then
    set AppleScript’s text item delimiters to {tids}
    
return x
  else
    set {n, z} to {text item 1 of x, (text item 2 of x) as integer}
    
set AppleScript’s text item delimiters to {tids}
    
set i to character 1 of n
    
set decSepChar to character 2 of n — "." or ","
    
set d to text 3 thru -1 of n
    
set l to count d
    
if l > z then
      return (i & (text 1 thru z of d) & decSepChar & (text (z + 1) thru -1 of d))
    else
      repeat (z – l) times
        set d to d & "0"
      end repeat
      
return (i & d)
    end if
  end if
end Stringify

★Click Here to Open This Script 

AppleScript名:TTSで日本語数値読み上げ v2
repeat with i from 15 to 70
  set aNum to (10 ^ i)
  
set jRes to encodeJapaneseNumText(aNum) of japaneseNumberEncodingKit
  
say jRes using "Kyoko" –or "Otoya"
end repeat

–課題:オーバーフローチェックを行っていない
set a to "102320120000108220010"
set jRes to encodeJapaneseNumText(a) of japaneseNumberEncodingKit
–> "1垓232京120兆1億822万10"

script japaneseNumberEncodingKit
  –数字文字列を日本語数値表現文字列に変換
  
on encodeJapaneseNumText(aNum)
    
    
set aText to Stringify(aNum) of me
    
set aText to aText as Unicode text
    
set dotText to "." as Unicode text
    
set upperDigit to ""
    
set lowerDigit to ""
    
    
–小数点の処理
    
if dotText is in aText then
      set b to offset of dotText in aText
      
set upperDigit to characters 1 thru (b – 1) of aText
      
set upperDigit to upperDigit as Unicode text
      
set lowerDigit to characters b thru -1 of aText
      
set lowerDigit to lowerDigit as Unicode text
    else
      set upperDigit to aText
    end if
    
    
    
set scaleList3 to {"", "万", "億", "兆", "京", "垓", "丈", "壌", "溝", "砂", "正", "載", "極", "恒河沙", "阿僧梢", "那由他", "不可思議", "無量大数"}
    
set splitDigit to 4
    
set nList to splitByDigit(upperDigit, splitDigit) of me
    
set nList to reverse of nList
    
    
set resText to ""
    
set digCount to 1
    
repeat with i in nList
      set b to (contents of i) as number
      
if b is not equal to 0 then
        set resText to (b as text) & item digCount of scaleList3 & resText
      end if
      
set digCount to digCount + 1
    end repeat
    
    
    
    
return resText & lowerDigit
    
  end encodeJapaneseNumText
  
  
–指定桁数で区切る
  
on splitByDigit(a, splitDigit)
    set aList to characters of a
    
set aList to reverse of aList
    
log aList
    
set resList to {}
    
set tempT to ""
    
set tempC to 1
    
repeat with i in aList
      set tempT to contents of i & tempT
      
if tempC mod splitDigit = 0 then
        set resList to {tempT} & resList
        
set tempT to ""
      end if
      
set tempC to tempC + 1
    end repeat
    
    
if tempT is not equal to "" then
      set resList to {tempT} & resList
    end if
    
    
resList
    
  end splitByDigit
  
  
  
  
on Stringify(x) — for E+ numbers
    set x to x as string
    
set {tids, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, {"E+"}}
    
if (count (text items of x)) = 1 then
      set AppleScript’s text item delimiters to tids
      
return x
    else
      set {n, z} to {text item 1 of x, (text item 2 of x) as integer}
      
set AppleScript’s text item delimiters to tids
      
set i to character 1 of n
      
set decSepChar to character 2 of n — "." or ","
      
set d to text 3 thru -1 of n
      
set l to count d
      
if l > z then
        return (i & (text 1 thru z of d) & decSepChar & (text (z + 1) thru -1 of d))
      else
        repeat (z – l) times
          set d to d & "0"
        end repeat
        
return (i & d)
      end if
    end if
  end Stringify
end script

★Click Here to Open This Script 

Posted in Number System Text Text to Speech | Tagged 10.12savvy 10.13savvy 10.14savvy | Leave a comment

Safariで現在見えている表を抽出してCSV書き出し

Posted on 9月 24, 2019 by Takaaki Naganoya

Safariの最前面のウィンドウで表示中のページのうち、現在ウィンドウ内に表示中の表要素をCSV書き出ししてNumbersでオープンするAppleScriptです。

このところ下調べを行なっていた「Webブラウザで表示中の要素を処理する」「表示中ではない要素は処理をしない」というScriptです。

これで、「表の一部を選択しておく」とかいった操作は不要になりました。ウィンドウ内に表示されている表をWebコンテンツ内部の表示座標をもとに自動抽出します。表示エリア外に位置しているものは書き出し処理しません。

各DOM ElementsのWebコンテンツ中の表示座標を取得して、絞り込みを行なっています。ただし、各DOM座標はWebブラウザのスクロールにしたがって数値が変わる(相対座標)ため、少々手こずりました。また、本Scriptでは上下スクロールのみ考慮してDOM要素の抽出を行なっており、横に長いページの横方向スクロールは考慮しておりません。

本Scriptは大量一括処理を志向するプログラムではなく、「見えているもの」をそのまま処理してほしいという考えで作ったものでもあり、Webブラウザ(Safari)で表示中のページのソースを取得してそのまま処理しています。つまり、ユーザーが閲覧中のページのデータそのものを処理しています。

これは、ページのソースを取得するコマンドを持っていないGoogle Chromeにはできない処理です(同じURLの内容を別途curlコマンドなどで取得すればOK。Cookie値などの再現が大変でしょうけれども)。

その他、実際に作って使ってみた感想は、装飾用に使われている表データまで取り込んでしまう点に不満があるぐらいでしょうか。これら「ゴミデータ」(再利用する価値のない装飾用の表データ)を区別するために、行数が足りない場合には書き出さないといった「足切り」を行う必要性を感じます。

–> Download VisibleTableExporter(Code-signed executable applet with Framework in its bundle)

AppleScript名:Safariで現在見えている表を抽出してCSV書き出し.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/09/22
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader

property NSUUID : a reference to current application’s NSUUID
property NSString : a reference to current application’s NSString
property HTMLDocument : a reference to current application’s HTMLDocument
property NSMutableArray : a reference to current application’s NSMutableArray
property NSJSONSerialization : a reference to current application’s NSJSONSerialization

set aTag to "table"

set indRes to getVisibleElementIndexList(aTag) of me
if indRes = false or indRes = {} then
  display notification "No Visible Table in Web browser"
  
return
end if

tell application "Safari"
  tell front document
    set aSource to source
  end tell
end tell

repeat with i in indRes
  set inList to filterATableAndPaseCells(aSource, i, aTag) of me
  
if inList = false or inList = {} then return
  
set aUUID to current application’s NSUUID’s UUID()’s UUIDString() as text
  
set aNewFile to ((path to desktop) as string) & aUUID & ".csv"
  
saveAsCSV(inList, aNewFile) of me
  
  
tell application "Numbers"
    open (aNewFile as alias)
  end tell
end repeat

tell application "Numbers" to activate

on filterATableAndPaseCells(aSource as string, targInd as integer, aTag as string)
  set aHTML to current application’s HTMLDocument’s documentWithString:(aSource as string)
  
  
–Table要素をリストアップ
  
set eList to (aHTML’s nodesMatchingSelector:aTag) as list
  
set aObj to contents of item (targInd + 1) of eList
  
  
  
–Count columns of Table Header
  
set aTableHeader to (aObj’s nodesMatchingSelector:"tr")’s firstObject()
  
set hList to aTableHeader’s nodesMatchingSelector:"th"
  
set hStrList to {}
  
repeat with i1 in hList
    set the end of hStrList to i1’s textContent() as string
  end repeat
  
set hLen to length of hStrList –count columns
  
  
–Acquire whole table body contents
  
set aTableBody to (aObj’s nodesMatchingSelector:"tbody")’s firstObject()
  
set bList to aTableBody’s nodesMatchingSelector:"td"
  
set bbList to {}
  
repeat with i2 in bList
    set the end of bbList to i2’s textContent() as string
  end repeat
  
  
set tbList to makeList1DTo2D(bbList, hLen) of me
  
  
return {hStrList} & tbList
end filterATableAndPaseCells

–1D Listを2D化
on makeList1DTo2D(orig1DList as list, aMax)
  set tbList to {}
  
set tmpList to {}
  
set aCount to 1
  
  
repeat with i3 in orig1DList
    set j to contents of i3
    
set the end of tmpList to j
    
    
if aCount ≥ aMax then
      set aCount to 1
      
set the end of tbList to tmpList
      
set tmpList to {}
    else
      set aCount to aCount + 1
    end if
  end repeat
  
  
return tbList
end makeList1DTo2D

–Safariのウィンドウ上で表示中のDOM Elementsを座標計算して返す
on getVisibleElementIndexList(aTag as string)
  tell application "Safari"
    set dCount to count every document
    
if dCount = 0 then return false
    
    
set jRes to do JavaScript "var winWidth = window.innerWidth,
winHeight = window.innerHeight,
winLeft = window.scrollX
winTop = window.scrollY,
winBottom = winTop + winHeight,
winRight = winLeft + winWidth,
    elementsArray = document.body.getElementsByTagName(’" & aTag & "’),
    elemLen = elementsArray.length,
inView = [];
      
    var step;
    for (step = 0 ; step < elemLen ; step++) {
      var tmpElem = document.body.getElementsByTagName(’" & aTag & "’)[step];
      var bVar = tmpElem.getBoundingClientRect();
      if (bVar.top > 0 && bVar.top < winHeight) {
        inView.push(step);
      }
    }
    JSON.stringify(inView);"
in front document
    
    
set jList to parseJSONAsList(jRes) of me
    
return jList
    
  end tell
end getVisibleElementIndexList

on parseJSONAsList(jsRes as string)
  set jsonString to NSString’s stringWithString:jsRes
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict as list
end parseJSONAsList

–Save 2D List to CSV file
on saveAsCSV(aList as list, aPath)
  set crlfChar to (string id 13) & (string id 10)
  
set LF to (string id 10)
  
set wholeText to ""
  
  
repeat with i in aList
    set newLine to {}
    
    
–Sanitize (Double Quote)
    
repeat with ii in i
      set jj to ii as text
      
set kk to repChar(jj, string id 34, (string id 34) & (string id 34)) of me –Escape Double Quote
      
set the end of newLine to kk
    end repeat
    
    
–Change Delimiter
    
set aLineText to ""
    
set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to "\",\""
    
set aLineList to newLine as text
    
set AppleScript’s text item delimiters to curDelim
    
    
set aLineText to repChar(aLineList, return, "") of me –delete return
    
set aLineText to repChar(aLineText, LF, "") of me –delete lf
    
    
set wholeText to wholeText & "\"" & aLineText & "\"" & crlfChar –line terminator: CR+LF
  end repeat
  
  
if (aPath as string) does not end with ".csv" then
    set bPath to aPath & ".csv" as Unicode text
  else
    set bPath to aPath as Unicode text
  end if
  
  
writeToFileAsUTF8(wholeText, bPath, false) of me
  
end saveAsCSV

on writeToFileAsUTF8(this_data, target_file, append_data)
  tell current application
    try
      set the target_file to the target_file as text
      
set the open_target_file to open for access file target_file with write permission
      
if append_data is false then set eof of the open_target_file to 0
      
write this_data as «class utf8» to the open_target_file starting at eof
      
close access the open_target_file
      
return true
    on error error_message
      try
        close access file target_file
      end try
      
return error_message
    end try
  end tell
end writeToFileAsUTF8

on repChar(origText as text, targChar as text, repChar as text)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

★Click Here to Open This Script 

Posted in file JavaScript JSON list Text | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSJSONSerialization NSMutableArray NSString NSUUID Numbers Safari | 1 Comment

Skimでオープン中のPDFで選択中のテキストを返す

Posted on 9月 16, 2019 by Takaaki Naganoya

フリーでScriptableなmacOS用PDFビューワー「Skim」上でオープン中のPDFで、選択中のテキストの内容を取得するAppleScriptです。

フリーかつオープンソースで提供されているアプリケーションのうち、奇跡的に豊富なAppleScript対応機能を備えるPDFビューワー、それがSkimです。Skimに比べればPreview.appなど取るに足らない存在。「PDFビューワー四天王」のうち、その最上位に君臨するアプリケーションこそがSkimです(四天王とかいいつつ、Skim、Preview、Acrobatの3人しかいないのはお約束)。


▲SkimでPDFをオープンし、「AppleScriptってなんだろう?」の文字列を選択

ただ、そんなグレートな存在のSkimでも、「選択中のテキストを取得する」という処理を書いたことはありませんでした。

Skimの「selection」によって取得されるのがテキストではなくRTFなので、AppleScriptの基本的な機能ではこのRTFはひどく扱いが難しいデータ「でした」。

しかし、Cocoaの機能を利用することで、テキストへの変換は可能です。

それでも、Cocoaが期待するRTFのデータとAppleScriptの世界のRTFのデータ同士の変換が難儀でした。食後の腹ごなしに行うには手に余るといったレベル。

そこで、お気軽データ変換の最後の砦であるクリップボードを経由してRTFをAppleScriptの世界からCocoaの世界に受け渡してみたところ、大成功。あとは、PDFから取得したテキストデータによくあることですが、日本語のテキストだとUnicodeのNormalize方法の問題によりひらがな/カタカナと濁点や半濁点が分離した状態で返ってきました。

これについても、Cocoaの機能を利用してNormalizeを行い、常識的なテキストに変換できました。

AppleScript名:Skimでオープン中のPDFの選択中のテキストを返す
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/09/16
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

tell application "Skim"
  tell front document
    set aSel to selection
    
repeat with i in aSel
      set aCon to contents of i
      
set rList to RTF of aCon
      
      
set sCon to ""
      
repeat with ii in rList
        set the clipboard to ii
        
set aText to getClipboardAsText() of me
        
set aCon to aCon & aText
      end repeat
      
      
set aStr to textfy(aCon) of me
      
return aStr
    end repeat
  end tell
end tell

–Normalize Unicode Text in NFKC
on textfy(aText as string)
  set aStr to current application’s NSString’s stringWithString:aText
  
set aNFKC to aStr’s precomposedStringWithCompatibilityMapping()
  
return aNFKC as string
end textfy

–Clipboard内の情報をテキストとして取得する
on getClipboardAsText()
  — get the pasteboard items
  
set theClip to current application’s NSPasteboard’s generalPasteboard()
  
set pbItems to theClip’s pasteboardItems()
  
  
set theStrings to {}
  
  
repeat with anItem in pbItems
    if (anItem’s types()’s containsObject:(current application’s NSPasteboardTypeString)) then
      set end of theStrings to (anItem’s stringForType:(current application’s NSPasteboardTypeString)) as text
    end if
  end repeat
  
  
return theStrings as text
end getClipboardAsText

★Click Here to Open This Script 

とか言ってたら、夕飯の買い物に出かけようとした頃にShane Stanleyから「もっとシンプルに書けるよー」というサンプルが届いて脱力しました。もっと簡潔に書けたようです(同一サンプルで日本語データに対してチェックずみ)。

ただ、PDFから文字取り出ししたあとは、Unicodeの再Normalizeは割とやらないといけないケースが多いので、選択部分(selection)からRTFじゃなくてcharacterでデータを取り出せばよかったというあたりが反省点でしょうか。

set theText to ""
tell application "Skim"
  tell front document
    set aSel to selection
    
repeat with anItem in aSel
      set theText to theText & (characters of anItem) as text
    end repeat
  end tell
end tell
return theText

★Click Here to Open This Script 

Posted in Clipboard RTF Text | Tagged 10.12savvy 10.13savvy 10.14savvy NSPasteboard NSPasteboardTypeString NSString Skim | Leave a comment

tableExtractor

Posted on 9月 15, 2019 by Takaaki Naganoya

Safariで表示中のページのうち、テキストを選択中のキーワードを含む表をCSVファイルに書き出してNumbersでオープンするAppleScriptです。

–> Download tableExtractor Run-Only (Code-Signed Executable including Framework in its bundle)

–> Watch Demo movie

実行前にSafariの「開発」メニューから、「スマート検索フィールドからのJavaScriptの実行を許可」「AppleEventからのJavaScriptの実行を許可」を実行しておく必要があります(実行済みの場合には必要ありません)。


▲Safariで表示中のページのうち、CSV書き出ししたい表のテキストを選択


▲本Scriptで表をCSVに書き出してNumbersでオープン

以前に作成した「Safariで表示中のPageの選択中の文字を含む表データを取得」Scriptがいい線を行っていた(あらかじめ表中のテキストを選択しておく、という前提条件がかったるいかと思っていたのに、そうでもなかった)ので、ありもののサブルーチンを追加して、表部分のHTMLからのタグ削除やCSV書き出しなどを行えるようにしました。

本Scriptは表データをCSV書き出しする必要はどこにもないのですが、Numbers v6.1に「表を新規作成して表のセル数を指定すると多くの場合にエラーになる」というバグがあるので、Numbersを直接操作してデータ出力させることはやっていません。

処理時間もさほどかからないので、表示中のページのすべての表オブジェクトをCSV化したり、表を選択するUIを実装して、「どの表を出力するか?」という選択処理をしてもいいかもしれません。


▲漫然とMacOS日本語で書き出ししたため文字化けしたもの(左)、UTF8を指定して書き出ししたために文字化けしなくなったもの(右)

途中でCSV書き出しした表データに文字化けが発生していたのですが、これはUTF8でファイル書き出ししていなかったためでした。

本Scriptは前バージョンよりもキーワードの検出処理をていねいに行なっています。各TableのHTMLに対してタグの除去を行なったうえでWebブラウザ上で選択中の文字列を含んでいるかどうかをチェックしています。

AppleScript名:tableExtractor.scptd
— Created 2019-09-15 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader

property NSString : a reference to current application’s NSString
property HTMLDocument : a reference to current application’s HTMLDocument
property NSMutableArray : a reference to current application’s NSMutableArray

tell application "Safari"
  set dList to every document –Sometimes "count every document"causes error
  
if length of dList = 0 then return
  
  
–Get URL
  
tell front document
    set aURL to URL
  end tell
  
  
–Get Selected Text
  
set aRes to do JavaScript "var selObj = window.getSelection();
  var selStr = (selObj).getRangeAt(0);
  unescape(selStr);"
in front document
  
  
if aRes = "" then return
end tell

set aRes to filterATableAndPaseCells(aURL, aRes) of me
if aRes = false then
  display notification "I could not filter table data…"
  
return
end if

–Save 2D List to temp CSV file on desktop folder
set savePath to ((path to desktop) as string) & (do shell script "uuidgen") & ".csv"
saveAsCSV(aRes, savePath) of me

tell application "Numbers"
  activate
  
open file savePath
end tell

on filterATableAndPaseCells(aURL, aKeyword)
  set aData to (do shell script "curl " & aURL)
  
set aHTML to current application’s HTMLDocument’s documentWithString:(aData as string)
  
  
–Table要素をリストアップ
  
set eList to (aHTML’s nodesMatchingSelector:"table")
  
  
–Table要素のうちSafari上で選択中の文字列を含むものをサーチ(指定データを含むものを抽出)
  
set hitF to false
  
repeat with i in eList
    set cellList to i’s children()’s array()
    
set htmlSource to i’s serializedFragment() as string –HTML source
    
set html2 to trimStrFromTo(htmlSource, "<", ">") of me
    
set html3 to repChar(html2, return, "") of me
    
    
if html3 contains aKeyword then
      set hitF to true
      
exit repeat
    end if
  end repeat
  
if hitF = false then return false
  
  
–Count columns of Table Header
  
set aTableHeader to (i’s nodesMatchingSelector:"tr")’s firstObject()
  
set hList to aTableHeader’s nodesMatchingSelector:"th"
  
set hStrList to {}
  
repeat with i1 in hList
    set the end of hStrList to i1’s textContent() as string
  end repeat
  
set hLen to length of hStrList –count columns
  
  
–Acquire whole table body contents
  
set aTableBody to (i’s nodesMatchingSelector:"tbody")’s firstObject()
  
set bList to aTableBody’s nodesMatchingSelector:"td"
  
set bbList to {}
  
repeat with i2 in bList
    set the end of bbList to i2’s textContent() as string
  end repeat
  
  
set tbList to makeList1DTo2D(bbList, hLen) of me
  
  
return {hStrList} & tbList
end filterATableAndPaseCells

–1D Listを2D化
on makeList1DTo2D(orig1DList, aMax)
  set tbList to {}
  
set tmpList to {}
  
set aCount to 1
  
  
repeat with i3 in orig1DList
    set j to contents of i3
    
set the end of tmpList to j
    
    
if aCount ≥ aMax then
      set aCount to 1
      
set the end of tbList to tmpList
      
set tmpList to {}
    else
      set aCount to aCount + 1
    end if
  end repeat
  
  
return tbList
end makeList1DTo2D

on trimStrFromTo(aParamStr, fromStr, toStr)
  set theScanner to current application’s NSScanner’s scannerWithString:aParamStr
  
set anArray to current application’s NSMutableArray’s array()
  
  
repeat until (theScanner’s isAtEnd as boolean)
    set {theResult, theKey} to theScanner’s scanUpToString:fromStr intoString:(reference)
    
    
theScanner’s scanString:fromStr intoString:(missing value)
    
set {theResult, theValue} to theScanner’s scanUpToString:toStr intoString:(reference)
    
if theValue is missing value then set theValue to ""
    
    
theScanner’s scanString:toStr intoString:(missing value)
    
    
anArray’s addObject:theValue
  end repeat
  
  
if anArray’s |count|() = 0 then return aParamStr
  
  
copy aParamStr to curStr
  
repeat with i in (anArray as list)
    set curStr to repChar(curStr, fromStr & i & toStr, "") of me
  end repeat
  
  
return curStr
end trimStrFromTo

on repChar(aStr, targStr, repStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set bString to aString’s stringByReplacingOccurrencesOfString:targStr withString:repStr
  
set cString to bString as string
  
return cString
end repChar

–2D List to CSV file
on saveAsCSV(aList, aPath)
  –set crlfChar to (ASCII character 13) & (ASCII character 10)
  
set crlfChar to (string id 13) & (string id 10)
  
set LF to (string id 10)
  
set wholeText to ""
  
  
repeat with i in aList
    set newLine to {}
    
    
–Sanitize (Double Quote)
    
repeat with ii in i
      set jj to ii as text
      
set kk to repChar(jj, string id 34, (string id 34) & (string id 34)) of me –Escape Double Quote
      
set the end of newLine to kk
    end repeat
    
    
–Change Delimiter
    
set aLineText to ""
    
set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to "\",\""
    
set aLineList to newLine as text
    
set AppleScript’s text item delimiters to curDelim
    
    
set aLineText to repChar(aLineList, return, "") of me –delete return
    
set aLineText to repChar(aLineText, LF, "") of me –delete lf
    
    
set wholeText to wholeText & "\"" & aLineText & "\"" & crlfChar –line terminator: CR+LF
  end repeat
  
  
if (aPath as string) does not end with ".csv" then
    set bPath to aPath & ".csv" as Unicode text
  else
    set bPath to aPath as Unicode text
  end if
  
  
writeToFileUTF8(wholeText, bPath, false) of me
  
end saveAsCSV

on writeToFileUTF8(this_data, target_file, append_data)
  tell current application
    try
      set the target_file to the target_file as text
      
set the open_target_file to open for access file target_file with write permission
      
if append_data is false then set eof of the open_target_file to 0
      
write this_data as «class utf8» to the open_target_file starting at eof
      
close access the open_target_file
      
return true
    on error error_message
      try
        close access file target_file
      end try
      
return error_message
    end try
  end tell
end writeToFileUTF8

★Click Here to Open This Script 

Posted in file Internet JavaScript list Text | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSMutableArray NSString Numbers Safari | 1 Comment

Safariで表示中のPageの選択中の文字を含む表データを取得

Posted on 9月 3, 2019 by Takaaki Naganoya

Safari上で一部のテキストを選択した「表」のデータをHTMLReaderフレームワークを利用してparseし、2D Listとして取得するAppleScriptです。

Web上の表データをそのまま利用したいケースが多々あります。こんな小さなデータではなく、数百個にわたる表データをインポートして使いたいというケースです。

そのときに作った部品を転用して、より一般的な用途に使えるようにしたのが本Scriptです。ただし、さまざまな用途に使って鍛えたというものでもなく、AppleのWebドキュメントやWikiの内容の抽出など、割と「規則性の高そうなコンテンツ」で利用してみました。

本来は、複数ページの特定の表を指定してデータを取得する用途に用いているものなので、本Scriptのように「選択中の文字列を含む表」といった、のどかな使い方はしません。動作内容がわかりやすいように作り変えたためにこのような仕様になっています。

どこぞのオンラインストアの諸元をまとめた表をWeb上からくすねてくる、とかいう用途だと、割と表が込み入って(JavaScriptを仕込んでソートし直せるようにしてあるとか)いるケースがあるので、どのページのどの表にでもあまねく利用できるという種類のものではありません。

–> Download HTMLReader.framework(To ~/Library/Frameworks)

HTMLReader.frameworkを利用するためには、macOS 10.14以降だとSIPを解除するかScript Debugger上で動かすか、AppleScriptアプレット内に組み込んで実行することになります。

AppleScript名:Safariで表示中のPageの選択中の文字を含む表データを取得.scptd
— Created 2019-09-02 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader

property NSString : a reference to current application’s NSString
property HTMLDocument : a reference to current application’s HTMLDocument
property NSMutableArray : a reference to current application’s NSMutableArray

tell application "Safari"
  set dList to every document –Sometimes "count every document"causes error
  
if length of dList = 0 then return
  
  
–Get URL
  
tell front document
    set aURL to URL
  end tell
  
  
–Get Selected Text
  
set aRes to do JavaScript "var selObj = window.getSelection();
  var selStr = (selObj).getRangeAt(0);
  unescape(selStr);"
in front document
  
  
if aRes = "" then return
end tell

set aRes to filterATableAndPaseCells(aURL, aRes) of me
–> {{"Objective-C and AppleScript class", "Attributes (script term, if different)", "Relationships"}, {"NSObjectImplements the item AppleScript class. For any scriptable Objective-C class that inherits from NSObject, the AppleScript class it implements inherits from the item class (and inherits the class property and the properties property).", "class name (class), properties", ""}, {"NSApplicationImplements the application AppleScript class.", "name, active flag (frontMost), version", "documents, windows (both accessible as ordered relationship)"}, {"NSDocumentImplements the document AppleScript class.", "location of the document’s on-disk representation (path); last component of filename (name); edited flag (modified)", ""}, {"NSWindowImplements the window AppleScript class.", "title (name); various binary-state attributes: closeable, floating, miniaturized, modal, resizable, titled, visible, zoomable", "document"}}

on filterATableAndPaseCells(aURL, aKeyword)
  set aData to (do shell script "curl " & aURL)
  
set aHTML to current application’s HTMLDocument’s documentWithString:(aData as string)
  
  
–Table要素をリストアップ
  
set eList to (aHTML’s nodesMatchingSelector:"table")
  
  
–Table要素のうちSafari上で選択中の文字列を含むものをサーチ(指定データを含むものを抽出)
  
set hitF to false
  
repeat with i in eList
    set cellList to i’s children()’s array()
    
set htmlSource to i’s serializedFragment() as string –HTML source
    
    
if htmlSource contains aKeyword then
      set hitF to true
      
exit repeat
    end if
  end repeat
  
if hitF = false then return false
  
  
–Count columns of Table Header
  
set aTableHeader to (i’s nodesMatchingSelector:"tr")’s firstObject()
  
set hList to aTableHeader’s nodesMatchingSelector:"th"
  
set hStrList to {}
  
repeat with i1 in hList
    set the end of hStrList to i1’s textContent() as string
  end repeat
  
set hLen to length of hStrList –count columns
  
  
–Acquire whole table body contents
  
set aTableBody to (i’s nodesMatchingSelector:"tbody")’s firstObject()
  
set bList to aTableBody’s nodesMatchingSelector:"td"
  
set bbList to {}
  
repeat with i2 in bList
    set the end of bbList to i2’s textContent() as string
  end repeat
  
  
set tbList to makeList1DTo2D(bbList, hLen) of me
  
  
return {hStrList} & tbList
end filterATableAndPaseCells

–1D Listを2D化
on makeList1DTo2D(orig1DList, aMax)
  set tbList to {}
  
set tmpList to {}
  
set aCount to 1
  
  
repeat with i3 in orig1DList
    set j to contents of i3
    
set the end of tmpList to j
    
    
if aCount ≥ aMax then
      set aCount to 1
      
set the end of tbList to tmpList
      
set tmpList to {}
    else
      set aCount to aCount + 1
    end if
  end repeat
  
  
return tbList
end makeList1DTo2D

★Click Here to Open This Script 

Posted in JavaScript Text URL | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSMutableArray NSString Safari | 1 Comment

指定URLのMS名を取得する v2a

Posted on 9月 3, 2019 by Takaaki Naganoya

Shane Stanleyが「HTMLをXMLと見立ててアクセスすれば外部フレームワークなしに処理できて簡単だよ」と、送ってくれたサンプルScriptです。

2つの意味で焦りました。

(1)指定URLの内容をダウンロードするのに、「initWithContentsOfURL:」で処理
(2)この調子で処理したら、お手軽にREST APIも呼べそうな雰囲気

いろいろ考えさせられる内容でもあります。こういう「それ自体で何か製品を構成できるほどのサイズの処理じゃないけど、何かに絶対に使ってますよね」的な処理をBlogで公開しておくことのメリットを感じつつ、XML処理とか正規表現の処理が個人的に不得意なので、とても参考になります。

自分の用途が残念な(そんなに生産的でもなく趣味的な、という意味で)ものだったので、恐縮するばかりですー(オンラインゲームの機体のデータをWikiからまるごと引っこ抜くというものだったので)。

AppleScript名:get a title.scptd
—
–  Created by: Shane Stanley
–  Created on: 2019/09/03
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

— classes, constants, and enums used
property NSXMLDocumentTidyHTML : a reference to 512
property NSXMLDocument : a reference to current application’s NSXMLDocument
property NSString : a reference to current application’s NSString
property |NSURL| : a reference to current application’s |NSURL|
property HTMLDocument : a reference to current application’s HTMLDocument
property NSMutableArray : a reference to current application’s NSMutableArray

set aURL to "https://w.atwiki.jp/senjounokizuna/pages/1650.html"
set aRes to getTitleFromAURL(aURL) of me
–> "ジム・スナイパー  RGM-79(G)"

on getTitleFromAURL(aURL)
  set theNSURL to |NSURL|’s URLWithString:aURL
  
set {theXML, theError} to NSXMLDocument’s alloc()’s initWithContentsOfURL:theNSURL options:NSXMLDocumentTidyHTML |error|:(reference)
  
if theXML is missing value then error theError’s localizedDescription() as text
  
repeat with i from 2 to 7 by 1
    set theNodes to (theXML’s nodesForXPath:("//h" & i) |error|:(missing value))
    
if theNodes’s |count|() is not 0 then return (theNodes’s firstObject()’s stringValue()) as text
  end repeat
  
error "Header is missing"
end getTitleFromAURL

★Click Here to Open This Script 

Posted in Text URL XML | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSMutableArray NSString NSURL NSXMLDocument NSXMLDocumentTidyHTML | Leave a comment

指定URLのMS名を取得する v2

Posted on 9月 3, 2019 by Takaaki Naganoya

指定URLの初出の指定タグ要素を抽出するAppleScriptです。

たまたま、戦場の絆Wikiから各種データを自動で抽出するAppleScriptを書いたときについでに作った、各ページのh2タグで囲まれた機種名を取り出す処理部分です。


▲このデータだけ機種名がh3タグでマークされていて、例外を吸収するために汎用性を高めたのが本ルーチン

Webサイトからのデータ取り出しは割と重要な技術です。それを容易に可能にするHTMLReaderのようなFrameworkは、とても重要なパーツといえます。HTMLReaderがなければ、こんな簡単に処理することはできなかったでしょう(この些細な処理を、ではなくやりたい処理全体に対しての評価)。

# WebスクレイピングはScripter必須の技術なので、Safari/ChromeでDOMアクセス派や正規表現でソースから抽出派、XMLとして解釈してXPathでアクセスする派などいろいろありそうですが、自分はHTMLReaderを使って楽をしてデータを取り出す派 といえます

特定のURL上のHTMLの特定のタグ要素のデータを抜き出すという処理であり、かならずしもどのサイトでも万能に処理できるというわけでもありません。ただ、Wikiのような管理プログラムでコンテンツを生成しているサイトから各種データを抜き出すのは、生成されるHTMLの規則性が高くて例外が少ないため、割と簡単です。

HTMLReaderをAppleScriptから呼び出し、表データを2D Listとして解釈するなど、データ取り出しが簡単にできるようになったことは意義深いと思われます。

macOS 10.13まではスクリプトエディタ/Script Debugger上でScriptを直接実行できます。macOS 10.14以降ではSIPを解除するか、Script Debugger上で実行するか、本記事に添付したようなアプレット(バンドル内にFramework同梱)を実行する必要があります。

HTMLReaderについては、Frameworkにするよりもアプリケーション化してsdefをつけて、AppleEvent経由で呼び出す専用のバックグラウンドアプリケーションにすることも考えるべきかもしれません。ただ、すべての機能についてsdefをかぶせるためには、「こういうパターンで処理すると便利」という例をみつけてまとめる必要があります。つまり、sdefをかぶせると返り値はAppleScript的なデータに限定されるため、何らかの処理が完結した状態にする必要があります。

–> Download tagElementPicker.zip (Code Signed executable Applet)

–> Download HTMLReader.framework (To ~/Library/Frameworks)

Webコンテンツのダウンロードは、本ルーチンではcurlコマンドで実装していますが、いろいろ試してみたところ現時点で暫定的にこれがベストという判断を行っています。

もともと、macOS 10.7でURL Access Scriptingが廃止になったため、Webアクセスのための代替手段を確保することはScritperの間では優先順位の高い調査項目でした。

curlコマンドはその代替手段の中でも最有力ではあったものの、macOS 10.10以降のAppleScript処理系自体のScripting Bridge対応にともない、NSURLConnectionを用いたアクセスも試してきました。同期処理できて、Blocks構文の記述が必須ではないため、実装のための難易度がCocoa系のサービスでは一番低かったからです。

ただし、NSURLConnection自体がDeprecated扱いになり、後継のNSURLSessionを用いた処理を模索。いろいろ書いているうちに、処理内容がapplescript-stdlibのWebモジュールと酷似した内容になってきた(もともと同ライブラリではNSURLSessionを用いていたため)ので、この機能のためだけにapplescript-stdlibを組み込んで使ってみたりもしました。

しかし、applescript-stdlibのWebモジュールは連続して呼び出すと処理が止まるという代物であり、実際のプログラムに組み込んで使うのは「不可能」でした。1つのURLを処理するには問題はないものの、数百個のURLを処理させると止まることを確認しています。おまけに処理本体にも自分自身のsdefを用いた記述を行っているためメンテナンス性が最悪で、中身をいじくることは(自分には)無理です。

# applescript-stdlibのWebモジュールではUserAgent名がサイト側の想定しているものに該当せずアクセスを拒否されたのか、Webモジュール側の内部処理がまずいのかまでは原因追求できていません。連続処理を行うと止まるという症状を確認しているだけです

NSURLSessionによる処理については、applescript-stdlibのWebモジュールを参考にしつつもう少し書き慣れる必要がある一方で、いろいろモジュール単位で差し替えて試行錯誤したところ、curlコマンドは遅くなったり処理が止まったりすることもなく利用できています。

それでも、curlコマンド以外の選択肢を用意しておくことは重要であるため、NSURLSessionも引き続き追いかけておきたいところです。

AppleScript名:指定URLのMS名を取得する v2.scptd
— Created 2019-09-02 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader

property NSString : a reference to current application’s NSString
property HTMLDocument : a reference to current application’s HTMLDocument
property NSMutableArray : a reference to current application’s NSMutableArray

set aURL to "https://w.atwiki.jp/senjounokizuna/pages/1650.html"
set aRes to getTitleFromAURL(aURL) of me
–> "ジム・スナイパー  RGM-79(G)"

on getTitleFromAURL(aURL)
  set aData to (do shell script "curl " & aURL)
  
set aHTML to current application’s HTMLDocument’s documentWithString:(aData as string)
  
  
–Levelの高いHeader Tagから順次低い方にサーチして返す
  
repeat with i from 2 to 7 by 1
    set aHeaderTag to "h" & i as string
    
set eList to (aHTML’s nodesMatchingSelector:aHeaderTag)
    
    
if (eList as list) is not equal to {} then
      return (eList’s firstObject()’s textContent()) as string
    end if
  end repeat
  
  
error "Header is missing"
end getTitleFromAURL

★Click Here to Open This Script 

Posted in Text URL | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSMutableArray NSString | Leave a comment

Numbersで選択範囲のセルから数字以外の文字を除去する

Posted on 8月 29, 2019 by Takaaki Naganoya

Numbersで選択範囲のセルから数字以外の文字を除去するAppleScriptです。

よく、Webブラウザ上で表示中の表データからNumbersなどの表計算ソフトにデータをコピー&ペーストして再利用することがあります。この際に、Webブラウザ上で選択中のDOM構造などを取得できると便利なのですが、いろいろ調べてみてもなかなか方法が見つかりません(自分が設計していたら、絶対に実装してるんですけれども)。

そこで、表データをWebブラウザから表計算ソフト上にコピー後にデータ加工することを考えることになります。

ExcelやNumbers上に表データをペーストして、その後で加工することをよく行います。手動で行うとかったるいので、選択範囲のセルを順次加工するScriptを日常的に作ってはストックしてあります(セル内の改行文字を削除するとか、いろいろ)。

本ScriptはmacOS 10.14.6+Numbers v6.1で検証してあります。

OS標準装備のScript Menuに入れて呼び出して利用しています。

もともと、Numbersのセル書き換え速度はそれほど速くないので、数百セルとか数千セルを一気に書き換えるような用途は考慮していません。そういう用途には、書き換えたデータをCSV書き出しして、CSVのファイルをNumbersでオープンするといった処理になると思います。

AppleScript名:選択範囲のセルから数字以外の文字を除去する
— Created 2019-08-29 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

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 false
      end try
      
      
tell theTable
        set cellList to cell of selection range
        
set mySelectedRanges to value of cell of selection range
        
set res2 to returnNumbersCharOnlyList(mySelectedRanges) of me
        
        
repeat with i from 1 to (length of cellList)
          ignoring application responses –Async Mode
            tell item i of cellList
              set value to item i of res2
            end tell
          end ignoring
        end repeat
        
      end tell
      
    end tell
  end tell
end tell

on returnNumbersCharOnlyList(aList)
  set nList to {}
  
repeat with i in aList
    set the end of nList to returnNumberCharsOnly(i) of me
  end repeat
  
return nList
end returnNumbersCharOnlyList

on returnNumberCharsOnly(aStr)
  set anNSString to current application’s NSString’s stringWithString:aStr
  
set anNSString to anNSString’s stringByReplacingOccurrencesOfString:"[^0-9]" withString:"" options:(current application’s NSRegularExpressionSearch) range:{0, anNSString’s |length|()}
  
return anNSString as text
end returnNumberCharsOnly

★Click Here to Open This Script 

Posted in list regexp Text | Tagged 10.12savvy 10.13savvy 10.14savvy NSRegularExpressionSearch NSString | Leave a comment

Script Editor, Script Debuggerから選択範囲の情報を取得

Posted on 8月 19, 2019 by Takaaki Naganoya

スクリプトエディタ(Script Editor)およびScript Debuggerの最前面の書類から選択範囲の情報を取得するAppleScriptです。

スクリプトエディタとScript Debuggerで動く共通のツールをAppleScriptで作ってみたら、結果が異なりました。両エディタで同じ範囲を選択してみても、


▲Script Editor上で選択(左)、Script Debugger上で選択(右)

Script Editorでは、character range of selectionを実行すると、{文字開始位置, 文字終了位置}を返してきます。

一方、Script Debuggerでは、character range of selectionを実行すると、{文字開始位置, 選択文字長}を返してきます。

この違いにより、両エディタで異なる結果が得られたのでした。

選択中のテキスト(contents of selection)をそのまま取得して処理するのはよくあるパターンです。選択範囲を数値で取得するケースは(個人的に)あまりありませんでした。

これらのエディタ上で選択中のAppleScriptソースを取得して、そのままコンパイル(構文確認)して変数のみ抽出して変数名の一覧リストが欲しかったのですが、部分的にコンパイル(構文確認)しただけではエラーになる例が多い(ライブラリを呼び出している場合とか)ので、ファイル全体をコンパイル(構文確認)したのちに、エディタ上の選択範囲に該当するデータを抽出するように変更してみました。


▲選択範囲からAppleScript構文色分け情報をもとに変数のみ列挙して返すAppleScriptを実行。このために両エディタ対応を調べていた

AppleScript名:Ecript Editorの選択範囲情報を取得.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/08/19
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
tell application "Script Editor"
  tell front document
    set {cStart, cEnd} to character range of selection –{start pos, end pos}
    
return {cStart, cEnd}
    
–> {516, 1334}
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:Script Debuggerの選択範囲情報を取得
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/08/19
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
tell application "Script Debugger"
  tell front document
    set {cStart, cNums} to character range of selection –{start pos, length}
    
return {cStart, cStart + cNums – 1}
    
–> {516, 1335}
  end tell
end tell

★Click Here to Open This Script 

Posted in list Text | Tagged 10.12savvy 10.13savvy 10.14savvy Script Debugger Script Editor | Leave a comment

指定のAppleScriptテキストを構文確認して指定の構文要素が入っていないかチェック

Posted on 7月 31, 2019 by Takaaki Naganoya

指定のテキストをAppleScriptとみなして構文確認して、指定の構文要素が入っていないかチェックするAppleScriptです。

AppleScriptにeval関数はないので、文字列として与えたAppleScriptをその場で実行する「run script」コマンドをevalがわりに使っています。

文字列をそのままrun scriptするのは(一応いろいろ保護機能はあるものの)、セキュリティ的にリスクの高い操作になってしまいます。


▲こんなのがrun scriptコマンドで実行されてしまったらと思うとゾッとします。ためしに実行してみたら、実行権限がないので実行できないエラーになりました

そこで、文字列をいったんAppleScriptとして評価(構文確認)し、コマンドなどの危険と思われる構文要素が入っていないかどうかチェックする処理を書いて使っています。

これら、「コマンド」および「追加コマンド」といった構文要素が入っていたらtrueを返します。

本Scriptをライブラリ化して組み込むことで、少ない記述量で対象の文字列をそのままrun scriptしてよいかどうか判定できるようにしています。

–> Download checkDanger(with Library in its bundle)


▲実際にテキストをAppleScriptとして評価して構文要素を検出し、このようにコマンド部分(AppleScriptのdo shell scriptコマンド)が入っていることを検知できる

AppleScript名:指定のAppleScriptテキストを構文確認して指定の構文要素が入っていないかチェック.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/31
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use framework "AppKit"
use framework "OSAKit"
use attrLib : script "asAttrRecLib"

property NSArray : a reference to current application’s NSArray
property OSANull : a reference to current application’s OSANull
property NSString : a reference to current application’s NSString
property OSAScript : a reference to current application’s OSAScript
property NSPredicate : a reference to current application’s NSPredicate
property NSDictionary : a reference to current application’s NSDictionary
property NSUnarchiver : a reference to current application’s NSUnarchiver
property OSALanguage : a reference to current application’s OSALanguage
property NSCountedSet : a reference to current application’s NSCountedSet
property NSMutableArray : a reference to current application’s NSMutableArray
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property OSALanguageInstance : a reference to current application’s OSALanguageInstance

script spd
  property fArray : {}
  
property outList : {}
  
property resStr : {}
end script

on run
  set theSource to "do shell script \"rm -f *.*\""
  
set aRes to chkTargLexicalElementsFromCompiledScriptAttribute(theSource, {9, 14}) of me –{Command, External Command}
  
–> true : 指定の構文要素が入っていた
  
  
set theSource to "{{aName:\"piyoko\", aVal:100}, {aName:\"piyomaru\", aVal:80}, {aName:\"piyoo\", aVal:10}, {aName:\"Gundamo\", aVal:10}}"
  
set bRes to chkTargLexicalElementsFromCompiledScriptAttribute(theSource, {9, 14}) of me –{Command, External Command}
  
–> false : 指定の構文要素は入っていなかった
end run

–AppleScriptのソーステキストをコンパイルして、指定の構文要素が含まれているかチェックする
on chkTargLexicalElementsFromCompiledScriptAttribute(theSource as string, targLexicalElements as list)
  
  
–AppleScriptの構文色分け情報を取得
  
set ccRes to getAppleScriptSourceColors() of me
  
set cRes to chkASLexicalFormatColorConfliction(ccRes) of me –構文色分けの重複色チェック
  
if cRes = false then error "There is some duplicate(s) color among AppleScript’s lexical color settings"
  
  
–検索用の色情報を作成
  
set colTargList to {}
  
repeat with i in targLexicalElements
    set commentCol to contents of item i of ccRes –Variable and Sub-routine name
    
set searchVal to (redValue of commentCol as string) & " " & (greenValue of commentCol as string) & " " & (blueValue of commentCol as string) –for filtering
    
set the end of colTargList to searchVal
  end repeat
  
  
  
–与えられたテキストをAppleScriptとして評価し構文色分け情報をもとにStyle Runs的なDictionary化して返す
  
set aRitch to compileASSourcetextAndReturnStyledText(theSource) of me
  
  
  
–書式付きテキストからstyle runs的な書式リストを作成
  
set anAttrList to getAttributeRunsFromAttrString(aRitch) of attrLib
  
  
set bList to filterRecListByLabelAndSublist(anAttrList, "colorStr IN %@", colTargList) of me
  
  
return not (bList as list = {}) as boolean
  
end chkTargLexicalElementsFromCompiledScriptAttribute

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

——-

–AppleScriptの構文色分けのカラー値をRGBで取得する
on getAppleScriptSourceColors()
  — get the plist info as a dictionary
  
set thePath to NSString’s stringWithString:"~/Library/Preferences/com.apple.applescript.plist"
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theInfo to NSDictionary’s dictionaryWithContentsOfFile:thePath
  
  
— extract relevant part and loop through
  
set theArray to (theInfo’s valueForKey:"AppleScriptSourceAttributes") as list
  
  
set colList to {}
  
  
repeat with i from 1 to count of theArray
    set anEntry to item i of theArray
    
    
set colorData to NSColor of anEntry
    
set theColor to (NSUnarchiver’s unarchiveObjectWithData:colorData)
    
    
set {rVal, gVal, bVal} to retColListFromNSColor(theColor, 255) of me
    
    
set fontData to NSFont of anEntry
    
set theFont to (NSUnarchiver’s unarchiveObjectWithData:fontData)
    
    
set aFontName to theFont’s displayName() as text
    
set aFontSize to theFont’s pointSize()
    
    
set aColRec to {redValue:rVal, greenValue:gVal, blueValue:bVal, fontName:aFontName, fontSize:aFontSize}
    
    
set the end of colList to aColRec
  end repeat
  
  
return colList
end getAppleScriptSourceColors

–AppleScriptの構文色分けのカラー値をRGBで取得する
on getAppleScriptSourceNSColorsDict()
  — get the plist info as a dictionary
  
set thePath to NSString’s stringWithString:"~/Library/Preferences/com.apple.applescript.plist"
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theInfo to NSDictionary’s dictionaryWithContentsOfFile:thePath
  
  
— extract relevant part and loop through
  
set theArray to (theInfo’s valueForKey:"AppleScriptSourceAttributes") as list
  
  
set aDict to NSMutableDictionary’s alloc()’s init()
  
  
repeat with i from 1 to count of theArray
    set anEntry to item i of theArray
    
    
set colorData to NSColor of anEntry
    
set theColor to (NSUnarchiver’s unarchiveObjectWithData:colorData)
    
    
set {rVal, gVal, bVal} to retColListFromNSColor(theColor, 255) of me
    
    
set fontData to NSFont of anEntry
    
set theFont to (NSUnarchiver’s unarchiveObjectWithData:fontData)
    
    
set aFontName to theFont’s displayName() as text
    
set aFontSize to theFont’s pointSize()
    
    
set colIndStr to (rVal as string) & " " & (gVal as string) & " " & (bVal as string)
    
set tmpColDat to {numList:{rVal, gVal, bVal}, strInd:colIndStr}
    
–(aDict’s addObject:tmpColDat forKey:theColor)
    (
aDict’s addObject:{rVal, gVal, bVal} forKey:theColor)
  end repeat
  
  
return aDict
end getAppleScriptSourceNSColorsDict

–NSColorからRGBの値を取り出す
on retColListFromNSColor(aCol, aMAX as integer)
  set aSpace to (aCol’s colorSpaceName()) as string
  
–set aSpace to (aCol’s type()) as integer
  
  
if aSpace is in {"NSDeviceRGBColorSpace", "NSCalibratedRGBColorSpace"} then
    copy aCol to cCol
  else
    –RGB以外の色空間の色は、RGBに変換
    
–CMYKとグレースケールは同一メソッドでRGBに変換できることを確認済み
    
set cCol to aCol’s colorUsingColorSpaceName:"NSCalibratedRGBColorSpace"
    
if cCol = missing value then error "Color Space Conversion Error (" & aSpace & " to NSCalibratedRGBColorSpace)"
  end if
  
  
set aRed to round ((cCol’s redComponent()) * aMAX) rounding as taught in school
  
set aGreen to round ((cCol’s greenComponent()) * aMAX) rounding as taught in school
  
set aBlue to round ((cCol’s blueComponent()) * aMAX) rounding as taught in school
  
  
if aRed > aMAX then set aRed to aMAX
  
if aGreen > aMAX then set aGreen to aMAX
  
if aBlue > aMAX then set aBlue to aMAX
  
  
return {aRed, aGreen, aBlue} as list
end retColListFromNSColor

–AS書式で配色に重複がないかどうかチェック
on chkASLexicalFormatColorConfliction(aList)
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set bList to (anArray’s valueForKeyPath:"redValue.stringValue") as list
  
set cList to (anArray’s valueForKeyPath:"greenValue.stringValue") as list
  
set dList to (anArray’s valueForKeyPath:"blueValue.stringValue") as list
  
  
set colStrList to {}
  
repeat with i from 1 to (length of bList)
    set bItem to contents of item i of bList
    
set cItem to contents of item i of cList
    
set dItem to contents of item i of dList
    
set the end of colStrList to bItem & " " & cItem & " " & dItem
  end repeat
  
  
set aRes to returnDuplicatesOnly(colStrList) of me
  
  
if aRes is equal to {} then
    return true –重複が存在しなかった場合
  else
    return false –重複があった場合
  end if
end chkASLexicalFormatColorConfliction

on returnDuplicatesOnly(aList as list)
  set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
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

–テキスト形式のAppleScriptをコンパイルして書式付きテキスト(NSAttributedString)を返す
on compileASSourcetextAndReturnStyledText(theSource)
  — create a new AppleScript instance
  
set anOSALanguageInstance to OSALanguage’s languageForName:"AppleScript"
  
  
set theScript to OSAScript’s alloc()’s initWithSource:theSource fromURL:(missing value) languageInstance:anOSALanguageInstance usingStorageOptions:(OSANull)
  
set {theResult, theError} to theScript’s compileAndReturnError:(reference)
  
  
if theResult as boolean is false then
    — handle error
    
error "Compile Error"
  else
    set styledSourceText to theScript’s richTextSource()
  end if
  
  
return styledSourceText
end compileASSourcetextAndReturnStyledText

–文字置換
on repChar(origText as string, targChar as string, repChar as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

–リストに入れたレコードを、指定の属性ラベルの値で抽出。値が別途指定のリストの中に存在していることが条件
on filterRecListByLabelAndSublist(aRecList as list, aPredicate as string, aSubList as list)
  set aArray to NSArray’s arrayWithArray:aRecList
  
set aSubArray to NSArray’s arrayWithArray:aSubList
  
  
–抽出
  
set aPredicate to NSPredicate’s predicateWithFormat_(aPredicate, aSubArray)
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
  
return filteredArray as list
end filterRecListByLabelAndSublist

★Click Here to Open This Script 

Posted in Color OSA Text | Tagged 10.12savvy 10.13savvy 10.14savvy NSArray NSCountedSet NSDictionary NSMutableArray NSMutableDictionary NSPredicate NSString NSUnarchiver OSALanguage OSALanguageInstance OSANull OSAScript | 2 Comments

アラートダイアログ上にTextViewを表示

Posted on 7月 8, 2019 by Takaaki Naganoya

アラートダイアログ上にTextViewを表示して、指定のテキストを閲覧するAppleScriptです。

とくにこれといって何か表示するものを思いつかなかったので、自分自身のソースコードを取得して表示しています。スクリプトエディタやScript Debugger上で実行した場合には自分自身のソースコードをテキストビュー上で表示します。

読み取り専用のスクリプトやアプレットで実行している場合にはソースコードを取得できません。何か適宜自分で表示させたいテキストを与えてみてください。

AppleScript名:アラートダイアログ上にTexViewを表示
— Created 2019-07-02 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "OSAKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSFont : a reference to current application’s NSFont
property NSView : a reference to current application’s NSView
property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSTextView : a reference to current application’s NSTextView
property NSScrollView : a reference to current application’s NSScrollView
property NSRunningApplication : a reference to current application’s NSRunningApplication
property OSAScript : a reference to current application’s OSAScript

property returnCode : 0

–Get Self Source Code (a kind of joke)
set mePath to path to me
set asStr to getASsourceFor(mePath) of me

set paramObj to {myMessage:"Main Message", mySubMessage:"Sub information", mes1:(asStr), mesWidth:400, mesHeight:200, fontName:"HiraginoSans-W3", fontSize:11.0}

–my dispTextViewWithAlertdialog:paramObj–for debug
my performSelectorOnMainThread:"dispTextViewWithAlertdialog:" withObject:paramObj waitUntilDone:true

on dispTextViewWithAlertdialog:paramObj
  –Receive Parameters
  
set aMainMes to (myMessage of paramObj) as string –Main Message
  
set aSubMes to (mySubMessage of paramObj) as string –Sub Message
  
set mesStr to (mes1 of paramObj) as string –Text Input field 1 Label
  
set aWidth to (mesWidth of paramObj) as integer –TextView width
  
set aHeight to (mesHeight of paramObj) as integer –TextView height
  
set aFontName to (fontName of paramObj) as string –TextView font name
  
set aFontSize to (fontSize of paramObj) as real –TextView font size
  
  
— Create a TextView with Scroll View
  
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
set aView to NSTextView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
aView’s setRichText:true
  
aView’s useAllLigatures:true
  
aView’s setTextColor:(current application’s NSColor’s cyanColor()) –cyanColor
  
aView’s setFont:(current application’s NSFont’s fontWithName:aFontName |size|:aFontSize)
  
set aColor to current application’s NSColor’s colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.5
  
aView’s setBackgroundColor:aColor
  
aView’s setString:mesStr
  
aScroll’s setDocumentView:aView
  
aView’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
— set up alert
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aScroll
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
end dispTextViewWithAlertdialog:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

–指定AppleScriptファイルのソースコードを取得する(実行専用Scriptからは取得できない)
— Original Created 2014-02-23 Shane Stanley
on getASsourceFor(anAlias as {alias, string})
  set aURL to |NSURL|’s fileURLWithPath:(POSIX path of anAlias)
  
set theScript to OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
  
if theScript is equal to missing value then
    error "Compile Error" — handle error
  else
    set sourceText to theScript’s source()
  end if
  
  
return sourceText as string
end getASsourceFor

★Click Here to Open This Script 

Posted in Color file File path Font GUI Text URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSAlert NSColor NSFont NSRunningApplication NSScrollView NSTextView NSURL OSAScript | Leave a comment

Handle diff v2

Posted on 7月 3, 2019 by Takaaki Naganoya

Script Debugger上でオープン中の2つのAppleScript書類のうち、名称が同じハンドラ(サブルーチン)の内容同士を比較して、お互いに合っているかどうかをチェックするAppleScriptです。

アプリケーション書き出しして、Script Debuggerのスクリプトメニューに入れて実行します(AppleScript書類のままだと、Myriad Tables Lib内のフレームワークが呼べないため)。


▲本Scriptはスクリプトエディタの環境設定で行うAppleScriptの構文色分け設定色が「RGBカラー」でないとエラーになります。CMYKとかグレースケールカラーで指定して、そのままRGBに変換されずに保持される(CMYK色はアクセスしているうちにRGBに変換されるが、グレースケールは保持される)ため、色空間の判定を行ってRGB色に変換してから処理する必要があります(自分用メモ)

スクリプトエディタ上で設定する構文色分け設定をもとに、AppleScriptの構文要素を考慮したハンドラ一覧を作成し、2つのAppleScript書類の間に共通して存在するハンドラ名のハンドラ(サブルーチン)のAppleScriptソースを取得。インデント(tab)を削除したのちに比較を実行。

共通名称のハンドラすべてをチェックして、結果を表インタフェースで表示します。初版(v1)では実行するたびに1つのハンドラをチェックしていたのですが、あまりにかったるいので即座にループですべて調べてまとめて結果を表示するようにしました(v2)。

–> download executable archive (mainly for macOS 10.14 or later)

ただし、1つのAppleScript書類内にScript Object(JavaScriptでいうところのClosureみたいなもの)で論理分割された同名のハンドラが複数回登場するパターンは想定していません。複数検出するとエラーになります。

とくにScript Debuggerを対象にせずスクリプトエディタを対象にしてもよいのですが、些細な変更で実現できるため、興味のある方はやってみてください。あと、本Scriptは必要に迫られまくって作ったものなので、動作でおかしい箇所があったらぜひぜひご指摘を。

個人的には、ハンドラ名称を構文要素を考慮しつつ取得している一方で、ハンドラの内容は単なる文字列検索で取り出しているというあたりにアンバランスさを感じます。ただ、趣味のScriptではないので若干の手抜きを(^ー^;;

macOS 10.14.5上のスクリプトエディタで、構文色分け情報を何回設定しても「黒」になるという現象に遭遇したのですが、他のユーザー環境上での再現性については未知数であるため、まだレポートできない状況です。

→ その後、本ツールは強化されて、構文色分け設定にRGB以外の色が設定してあってもRGBに変換して処理する機能や、構文色分け設定を参照したコメント除去機能や、各種書式情報の取得を3倍高速化するカラーキャッシュなどの機能を実装したプログラムに(必要に迫られて)成長しました。

AppleScript名:Handle diff v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/02
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5" — Sierra (10.12) or later (maybe 10.11 is OK but not confirmed)
use framework "Foundation"
use scripting additions
use framework "OSAKit"
use script "Myriad Tables Lib" version "1.0.9" –https://www.macosxautomation.com/applescript/apps/Script_Libs.html

property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property OSAScript : a reference to current application’s OSAScript
property NSPredicate : a reference to current application’s NSPredicate
property NSDictionary : a reference to current application’s NSDictionary
property NSUnarchiver : a reference to current application’s NSUnarchiver
property NSCountedSet : a reference to current application’s NSCountedSet

–構文色分け設定に重複色がないかチェック
set cList to getAppleScriptSourceColors() of me
set cRes to chkASLexicalFormatColorConfliction(cList) of me –構文色分けの重複色チェック
if cRes = false then error "There is some duplicate(s) color among AppleScript’s lexical color settings"

–Script Debugger上でオープン中の2つのAppleScript書類のパスを取得
set dList to retTwoPathList() of me
if dList = false then return

copy dList to {d1Path, d2Path}

–各AppleScript書類のハンドラ名称一覧を取得する
set hList1 to retHandlerNamesFromAppleScriptSource(d1Path as alias) of me
set hList2 to retHandlerNamesFromAppleScriptSource(d2Path as alias) of me

–2つのAppleScript書類のハンドラの共通項目(名称のみ)を抽出する
set resList to returnDuplicatesOnly(hList1 & hList2) of me
if resList = {} then
  –共通のハンドラ(サブルーチン)が指定の2つのScriptに存在していなかった
  
display dialog "There is no common handler between the scripts." buttons {"OK"} default button 1
  
return
end if

–各AppleScript書類のソースを取得して、指定のハンドラのテキストを取得する
set s1Source to getASsourceFor(d1Path as alias) of me
set s2Source to getASsourceFor(d2Path as alias) of me

if (s1Source = false) or (s2Source = false) then
  display dialog "Error occured in getteing AS source" buttons {"OK"} default button 1
  
return
end if

set outList to {}
repeat with i in resList
  set resHandler to contents of i
  
set s1Source to extractHandlerSourceOnly(s1Source, resHandler) of me
  
set s2Source to extractHandlerSourceOnly(s2Source, resHandler) of me
  
set compareF to (s1Source is equal to s2Source) as boolean
  
set the end of outList to {resHandler, compareF}
end repeat

–結果表示
tell me to activate
display table with data outList with prompt "Handler contents compare results" column headings {"Handler name", "Match?"} with title "Handler Diff Results"

–指定のハンドラの内容を抽出する(コメントぐらいは結果から削除してもいいような気もする)
–Script Objectの使用は考慮していない。1つのAppleScript書類からScript Objectで論理分割された同名のハンドラが複数検出されるケースは想定していない
on extractHandlerSourceOnly(wholeScript as string, handlerName as string)
  –インデント文字(Tab)をすべて削除
  
set targScript to repChar(wholeScript, tab, "") of me
  
  
–"on"ではじまるハンドラと仮定して抽出
  
set handlerStr to extractStrFromTo(targScript, "on " & handlerName, "end " & handlerName) of me
  
if handlerStr = false then
    –"to"ではじまるハンドラと仮定して抽出
    
set handlerStr to extractStrFromTo(targScript, "to " & handlerName, "end " & handlerName) of me
    
if handlerStr = false then return false
  else
    return handlerStr
  end if
end extractHandlerSourceOnly

on retHandlerNamesFromAppleScriptSource(aFile)
  set aRec to getAttrRecFromASPath(aFile) of me
  
set cList to getAppleScriptSourceColors() of me
  
  
set targAttr to contents of item 7 of cList –ハンドラあるいは変数
  
set tmpCoStr to ((redValue of targAttr) as string) & " " & ((greenValue of targAttr) as string) & " " & ((blueValue of targAttr) as string)
  
  
set ontoColItem to contents of item 3 of cList –スクリプティング予約語(on/to)
  
set ontoCoStr to ((redValue of ontoColItem) as string) & " " & ((greenValue of ontoColItem) as string) & " " & ((blueValue of ontoColItem) as string)
  
  
  
–変数あるいはハンドラ名称をリストアップ(variables & handler)
  
set tmp1Array to NSArray’s arrayWithArray:aRec
  
set thePred0 to NSPredicate’s predicateWithFormat_("colorStr == %@", tmpCoStr)
  
set dArray to (tmp1Array’s filteredArrayUsingPredicate:thePred0) as list
  
  
–改行を含むデータをリストアップ(text data contains return)
  
set thePred1 to NSPredicate’s predicateWithFormat_("stringVal CONTAINS %@", return)
  
set eArray to ((tmp1Array’s filteredArrayUsingPredicate:thePred1)’s valueForKeyPath:"itemIndex") as list
  
  
set the beginning of eArray to 0 –ハンドラ宣言部がTopに来る場合に備える
  
  
–"on"(ハンドラ宣言)の項目をリストアップ 文字と色で抽出
  
set thePred2 to NSPredicate’s predicateWithFormat_("stringVal == %@ && colorStr == %@ ", "on", ontoCoStr)
  
set fArray to ((tmp1Array’s filteredArrayUsingPredicate:thePred2)’s valueForKeyPath:"itemIndex") as list
  
  
–"to"(ハンドラ宣言ないしは代入対象指定) の項目をリストアップ文字と色で抽出
  
set thePred3 to NSPredicate’s predicateWithFormat_("stringVal == %@ && colorStr == %@ ", "to", ontoCoStr)
  
set gArray to ((tmp1Array’s filteredArrayUsingPredicate:thePred3)’s valueForKeyPath:"itemIndex") as list
  
  
  
set handlerList to {}
  
  
–on ではじまるハンドラの抽出
  
repeat with i in eArray –改行を含むテキストのアイテム番号リスト
    set j to (contents of i) as integer
    
repeat with ii in fArray –"on"の項目リスト
      set jj to (contents of ii) as integer
      
      
set handlerStr to missing value
      
      
if (j + 1) = jj then
        set handlerStr to stringVal of (item (jj + 2) of (aRec as list))
      else if (j + 2) = jj then
        set handlerStr to stringVal of (item (jj + 2) of (aRec as list))
      end if
      
      
if handlerStr is not in {"error", missing value} and handlerStr is not in handlerList then
        set the end of handlerList to handlerStr
      end if
      
    end repeat
  end repeat
  
  
  
–to ではじまるハンドラの抽出
  
repeat with i in eArray –改行を含むテキストのアイテム番号リスト
    set j to (contents of i) as integer
    
repeat with ii in gArray –"to"の項目リスト
      set jj to (contents of ii) as integer
      
      
set handlerStr to missing value
      
      
if (j + 1) = jj then
        set handlerStr to stringVal of (item (jj + 2) of (aRec as list))
      else if (j + 2) = jj then
        set handlerStr to stringVal of (item (jj + 2) of (aRec as list))
      end if
      
      
if handlerStr is not in {"error", missing value} and handlerStr is not in handlerList then
        set the end of handlerList to handlerStr
      end if
      
    end repeat
  end repeat
  
  
return handlerList
end retHandlerNamesFromAppleScriptSource

–ソースを取得してコンパイル(構文確認)する方式から、URL(fileURL)を指定してコンパイル(構文確認)する方式に変更した
on getAttrRecFromASPath(aFile)
  set aURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of aFile)
  
set theScript to OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
  
if theScript is equal to missing value then
    — handle error
    
error "Compile Error"
  else
    –set sourceText to theScript’s source() –No Use
    
set styledSourceText to theScript’s richTextSource()
  end if
  
  
set attrRes to getAttributeRunsFromAttrString(styledSourceText) of me
  
return attrRes
end getAttrRecFromASPath

–指定AppleScriptファイルのソースコードを取得する(実行専用Scriptからは取得できない)
— Original Created 2014-02-23 Shane Stanley
on getASsourceFor(anAlias as {alias, string})
  set aURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of anAlias)
  
set theScript to OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
  
if theScript is equal to missing value then
    — handle error
    
error "Compile Error"
  else
    set sourceText to theScript’s source()
  end if
  
  
return sourceText as string
end getASsourceFor

–Attributed StringをDictionary化
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
  
set itemCount to 1
  
  
repeat until (startIndex = theLength)
    set {theAtts, theRange} to theStyledText’s attributesAtIndex:startIndex longestEffectiveRange:(specifier) inRange:{startIndex, theLength – startIndex}
    
    
–String  
    
set aText to (thePureString’s substringWithRange:theRange) as string
    
    
–Color
    
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} –for comparison
      
set colStrForFind to (aRed as integer as string) & " " & (aGreen as integer as string) & " " & (aBlue as integer as string) –for filtering
    else
      set colList to {0, 0, 0}
      
set colStrForFind to "0 0 0"
    end if
    
    
–Font
    
set aFont to (theAtts’s valueForKeyPath:"NSFont")
    
if aFont is not equal to missing value then
      set aDFontName to aFont’s displayName()
      
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, itemIndex:itemCount}
    
set startIndex to current application’s NSMaxRange(theRange)
    
    
set itemCount to itemCount + 1
  end repeat
  
  
return (styleList of aSpd)
  
end getAttributeRunsFromAttrString

–AppleScriptの構文色分けのカラー値をRGBで取得する
on getAppleScriptSourceColors()
  
  
— get the plist info as a dictionary
  
set thePath to NSString’s stringWithString:"~/Library/Preferences/com.apple.applescript.plist"
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theInfo to NSDictionary’s dictionaryWithContentsOfFile:thePath
  
  
— extract relevant part and loop through
  
set theArray to (theInfo’s valueForKey:"AppleScriptSourceAttributes") as list
  
  
set colList to {}
  
  
repeat with i from 1 to count of theArray
    set anEntry to item i of theArray
    
    
set colorData to NSColor of anEntry
    
set theColor to (NSUnarchiver’s unarchiveObjectWithData:colorData)
    
    
set {rVal, gVal, bVal} to retColListFromNSColor(theColor, 255) of me
    
    
set fontData to NSFont of anEntry
    
set theFont to (NSUnarchiver’s unarchiveObjectWithData:fontData)
    
    
set aFontName to theFont’s displayName() as text
    
set aFontSize to theFont’s pointSize()
    
    
set aColRec to {redValue:rVal, greenValue:gVal, blueValue:bVal, fontName:aFontName, fontSize:aFontSize}
    
    
set the end of colList to aColRec
  end repeat
  
  
return colList
end getAppleScriptSourceColors

–NSColorからRGBの値を取り出す
on retColListFromNSColor(aCol, aMAX as integer)
  set aRed to round ((aCol’s redComponent()) * aMAX) rounding as taught in school
  
set aGreen to round ((aCol’s greenComponent()) * aMAX) rounding as taught in school
  
set aBlue to round ((aCol’s blueComponent()) * aMAX) rounding as taught in school
  
  
if aRed > aMAX then set aRed to aMAX
  
if aGreen > aMAX then set aGreen to aMAX
  
if aBlue > aMAX then set aBlue to aMAX
  
  
return {aRed, aGreen, aBlue}
end retColListFromNSColor

–AS書式で配色に重複がないかどうかチェック
on chkASLexicalFormatColorConfliction(aList)
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set bList to (anArray’s valueForKeyPath:"redValue.stringValue") as list
  
set cList to (anArray’s valueForKeyPath:"greenValue.stringValue") as list
  
set dList to (anArray’s valueForKeyPath:"blueValue.stringValue") as list
  
  
set colStrList to {}
  
repeat with i from 1 to (length of bList)
    set bItem to contents of item i of bList
    
set cItem to contents of item i of cList
    
set dItem to contents of item i of dList
    
set the end of colStrList to bItem & " " & cItem & " " & dItem
  end repeat
  
  
set aRes to returnDuplicatesOnly(colStrList) of me
  
log aRes
  
if aRes is equal to {} then
    return true –重複が存在しなかった場合
  else
    return false –重複があった場合
  end if
end chkASLexicalFormatColorConfliction

on returnDuplicatesOnly(aList as list)
  set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
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

on retTwoPathList()
  tell application "Script Debugger"
    set dList to name of every document
    
set dResList to choose from list dList with prompt "Select two documents" with multiple selections allowed
    
if dResList = false then return false
    
if length of dResList is not equal to 2 then
      display dialog "Please Select two documents to compare handler contents" buttons {"OK"} default button 1 with icon 1 with title "Selection Error"
      
return false
    end if
    
    
set dPathList to {}
    
repeat with i in dResList
      set j to contents of i
      
tell document j
        set tmpPath to (file spec) as string –HFS path string
      end tell
      
      
set the end of dPathList to tmpPath
    end repeat
  end tell
  
  
return dPathList
end retTwoPathList

–Written By Philip Aker
–文字置換ルーチン
on repChar(origText as string, targStr as string, repStr as string)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

–指定文字と終了文字に囲まれた内容を抽出
on extractStrFromTo(aParamStr, fromStr, toStr)
  set theScanner to current application’s NSScanner’s scannerWithString:aParamStr
  
set anArray to current application’s NSMutableArray’s array()
  
  
repeat until (theScanner’s isAtEnd as boolean)
    set {theResult, theKey} to theScanner’s scanUpToString:fromStr intoString:(specifier)
    
theScanner’s scanString:fromStr intoString:(missing value)
    
set {theResult, theValue} to theScanner’s scanUpToString:toStr intoString:(specifier)
    
if theValue is missing value then set theValue to "" –>追加
    
theScanner’s scanString:toStr intoString:(missing value)
    
anArray’s addObject:theValue
  end repeat
  
  
if anArray’s |count|() is not equal to 1 then return false
  
  
return first item of (anArray as list)
end extractStrFromTo

★Click Here to Open This Script 

Posted in Color OSA Record Text | Tagged 10.12savvy 10.13savvy 10.14savvy NSArray NSCountedSet NSDictionary NSPredicate NSString NSUnarchiver OSAScript Script Debugger | Leave a comment

テキストから数値を抽出して度数分布集計 v3

Posted on 6月 29, 2019 by Takaaki Naganoya

CotEditorで編集中の最前面の書類の本文中から指定桁の数値を抽出して登場回数で度数分布の集計を行うAppleScriptです。

初版では、集計対象の数値を桁数で指定するという(使うのに)無茶な仕様になっていたので、この頭の悪い仕様に作った本人もめまいがしていました。

わざわざAppleScriptを使うのは、他のどの環境でも追いつけない高度な処理を行うことに意義があると思っています。

そこで、

 (1)数字部分をあらかじめ抽出して事前に集計(分布および最小値、最大値を計算)
 (2)事前集計結果をグラフ表示
 (3)集計対象の数字の範囲を最小値〜最大値までの間で指定できるように
 (4)パラメータの入力、および事前集計結果の表示を自前で作成したアラートダイアログで表示

といった変更を加えてみました。初版では「数字の桁数」というご無体な指定で数字を抽出していましたが、最初に最大値を計算しておいたことで、最大値の桁数ですべて数値を抽出し、最小値・最大値の間に収まる数値のみを抽出して度数分布を再計算しています(言うほど計算結果が変わってきたりはしないんですけど ^ー^;;)。

このぐらい行えば、安心して見られる感じでしょうか。

追記:
4.11といった文字が「4」と「11」に分離して認識されるようだったので数値として認識するCharacter setに「.」(小数点)および「,」(桁数区切り)を追加してみました。想定していた部分はうまくクリアしたものの、「REV.」の部分の「.」も認識して「0.411」のような数値として認識したようです。

このあたりに課題を残しつつも、全体として見ると当初からノイズとして除去する対象として考えていた箇所でもあったため、そんなもんだろうかと。

アラートダイアログに表示するテスト集計結果の文字が小さかったので、少し大きくしてみました。フォントについては「ヒラギノ角ゴシック W1」(PostScript名は「HiraginoSans-W1」)を指定しています。このあたりは好みに応じて変更してみるとよいでしょう。

巨大なテキスト(青空文庫の小説1作文まるごととか)を対象に処理していないので(画面キャプチャ掲載している程度のサイズ)そういう配慮は行っていません。仕事だと考慮しないでもないですが、必要と思われた処理をとりあえず組んでみた程度なので、そういうものだとお考えください。

–> Download Applet With Libraries (mainly for macOS 10.14 or later)

AppleScript名:テキストから数値を抽出して度数分布集計 v3.1
— Created 2019-06-29 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

property NSView : a reference to current application’s NSView
property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSTextField : a reference to current application’s NSTextField
property NSTextView : a reference to current application’s NSTextView
property NSScrollView : a reference to current application’s NSScrollView
property NSRunningApplication : a reference to current application’s NSRunningApplication

–property theResult : 0
property returnCode : 0
property segRes : missing value

set segRes to missing value

tell application "CotEditor"
  if (count every document) = 0 then return –No Document
  
  
tell front document
    set aText to contents of it
    
set lineTerm to (line ending)
  end tell
  
  
–改行コードの選択(ドキュメントの状態から取得)
  
if lineTerm = LF then
    set aRet to ASCII character 10 –To avoid keyword conflict (string)
  else if lineTerm = CR then
    set aRet to ASCII character 13
  else if lineTerm = CRLF then
    set aRet to (ASCII character 13) & (ASCII character 10)
  else
    set aRet to ASCII character 10
  end if
end tell

–事前にテキストから自動で数値部分を抽出して分析
set cArray to extractNumberFromText(aText) of me
set aRes to (cArray’s valueForKeyPath:"@max.self")’s intValue()
set bRes to (cArray’s valueForKeyPath:"@min.self")’s intValue()
set cRes to (cArray’s valueForKeyPath:"@count")’s intValue()

–事前に数字の分布シミュレーションを計算
set tmpLen to count every character of (aRes as string)
set theList to my findPattern:("[0-9]{" & tmpLen & "}") inString:aText
set sampleStr to calculateNumFreq(cArray, "■", aRet, bRes, aRes, true) of me

set sampleStr to return & return & "テスト集計結果:" & return & return & sampleStr

–テキストからの数値抽出時のパラメータ取得
set paramObj to {myMessage:"テキスト内の数値の度数分布集計", mySubMessage:"集計対象の数値の範囲と、集計時のグラフ生成時の構成文字を指定してください", mes1:"最小値(min.)", mes1Default:(bRes as string), mes2:"最大値(max.)", mes2Default:(aRes as string), mes3:"出力文字", mes3Default:"絆", aSample:sampleStr}

–set segRes to my inputParametersFromAlertDialog:paramObj–for debugging
my performSelectorOnMainThread:"inputParametersFromAlertDialog:" withObject:(paramObj) waitUntilDone:true
if segRes = missing value then return –Cancel

–度数分布計算
set tmpLen to count every character of ((a2Res of segRes) as string)
set theList to my findPattern:("[0-9]{" & tmpLen & "}") inString:aText
set outStr to calculateNumFreq(cArray, a3Res of segRes, aRet, a1Res of segRes, a2Res of segRes, false) of me

–テキストエディタへの集計結果出力
tell application "CotEditor"
  tell front document
    set contents of it to (aText & aRet & aRet & "集計結果:" & aRet & aRet & outStr & aRet)
  end tell
end tell

on inputParametersFromAlertDialog:paramObj
  –Receive Parameters
  
set aMainMes to (myMessage of paramObj) as string –Main Message
  
set aSubMes to (mySubMessage of paramObj) as string –Sub Message
  
set mes1Label to (mes1 of paramObj) as string –Text Input field 1 Label
  
set mes2Label to (mes2 of paramObj) as string –Text Input field 2 Label
  
set mes3Label to (mes3 of paramObj) as string –Text Input field 3 Label
  
set aTextInputString to (mes1Default of paramObj) as string –Text Input field 1 Default value
  
set bTextInputString to (mes2Default of paramObj) as string –Text Input field 2 Default value
  
set cTextInputString to (mes3Default of paramObj) as string –Text Input field 2 Default value
  
set sampleString to (aSample of paramObj) as string
  
  
— Create a view
  
set theView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 500, 400))
  
  
— create two input field and their labels pairs
  
–NSTextFields for Input
  
set aTextInput to makeNSTextField(100, 70, 140, 20, true, (aTextInputString), true, true) of me
  
set bTextInput to makeNSTextField(100, 35, 140, 20, true, (bTextInputString), true, true) of me
  
set cTextInput to makeNSTextField(100, 0, 140, 20, true, (cTextInputString), true, true) of me
  
  
–Labels
  
set a1TF to makeNSTextField(0, 70, 100, 20, false, (mes1Label), false, false) of me
  
set a2TF to makeNSTextField(0, 35, 100, 20, false, (mes2Label), false, false) of me
  
set a3TF to makeNSTextField(0, 0, 100, 20, false, (mes3Label), false, false) of me
  
  
–Sample Text View
  
set aColor to NSColor’s colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.9
  
set tvScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 120, 500, 300))
  
set tvView to NSTextView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 120, 500, 380))
  
tvView’s setRichText:true
  
tvView’s useAllLigatures:true
  
tvView’s setTextColor:(NSColor’s cyanColor()) —
  
tvView’s setFont:(current application’s NSFont’s fontWithName:"HiraginoSans-W1" |size|:16.0)
  
tvView’s setBackgroundColor:aColor
  
tvView’s setEditable:false
  
  
tvScroll’s setDocumentView:tvView
  
tvView’s enclosingScrollView()’s setHasVerticalScroller:true
  
tvView’s setString:(sampleString)
  
  
  
theView’s setSubviews:{a1TF, aTextInput, a2TF, bTextInput, a3TF, cTextInput, tvScroll}
  
  
— set up alert
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:theView
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then
    set my segRes to missing value
  else
    set s1Val to (aTextInput’s integerValue()) as integer
    
set s2Val to (bTextInput’s integerValue()) as integer
    
set s3Val to (cTextInput’s stringValue()) as string
    
    
–return {a1Res:s1Val, a2Res:s2Val, a3Res:s3Val}–old version’s way to return values
    
set my segRes to {a1Res:s1Val, a2Res:s2Val, a3Res:s3Val}
  end if
end inputParametersFromAlertDialog:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

on makeNSTextField(xPos as integer, yPos as integer, myWidth as integer, myHeight as integer, editableF as boolean, setVal as string, backgroundF as boolean, borderedF as boolean)
  set aNSString to NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(xPos, yPos, myWidth, myHeight))
  
aNSString’s setEditable:(editableF)
  
aNSString’s setStringValue:(setVal)
  
aNSString’s setDrawsBackground:(backgroundF)
  
aNSString’s setBordered:(borderedF)
  
return aNSString
end makeNSTextField

–与えられたテキストから数値部分を抽出して1D Arrayで返す
on extractNumberFromText(aText)
  set aStr to current application’s NSString’s stringWithString:aText
  
–set nonDigitCharacterSet to (current application’s NSCharacterSet’s decimalDigitCharacterSet())’s invertedSet()
  
set nonDigitCharacterSet to (current application’s NSCharacterSet’s characterSetWithCharactersInString:"0123456789.,")’s invertedSet()
  
set bArray to (aStr’s componentsSeparatedByCharactersInSet:nonDigitCharacterSet)
  
  
–Sweep Blank Items
  
load framework –BridgePlus
  
set cArray to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bArray))’s valueForKey:"intValue"
  
return cArray –return as NSArray
end extractNumberFromText

–正規表現でテキスト中から指定パターンに該当する箇所を抽出してリストで返す
on findPattern:thePattern inString:theString
  set theOptions to ((current application’s NSRegularExpressionDotMatchesLineSeparators) as integer) + ((current application’s NSRegularExpressionAnchorsMatchLines) as integer)
  
set theRegEx to current application’s NSRegularExpression’s regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value)
  
set theFinds to theRegEx’s matchesInString:theString options:0 range:{location:0, |length|:length of theString}
  
set theFinds to theFinds as list — so we can loop through
  
set theResult to {} — we will add to this
  
set theNSString to current application’s NSString’s stringWithString:theString
  
repeat with i from 1 to count of items of theFinds
    set theRange to (item i of theFinds)’s range()
    
set end of theResult to (theNSString’s substringWithRange:theRange) as integer
  end repeat
  
return theResult
end findPattern:inString:

–1D Listをユニーク化してソート
on uniquifyAndSort1DList(theList as list, aBool as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:theList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
set aDdesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:"self" ascending:aBool selector:"compare:"
  
set cArray to bArray’s sortedArrayUsingDescriptors:{aDdesc}
  
  
set bList to cArray as list
  
return bList
end uniquifyAndSort1DList

–度数分布集計して文字グラフ出力
on calculateNumFreq(theList, outChar, aLineTerminator, aMin, aMax, zeroPaddingF)
  set theCountedSet to current application’s NSCountedSet’s alloc()’s initWithArray:theList
  
set newArray to current application’s NSMutableArray’s new()
  
  
set kList to uniquifyAndSort1DList(theList, false) of me –降順ソート
  
set maxDigit to (count every character of (aMax as string))
  
  
repeat with i in kList
    if (i ≥ aMin) and (i ≤ aMax) then
      (newArray’s addObject:{theKey:i, theCount:(theCountedSet’s countForObject:i)})
    end if
  end repeat
  
  
set outStr to ""
  
  
repeat with i in newArray as list
    set j to (current application’s NSDictionary’s dictionaryWithDictionary:i)
    
set tmpStr to (j’s valueForKey:"theKey")
    
    
if zeroPaddingF = true then
      –Zero Pagging
      
set keyNumStr to numToZeroPaddingStr(tmpStr, maxDigit, "0") of me
    else
      –No Padding
      
copy (tmpStr as string) to keyNumStr
    end if
    
    
set outStr to outStr & keyNumStr & ":"
    
    
set aNum to (j’s valueForKey:"theCount")
    
repeat aNum times
      set outStr to outStr & outChar
    end repeat
    
    
set outStr to outStr & aLineTerminator
  end repeat
end calculateNumFreq

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

★Click Here to Open This Script 

Posted in list regexp Sort Text | Tagged 10.12savvy 10.13savvy 10.14savvy CotEditor NSAlert NSColor NSRunningApplication NSScrollView NSTextField NSTextView NSView | 1 Comment

テキストから指定桁数の数値を抽出して度数分布集計

Posted on 6月 28, 2019 by Takaaki Naganoya

CotEditorで編集中の最前面の書類の本文中から指定桁の数値を抽出して登場回数で度数分布の集計を行うAppleScriptです。

CotEditorのアプリケーション内のスクリプトメニューに入れて実行できることを確認してあります(@macOS 10.14.5)。

たまたま、テキストで集計していた情報のうち、数値部分の度数分布を計算したいと考え、ありもののルーチンを組み合わせて作ったものです。

実行すると、集計対象の数値の桁数を聞いてくるため、適当なものを選択してださい。

CotEditorのScriptingの要注意点で、オブジェクト階層を素直に書いて、当該階層のオブジェクトの属性値を取りたいような場合に、そのまま属性を書いても取得できないケースが見られます。そのため、明示的にオブジェクト階層を指定するために「of it」を書いています。Xcodeが同じような挙動を行うため、注意が必要です。

本Scriptについていえば、正規表現でテキストから情報を抽出したりと、一応最低限のレベルはクリアしているものの、いまひとつ満足できません。

数字が連続して登場している箇所を抽出し、どれを集計対象にするのかといった分析を冒頭で行ってユーザーに問い合わせしたいところです。現段階では、「桁数を聞く」という頭の悪い実装になっていますが、そのうちどうにかしたいと考えるところです。

AppleScript名:テキストから指定桁数の数値を抽出して度数分布集計.scptd
— Created 2019-06-28 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property graphStr : "絆" –グラフに出力する文字

tell application "CotEditor"
  –最前面の書類からテキスト本文を取得
  
tell front document
    set aText to contents of it –本文
    
set lineTerm to (line ending) –改行コード
  end tell
  
  
–改行コードの選択(ドキュメントの状態から取得)
  
if lineTerm = LF then
    set aRet to ASCII character 10 –To avoid keyword conflict (string)
  else if lineTerm = CR then
    set aRet to ASCII character 13
  else if lineTerm = CRLF then
    set aRet to (ASCII character 13) & (ASCII character 10)
  else
    set aRet to ASCII character 10
  end if
end tell

–桁数選択
set digiList to {"2", "3", "4", "5"}
set digitRes to first item of (choose from list digiList with prompt "Choose the digit to extract as numbers")

–正規表現で数字部分のみ抽出
set theList to my findPattern:("[0-9]{" & digitRes & "}") inString:aText

–検出した数字部分の度数分布を計算
set theCountedSet to current application’s NSCountedSet’s alloc()’s initWithArray:theList
set newArray to current application’s NSMutableArray’s new()
set kList to uniquifyAndSort1DList(theList, false) of me –降順ソート

repeat with i in kList
  (newArray’s addObject:{theKey:i, theCount:(theCountedSet’s countForObject:i)})
end repeat

–出力用のテキストを作成
set outStr to ""
repeat with i in newArray as list
  set outStr to (outStr & (theKey of i) as string) & ":"
  
set aNum to (theCount of i) as integer
  
  
repeat aNum times
    set outStr to outStr & graphStr
  end repeat
  
  
set outStr to outStr & aRet
end repeat

–最前面のテキスト末尾に集計結果を出力
tell application "CotEditor"
  tell front document
    set contents of it to (aText & aRet & aRet & "集計結果:" & aRet & aRet & outStr & aRet)
  end tell
end tell

–正規表現でテキスト中から指定パターンに該当する箇所を抽出してリストで返す
on findPattern:thePattern inString:theString
  set theOptions to ((current application’s NSRegularExpressionDotMatchesLineSeparators) as integer) + ((current application’s NSRegularExpressionAnchorsMatchLines) as integer)
  
set theRegEx to current application’s NSRegularExpression’s regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value)
  
set theFinds to theRegEx’s matchesInString:theString options:0 range:{location:0, |length|:length of theString}
  
set theFinds to theFinds as list — so we can loop through
  
set theResult to {} — we will add to this
  
set theNSString to current application’s NSString’s stringWithString:theString
  
repeat with i from 1 to count of items of theFinds
    set theRange to (item i of theFinds)’s range()
    
set end of theResult to (theNSString’s substringWithRange:theRange) as integer
  end repeat
  
return theResult
end findPattern:inString:

–1D Listをユニーク化してソート
on uniquifyAndSort1DList(theList as list, aBool as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:theList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
set aDdesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:"self" ascending:aBool selector:"compare:"
  
set cArray to bArray’s sortedArrayUsingDescriptors:{aDdesc}
  
  
set bList to cArray as list
  
return bList
end uniquifyAndSort1DList

★Click Here to Open This Script 

Posted in list Record regexp Sort Text | Tagged 10.12savvy 10.13savvy 10.14savvy CotEditor NSArray NSCountedSet NSMutableArray NSRegularExpression NSRegularExpressionDotMatchesLineSeparators NSSortDescriptor NSString | Leave a comment

アラートダイアログ上にTextField x 2を表示 v2

Posted on 5月 2, 2019 by Takaaki Naganoya

アラートダイアログに簡易UIを実装して便利なダイアログ部品を整備する計画の一環として作成した、アラートダイアログにNSTextFieldを2つ+ラベル用のfield2つを作成して、ユーザーからの数値入力を取得するAppleScriptです。

スクリプトエディタ、ScriptDebuggerの両方で実行できますが、Script Menuから実行するとダイアログが最前面に表示されません。Script Menuから実行する場合にはAppleScript書類の状態で呼び出すのではなく、AppleScriptアプレットに書き出して呼び出すのがよいでしょう。

macOS 10.14上では本Scriptの実行は明確にメインスレッド上で行うことを要求されます。Control-Comand-Rで実行してください。

AppleScript名:アラートダイアログ上にTextField x 2を表示 v2
— Created 2019-05-02 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSView : a reference to current application’s NSView
property NSAlert : a reference to current application’s NSAlert
property NSTextField : a reference to current application’s NSTextField
property NSRunningApplication : a reference to current application’s NSRunningApplication

property theResult : 0
property returnCode : 0

set paramObj to {myMessage:"Keynoteオブジェクトの2次元詰め込み", mySubMessage:"詰め込み先の矩形サイズを数値で入力してください", mes1:"幅", mes1Default:"900", mes2:"高さ", mes2Default:"500"}

set segRes to my simulateAndRetRect:paramObj
–> {a1Res:900, a2Res:500}

on simulateAndRetRect:paramObj
  –Receive Parameters
  
set aMainMes to (myMessage of paramObj) as string –Main Message
  
set aSubMes to (mySubMessage of paramObj) as string –Sub Message
  
set mes1Label to (mes1 of paramObj) as string –Text Input field 1 Label
  
set mes2Label to (mes2 of paramObj) as string –Text Input field 2 Label
  
set aTextInputString to (mes1Default of paramObj) as string –Text Input field 1 Default value
  
set bTextInputString to (mes2Default of paramObj) as string –Text Input field 2 Default value
  
  
— Create a view
  
set theView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 300, 60))
  
  
— create two input field and their labels pairs
  
–NSTextFields for Input
  
set aTextInput to makeNSTextField(100, 35, 140, 20, true, (aTextInputString), true, true) of me
  
set bTextInput to makeNSTextField(100, 0, 140, 20, true, (bTextInputString), true, true) of me
  
  
–Labels
  
set a1TF to makeNSTextField(0, 35, 100, 20, false, (mes1Label), false, false) of me
  
set a2TF to makeNSTextField(0, 0, 100, 20, false, (mes2Label), false, false) of me
  
  
theView’s setSubviews:{a1TF, aTextInput, a2TF, bTextInput}
  
  
— set up alert
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:theView
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
  
  
set s1Val to (aTextInput’s integerValue()) as integer
  
set s2Val to (bTextInput’s integerValue()) as integer
  
  
return {a1Res:s1Val, a2Res:s2Val}
end simulateAndRetRect:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

on makeNSTextField(xPos as integer, yPos as integer, myWidth as integer, myHeight as integer, editableF as boolean, setVal as string, backgroundF as boolean, borderedF as boolean)
  set aNSString to NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(xPos, yPos, myWidth, myHeight))
  
aNSString’s setEditable:(editableF)
  
aNSString’s setStringValue:(setVal)
  
aNSString’s setDrawsBackground:(backgroundF)
  
aNSString’s setBordered:(borderedF)
  
return aNSString
end makeNSTextField

★Click Here to Open This Script 

Posted in GUI Text | Tagged 10.11savvy 10.12savvy 10.13savvy NSAlert NSRunningApplication NSTextField NSView | Leave a comment

Google Sheets URLから正規表現でIDを抽出 v2

Posted on 4月 18, 2019 by Takaaki Naganoya

文字列で与えられたGoogle SpreadSheetsのURLから正規表現の機能を用いてSheets IDを抽出するAppleScriptです。

初回掲載時の内容にShane Stanleyから「長さが0の文字列」(zero length string)に対応できていないので、変更したほうがいいよ、という助言をもらったので書き換えました(Thanks Shane!)。

AppleScript名:Google Sheets URLから正規表現でIDを抽出 v2
— Created 2019-04-18 by Takaaki Naganoya
— Modified 2019-04-19 by Shane Stanley
use AppleScript version "2.5" –macOS 10.11 or later
use scripting additions
use framework "Foundation"

property NSString : a reference to current application’s NSString
property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch

–https://developers.google.com/sheets/guides/concepts?hl=ja
set aURLText to "https://docs.google.com/spreadsheets/d/1qpyC0XzvTcKT6EISywvqESX3A0MwQoFDE8p-Bll4hps/edit#gid=0
"

set sheetsID to (stripGoogleSheetsIDFromURL(aURLText) of me) as string
–> "1qpyC0XzvTcKT6EISywvqESX3A0MwQoFDE8p-Bll4hps"

set aURLText to "" –Zero Length String
set sheetsID to (stripGoogleSheetsIDFromURL(aURLText) of me) as string
–> ""

on stripGoogleSheetsIDFromURL(aText as string)
  set sStrHead to "/spreadsheets/d/"
  
set regStr to sStrHead & "([a-zA-Z0-9-_]+)"
  
  
set anNSString to NSString’s stringWithString:aText
  
set aRange to anNSString’s rangeOfString:regStr options:(NSRegularExpressionSearch)
  
  
–if aRange = {location:0, length:0} then return ""–v1
  
if |length| of aRange = 0 then return "" –Prepare for zero length strings(Thanks Shane!)
  
  
set bStr to anNSString’s substringWithRange:aRange
  
set theString to bStr’s stringByReplacingOccurrencesOfString:sStrHead withString:"" options:(NSRegularExpressionSearch) range:{location:0, |length|:length of sStrHead}
  
  
return theString as string
end stripGoogleSheetsIDFromURL

★Click Here to Open This Script 

Posted in regexp Text URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSRegularExpressionSearch NSString | 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を採用
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • 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ってなんだろう?
  • macOS 14で変更になったOSバージョン取得APIの返り値

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 (129) 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 (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年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