Archive for 1月, 2018

2018/01/23 文字数の原稿用紙換算枚数シミュレーション

文字数から原稿用紙(20×20 chars)換算枚数シミュレーションを行うAppleScriptです。

page1-320px-squared_manuscript_paperpdf.jpg
▲日本国内で(主に小中学校で)使われている「原稿用紙」20×20 characters

文字数の原稿用紙換算枚数のシミュレーションは、「歴史的な文学作品を、下世話な原稿用紙枚数でカウントする」という冗談の産物でしたが、当初からあからさまに「最大で1枚ぐらいの誤差が出る」ことがわかっていたので「○枚」という出力を行なっていました。

文字数だけで原稿用紙枚数の単純計算を行なっても、ほとんど意味がありません。途中で改行が入れば行数=原稿用紙枚数は変わりますし、1行あたりの文字数についても禁則文字(。、「」など)が入ればブラ下がり処理が必要になってくるので、概算ベースの原稿用紙枚数シミュレーションにはほとんど意味がありません(気分の問題)。

大学の先生がどういう課題の出し方をするのかはわかりませんが、だいたいは大学のレポートぐらいでしか「原稿用紙XX枚以上」といった表現は使わないものと思われます。つまり、真剣に何かそういうプログラムを作るほどのモチベーションが発生しないという内容でもあります。

とりあえず、長大な文章でも原稿用紙枚数をカウントするのにアホのようにメモリーを喰われずに原稿用紙枚数シミュレーションを行う方法を見つけたので試してみました。配列上で組版シミュレーションを行うのではなく、単に行数と文字位置だけをカウントアップしていくというものです。

実際に禁則処理を含めた枚数シミュレーションも行なってみました、Blogに掲載するようなものではありませんけれども。

AppleScript名:文字数の原稿用紙枚数換算(ほとんど意味なし)
– Created 2018-1-13 by Takaaki Naganoya
– 2018 Piyomaru Software
–http://piyocast.com/as/archives/5120

set gRes to countGenkoYoushiMaisuu(399, 400) of me
–> 1

set gRes to countGenkoYoushiMaisuu(4878, 400) of me
–> 13

on countGenkoYoushiMaisuu(totalCount, youshiChars)
  if (totalCount mod youshiChars) > 0 then
    set totalPlus to 1
  else
    set totalPlus to 0
  end if
  
set sheetNum to ((totalCount) div youshiChars) + totalPlus
  
return sheetNum
end countGenkoYoushiMaisuu

★Click Here to Open This Script 

AppleScript名:原稿用紙枚数シミュレーション(簡易版)v1
– Created 2018-1-13 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/5120

set aText to retTestText() of me

set sRes to genkoSimulation(20, 20, aText) of me
display notification “原稿用紙換算で約” & (sRes as string) & “枚です”

–原稿用紙枚数シミュレーション(簡易版)
on genkoSimulation(lineMax as integer, genkoLineMax as integer, aText as string)
  script spdT
    property aList : {}
  end script
  
  
if aText = “” then return 0
  
  
set (aList of spdT) to characters of aText
  
set charPointer to 1
  
set lineCounter to 1
  
set aLen to length of (aList of spdT)
  
  
set i to 1
  
  
repeat while i < aLen
    set j to contents of item i of (aList of spdT)
    
    
    
if j is in {string id 10, string id 13, string id 10 & string id 13} then
      set charPointer to 1
      
set lineCounter to lineCounter + 1
    else
      
      
set charPointer to charPointer + 1
      
      
if charPointer lineMax then
        set charPointer to 1
        
set lineCounter to lineCounter + 1
      end if
    end if
    
    
set i to i + 1
  end repeat
  
  
set totalPage to lineCounter div genkoLineMax
  
set amariPage to lineCounter mod genkoLineMax
  
if amariPage = 0 then
    
  else
    set totalPage to totalPage + 1
  end if
  
  
return totalPage
end genkoSimulation

on retTestText()
  return “12345
あいうえお
かきくけこ
さしすせそ
たちつてと
なにぬねの
はひふへほ
まみむめも
やいゆえよ
わいうえを
あいうえお
かきくけこ
さしすせそ
たちつてと
なにぬねの
はひふへほ
まみむめも
やいゆえよ
わいうえを
1234567890123456789ぉー”

end retTestText

★Click Here to Open This Script 

2018/01/21 NSRangeの拡張、隣接検出のじっけん

NSRange( {location:xxx, |length|:yyy})の拡張および隣接検出を行うAppleScriptです。

1次元座標範囲データを扱うNSRangeで、「隣接」という状況を検出できなくて残念なかぎりですが、NSIntersectionRangeで「重なり合い」については検出できます。

そこで、「左右に座標値を+1だけ拡張」したNSRangeを同時に保持しておき、NSIntersectionRangeで重なり合いが検出できたら「隣接している」とみなすことができます。

ただ、範囲の隣接状態を検出したいだけだったので、何かもう少し「とても簡単な方法」で解決できそうな気もしないではありません。また、隣接検出を「Arrayに放り込んでおいた無造作なデータ群」から行なってくれるぐらいでないと、とても脳筋なループ処理をさせられるので残念です。

AppleScript名:NSRangeの拡張、隣接検出
– Created 2018-1-12 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/5118

set aRange to current application’s NSMakeRange(10, 80) –original range
–> {location:10, |length|:80}

set bRange to extendRange(aRange) of me –Extended range
–> {location:9, |length|:81}

set cRange to current application’s NSMakeRange(90, 30) –compare target range
–> {location:90, |length|:30}

set aRes to current application’s NSIntersectionRange(aRange, cRange)
–> {location:0, |length|:0}–Not adjacent

set bRes to current application’s NSIntersectionRange(bRange, cRange)
–> {location:90, |length|:1}–Adjacent

–NSRangeの開始点とサイズを拡張
on extendRange(aRange)
  set aLoc to location of aRange
  
set aLen to |length| of aRange
  
  
if aLoc > 0 then
    set aLoc to aLoc - 1
  end if
  
  
set aLen to aLen + 2
  
set bRange to current application’s NSMakeRange(aLoc, aLen)
  
return bRange
end extendRange

★Click Here to Open This Script 

2018/01/19 なろう系ルビタグを置換

「小説家になろう」サイトからダウンロードしたテキストファイルに入っている、ルビのタグを置換するAppleScriptです。

音声読み上げを行うために、ルビタグの内容を残してルビをつけている対象のキーワードを削除してみました。また、テキストから言語の推定を行うのに、ルビタグのような特殊なタグが入っていると(日本語とわかっていながらも)、正しく言語を推定できないという問題もありました。

この手の処理ではNSScannerが重宝しますが、「タグのあった場所から前方にさかのぼって、文字種類が変わったところまでを削除」、という処理はさすがに地道にループで処理しないとダメそうだったので、そのようにしています。

「テキスト全文に対して形態素解析を行なって、各単語のRangeを取得し、ルビタグとRangeが隣接しているものを処理対象にする」

といった処理も考えてみましたが、隣接Rangeの検出のメソッドが見当たらなかったのと(オーバーラップしている場合は検出できるんですが)、処理内容がほとんどいまのプログラムと変わらないので、お蔵入りに。

現在のプログラムで、21,546文字の日本語のテキストを置換して自分のマシン(MacBook Pro Retina 2012)で0.27秒でした。

実際に使ってみて、TTS(テキスト音声読み上げ)サービスで読ませてみましたが、漢字の読み方を作品ごとによみがなに展開しないとしっくりこない(例:「西方諸国」→TTSだと「さいほうしょこく」。実際には「せいほうしょこく」)ので、そのあたりも置換しないといけないようです。

AppleScript名:なろう系ルビタグを置換
– Created 2018-01-14 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/5117

property NSString : a reference to current application’s NSString
property NSScanner : a reference to current application’s NSScanner
property NSMutableArray : a reference to current application’s NSMutableArray
property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch
property NSNumberFormatterRoundUp : a reference to current application’s NSNumberFormatterRoundUp

set aStr to “ 数多国ある西方諸国だが、元を辿ればとある一つの国へとつながっていた。それは幻晶騎士(シルエットナイト)の力により西方の地に覇をとなえた人類が作り上げた超巨大国家、その名を“ファダーアバーデン”という。
 西方暦一二八九年の現在において西方諸国を構成する主要国家、“ジャロウデク王国”、“クシェペルカ王国”、“ロカール諸国連合”、“|孤独なる十一《イレブンフラッグス》”などの国々は、全てかの巨大国家が分裂してできた残滓なのである。”

–set aStr to getEditorText()

–”|○o○o○《XXXXX》” –> “XXXXX”
set bRes to trimStrHeaderFromTo(aStr, “|”, “《”, “》”) of me

–”aaaaa○○○(XXXXX)” –> “XXXXX”
set cStr to trimStrHeaderFromToForward(bRes, “(”, “)”) of me

(*
“ 数多国ある西方諸国だが、元を辿ればとある一つの国へとつながっていた。それはシルエットナイトの力により西方の地に覇をとなえた人類が作り上げた超巨大国家、その名を“ファダーアバーデン”という。
 西方暦一二八九年の現在において西方諸国を構成する主要国家、“ジャロウデク王国”、“クシェペルカ王国”、“ロカール諸国連合”、“イレブンフラッグス”などの国々は、全てかの巨大国家が分裂してできた残滓なのである。”
*)

–”|○o○o○《XXXXX》” –> “XXXXX”
on trimStrHeaderFromTo(aParamStr, headerStr, fromStr, toStr)
  set theScanner to NSScanner’s scannerWithString:aParamStr
  
set anArray to NSMutableArray’s array()
  
  
repeat until (theScanner’s isAtEnd as boolean)
    set {theResult, theKey} to theScanner’s scanUpToString:headerStr intoString:(reference)
    
    
theScanner’s scanString:fromStr intoString:(missing value)
    
set {theResult, theValue} to theScanner’s scanUpToString:fromStr intoString:(reference)
    
if theValue is missing value then set theValue to “”
    
    
theScanner’s scanString:fromStr 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, i & fromStr, “”) of me
  end repeat
  
  
set curStr to repChar(curStr, toStr, “”) of me
  
  
return curStr
end trimStrHeaderFromTo

–”aaaaa○○○(XXXXX)” –> “XXXXX”
on trimStrHeaderFromToForward(aParamStr, fromStr, toStr)
  set theScanner to NSScanner’s scannerWithString:aParamStr
  
set anArray to NSMutableArray’s array()
  
  
repeat until (theScanner’s isAtEnd as boolean)
    set {theResult, theKey} to theScanner’s scanUpToString:fromStr intoString:(reference)
    
set curLoc to (theScanner’s scanLocation()) + 1
    
    
–scan back to different kind of character
    
set prevKind to detectCharKindMain(text (curLoc - 1) of aParamStr) of me
    
    
repeat with i from curLoc - 2 to 1 by -1
      set aStr to text i of aParamStr
      
set curKind to detectCharKindMain(aStr) of me
      
      
if prevKind is not equal to curKind then
        exit repeat
      end if
    end repeat
    
    
try
      set tmpStr to text (i + 1) thru curLoc of aParamStr
      
theScanner’s scanString:fromStr intoString:(missing value)
      
set {theResult, theValue} to theScanner’s scanUpToString:fromStr intoString:(reference)
      
if theValue is missing value then set theValue to “”
      
      
theScanner’s scanString:fromStr intoString:(missing value)
      
      
anArray’s addObject:tmpStr
    end try
    
  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, i, “”) of me
  end repeat
  
  
set curStr to repChar(curStr, toStr, “”) of me
  
  
return curStr
end trimStrHeaderFromToForward

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

–文字種別判定
on detectCharKindMain(aStr)
  set s1Res to chkKanji(aStr) of me
  
set s2Res to chkKatakana(aStr) of me
  
set s3Res to chkHiragana(aStr) of me
  
set s4Res to chkLineFeed(aStr) of me
  
set s5Res to chkSpecialSign(aStr) of me
  
set s6Res to chkAlphaNumeric(aStr)
  
  
if s1Res = true then
    set curKind to “Kanji”
  else if s2Res = true then
    set curKind to “Katakana”
  else if s3Res = true then
    set curKind to “Hiragana”
  else if s4Res = true then
    set curKind to “Line Feed”
  else if s5Res = true then
    set curKind to “Sign”
  else if s6Res = true then
    set curKind to “Alpha Numeric”
  end if
  
  
return curKind
end detectCharKindMain

on chkKanji(aChar)
  return detectCharKind(aChar, “[一-龠]”) of me
end chkKanji

on chkHiragana(aChar)
  return detectCharKind(aChar, “[ぁ-ん]”) of me
end chkHiragana

on chkKatakana(aChar)
  return detectCharKind(aChar, “[ァ-ヶ]”) of me
end chkKatakana

on chkLineFeed(aChar)
  return aChar is in {string id 10, string id 13, string id 13 & string id 10}
end chkLineFeed

on chkSpecialSign(aChar)
  return aChar is in {“「”, “」”, “『”, “』”, “ー”, “―”, “〜”, “〜”, “!”, “?”, “&”, “/”, “《”, “》”, “#”, “…”, “・”, “♪”, “。”, “、”, “.”, “々”, ““”, “””, “*”, “(”, “)”, “(”, “)”, ” “, “ ”, “§”, “【”, “】”, “■”, “%”, “≒”}
end chkSpecialSign

on chkAlphaNumeric(aChar)
  return detectCharKind(aChar, “[a-zA-Z0-9a-zA-Z0-9]”) of me –半角全角英数字
end chkAlphaNumeric

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

on getEditorText()
  tell application “CotEditor”
    if (count every document) = 0 then return false
    
tell front document
      return contents
    end tell
  end tell
end getEditorText

★Click Here to Open This Script 

2018/01/18 Numbersでセルのカラム幅を自動調整 v2

Numbersでオープン中の書類の表示中のシート内にある複数の表のカラム幅を自動調整するAppleScriptです。

numb1_resized.png
▲実行前

numb2_resized.png
▲実行後

カラム幅の自動調整を行う対象は、1つの表だけでも、複数の表が存在していても大丈夫ですが、カラム数は同じ必要があります。

一番上に存在する表1の幅を基準に、一番左のカラムは固定のままで、残りのカラムの幅を均等幅に調整します。

複数の表が存在している場合には、すべて表1のとおりにカラム幅を調整します。

AppleScript名:Numbersでセルのカラム幅を自動調整 v2
– Created 2018-1-11 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/5116

tell application "Numbers"
  tell front document
    tell sheet 1
      set tCount to count every table
      
if tCount = 0 then return
      
      
tell table 1
        set tableWidth to width
        
        
set cCount to count every column
        
set cWidth to width of every column
        
set aWidth to width –table width
        
        
set aveWidth to (aWidth - (first item of cWidth)) / (cCount - 1)
        
        
tell columns 2 thru cCount
          set width to aveWidth
        end tell
        
        
set wList to width of every column
      end tell
      
      
if tCount = 1 then return
      
      
set origCols to count every column of table 1
      
repeat with i from 2 to tCount
        if origCols is not equal to (count every column of table i) then
          display notification "Numbers: Column number is different in Table #" & (i as string)
          
return
        end if
      end repeat
      
      
repeat with i from 2 to tCount
        
        
tell table i
          set width to tableWidth
        end tell
        
        
set aCount to 1
        
        
tell table i
          repeat with ii from 1 to cCount
            tell column ii
              set width to (contents of item ii of wList)
            end tell
          end repeat
        end tell
        
      end repeat
    end tell
  end tell
end tell

★Click Here to Open This Script 

2018/01/18 テキストをTTSで読み上げて所要時間を算出 v2.1(CotEditor版)

CotEditorでオープン中の最前面の書類の本文テキストを取得し、macOS標準搭載のText To Speechの機能を用いて最大限に遅い速度(180 words per minute)と速い速度(220 words per minute)の2通りで読み上げて音声読み上げ所要時間のシミュレーション結果をCotEditor内蔵のコンソールに出力するAppleScriptです。

実際の読み上げ時間よりもはるかに短い時間でファイルへの音声レンダリングを実行し、生成した音声ファイルの再生時間(Duration)を取得することで、TTS読み上げ所要時間≒人間が実際に読み上げたときの所要時間を求めます。また、シミュレーション中は音声をファイルに出力するため、スピーカーなどから音声を出すわけではありません。

ttsreadout.png

CotEditor内蔵のScript Menuに入れて実行できることを確認しました。当然、OS側のScript Menuに入れて実行できます。

6,200文字の日本語テキストの読み上げ実時間の計測(速いパターンと遅いパターンの2回実行)に30秒ほどかかりました。読み上げ実時間は15分ぐらいだったので、実時間よりは速く処理できますが、割と時間がかかる処理です。

また、これは「言うは易し、行うは・・・」の典型例のような処理でした。sayコマンドによるTTS読み上げ、音声のファイル出力、読み上げ実時間を待たずにサウンドファイル出力などの機能がありながら、これらが非同期で実行されるために骨が折れます。

出力ファイルの再生時間を取得しようとするとエラー、出力ファイルパスのPOSIX pathにquoted form of でクォート処理するとエラー、などなど。

とりあえず、sayコマンドによる音声ファイル出力が終わったあと、音声ファイルが本当に出力終了するまでファイルをチェックしつつ待ちます。sayコマンドからの出力が並列処理で行えれば、並列処理向きの内容だと思います。

CotEditor以外でも実際にAppleScriptに対応しているエディタであれば、本文テキストを取得するだけなのでテキストエディットをはじめだいたいのものには対応できます。

AppleScript名:テキストをTTSで読み上げて所要時間を算出 v2.1(CotEditor版)
– Created 2018-01-10 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AVFoundation”
use framework “AppKit”
–http://piyocast.com/as/archives/5113

property |NSURL| : a reference to current application’s |NSURL|
property NSDate : a reference to current application’s NSDate
property NSUUID : a reference to current application’s NSUUID
property NSFileManager : a reference to current application’s NSFileManager
property AVAudioPlayer : a reference to current application’s AVAudioPlayer
property NSDateFormatter : a reference to current application’s NSDateFormatter
property NSSpeechSynthesizer : a reference to current application’s NSSpeechSynthesizer

set str3 to getEditorText() of me
if str3 = false then return

set aVoice to “Kyoko”

–Check existence of TTS Voice name
set vList to retAvailableTTSnames() of me
if aVoice is not in vList then error “Wrong TTS Voice Name”

set d1 to readTextByTTSVoiceAndReturnDuration(str3, aVoice, 180) of me –aSpeedRate is “Words per minute. 180 to 220″
set d2 to readTextByTTSVoiceAndReturnDuration(str3, aVoice, 220) of me

set outStr to (formatHMS(d1) of me & “/180 words per minute”) & return & (formatHMS(d2) of me & “/220 words per minute”) & return
tell application “CotEditor”
  activate
  
write to console outStr
end tell

on readTextByTTSVoiceAndReturnDuration(aStr as string, aVoice as string, aSpeedRate as integer)
  set aUUID to NSUUID’s UUID()’s UUIDString() as string
  
–set aPath to (((path to temporary items from user domain) as string) & aUUID & “.aif”)
  
set aPath to (((path to desktop) as string) & aUUID & “.aif”)
  
set aPOSIX to POSIX path of aPath
  
  
tell current application
    say aStr using aVoice saving to (aPOSIX) speaking rate aSpeedRate without waiting until completion
  end tell
  
  
repeat 100000 times
    set aExt to NSFileManager’s defaultManager()’s fileExistsAtPath:aPOSIX
    
if aExt as boolean = true then exit repeat
    
delay “0.001″ as real
  end repeat
  
  
if aExt = false then error “No Sound file”
  
  
set aDur to getDuration(aPath as alias) of me
  
try
    do shell script “rm -f “ & quoted form of POSIX path of aPath
  end try
  
  
return aDur as real
end readTextByTTSVoiceAndReturnDuration

on getDuration(aFile)
  set aURL to |NSURL|’s fileURLWithPath:(POSIX path of aFile)
  
  
repeat 1000 times
    set aAudioPlayer to AVAudioPlayer’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
    
set aRes to aAudioPlayer’s prepareToPlay()
    
if aRes as boolean = true then exit repeat
    
delay 0.5
  end repeat
  
if aRes = false then error “TTS sound output failed”
  
  
set channelCount to aAudioPlayer’s numberOfChannels()
  
set aDuration to aAudioPlayer’s duration()
  
return aDuration as real
end getDuration

on retAvailableTTSnames()
  set outList to {}
  
  
set aList to NSSpeechSynthesizer’s availableVoices()
  
set bList to aList as list
  
  
repeat with i in bList
    set j to contents of i
    
set aInfo to (NSSpeechSynthesizer’s attributesForVoice:j)
    
set aInfoRec to aInfo as record
    
set aName to VoiceName of aInfoRec
    
set the end of outList to aName
  end repeat
  
  
return outList
end retAvailableTTSnames

on formatHMS(aTime)
  set aDate to NSDate’s dateWithTimeIntervalSince1970:aTime
  
set aFormatter to NSDateFormatter’s alloc()’s init()
  
  
—This formatter text is localized in Japanese.
  
if aTime < hours then
    aFormatter’s setDateFormat:“mm分ss秒”
  else if aTime < days then
    aFormatter’s setDateFormat:“HH時間mm分ss秒”
  else
    aFormatter’s setDateFormat:“DD日HH時間mm分ss秒”
  end if
  
  
set timeStr to (aFormatter’s stringFromDate:aDate) as string
  
return timeStr
end formatHMS

on getEditorText()
  tell application “CotEditor”
    if (count every document) = 0 then return false
    
tell front document
      return contents
    end tell
  end tell
end getEditorText

★Click Here to Open This Script 

2018/01/17 文字種別にカウントする v2.1(Jedit Ω版)

Jedit Ωの最前面の書類を文字種類別にカウントして結果を新規Jedit Ωドキュメントに出力するAppleScriptです。

jeditomega1.png

Jedit Ω内蔵Script Menuに入れて実行してみたら実行できませんでした。スクリプト書類でもスクリプトバンドルでも無理でした(ASOCの実行自体ができないわけではない)。OS側のScript Menuに入れて実行してください。

Jedit Ωでfront documentの本文テキストを取り出すのに若干苦労しました。なんでこんなことに、、、、

同じテキストをオープンしてみて、Jedit ΩとCotEditorで得られる文字数が若干違うことに気づいてしまいましたが、これっていったいなんでしょうか(^ー^;;

AppleScript名:文字種別にカウントする v2.1(JeditΩ版)
– Created 2018-1-11 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/5111

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

set aRes to getEditorText() of me
if aRes = false then return

set myPath to retFrontDocsPath() of me
if myPath = missing value then return

set aRec to detectCharKindRatio(aRes) of me
set bRes to retFormattedStr(aRec) of me
makeNewDocument of me given parameter:(myPath & return & return & bRes)

on detectCharKindRatio(aStr as string)
  set theCountedSet to NSCountedSet’s alloc()’s initWithArray:(characters of aStr)
  
set theEnumerator to theCountedSet’s objectEnumerator()
  
  
set cCount to 0
  
set hCount to 0
  
set kCount to 0
  
set oCount to 0
  
set lfCount to 0
  
set scCount to 0
  
set anCount to 0
  
  
set totalC to length of aStr
  
set otherList to {}
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
    
set aStr to aValue as string
    
set tmpCount to (theCountedSet’s countForObject:aValue)
    
    
set s1Res to chkKanji(aStr) of me
    
set s2Res to chkKatakana(aStr) of me
    
set s3Res to chkHiragana(aStr) of me
    
set s4Res to chkLineFeed(aStr) of me
    
set s5Res to chkSpecialSign(aStr) of me
    
set s6Res to chkAlphaNumeric(aStr)
    
    
if s1Res = true then
      set cCount to cCount + tmpCount
    else if s2Res = true then
      set kCount to kCount + tmpCount
    else if s3Res = true then
      set hCount to hCount + tmpCount
    else if s4Res = true then
      set lfCount to lfCount + tmpCount
    else if s5Res = true then
      set scCount to scCount + tmpCount
    else if s6Res = true then
      set anCount to anCount + tmpCount
    else
      set oCount to oCount + tmpCount
      
set the end of otherList to aStr
    end if
  end repeat
  
  
set ckRes to roundingUp((cCount / totalC) * 100, 1) of me
  
set kkRes to roundingUp((kCount / totalC) * 100, 1) of me
  
set hgRes to roundingUp((hCount / totalC) * 100, 1) of me
  
set otRes to roundingUp((oCount / totalC) * 100, 1) of me
  
set lfRes to roundingUp((lfCount / totalC) * 100, 1) of me
  
set scRes to roundingUp((scCount / totalC) * 100, 1) of me
  
set anRes to roundingUp((anCount / totalC) * 100, 1) of me
  
  
return {kanjiNum:cCount, kanjiRatio:ckRes, hiraganaNum:hCount, hiraganaRatio:hgRes, katakanaNum:kCount, katakanaRatio:kkRes, otherNum:oCount, otherRatio:otRes, otherContent:otherList, lineFeedCount:lfCount, lineFeedRatio:lfRes, specialSignNum:scCount, specialSignRatio:scRes, alphaNumericNum:anCount, alphaNumericRatio:anRes, totalCount:totalC}
end detectCharKindRatio

on chkKanji(aChar)
  return detectCharKind(aChar, “[一-龠]”) of me
end chkKanji

on chkHiragana(aChar)
  return detectCharKind(aChar, “[ぁ-ん]”) of me
end chkHiragana

on chkKatakana(aChar)
  return detectCharKind(aChar, “[ァ-ヶ]”) of me
end chkKatakana

on chkLineFeed(aChar)
  return aChar is in {string id 10, string id 13, string id 13 & string id 10}
end chkLineFeed

on chkSpecialSign(aChar)
  return aChar is in {“「”, “」”, “『”, “』”, “ー”, “―”, “〜”, “〜”, “!”, “?”, “&”, “/”, “《”, “》”, “#”, “…”, “・”, “♪”, “。”, “、”, “.”, “々”, ““”, “””, “*”, “(”, “)”, “(”, “)”, ” “, “ ”, “§”, “【”, “】”, “■”, “%”, “≒”}
end chkSpecialSign

on chkAlphaNumeric(aChar)
  return detectCharKind(aChar, “[a-zA-Z0-9a-zA-Z0-9]”) of me –半角全角英数字
end chkAlphaNumeric

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

on roundingUp(aNum, aDigit as integer)
  set a to aNum as real
  
set aFormatter to NSNumberFormatter’s alloc()’s init()
  
aFormatter’s setMaximumFractionDigits:aDigit
  
aFormatter’s setRoundingMode:(NSNumberFormatterRoundUp)
  
set aStr to aFormatter’s stringFromNumber:(NSNumber’s numberWithFloat:a)
  
return (aStr as text) as real
end roundingUp

on getEditorText()
  tell application id “jp.co.artman21.JeditOmega”
    if (count every document) = 0 then return false
    
tell front document
      return text of it
    end tell
  end tell
end getEditorText

–処理結果から出力データの組み立て
on retFormattedStr(aRec)
  set a to “漢字  :” & (repChar(“■”, ((kanjiRatio of aRec) div 10)) of me & “  “ & (kanjiRatio of aRec) as string) & “%” & return
  
set b to “ひらがな:” & (repChar(“■”, ((hiraganaRatio of aRec) div 10)) of me & “  “ & (hiraganaRatio of aRec) as string) & “%” & return
  
set c to “カタカナ:” & (repChar(“■”, ((katakanaRatio of aRec) div 10)) of me & “  “ & (katakanaRatio of aRec) as string) & “%” & return
  
set d to “改行文字:” & (repChar(“■”, ((lineFeedRatio of aRec) div 10)) of me & “  “ & (lineFeedRatio of aRec) as string) & “%” & return
  
set e to “特殊記号:” & (repChar(“■”, ((specialSignRatio of aRec) div 10)) of me & “  “ & (specialSignRatio of aRec) as string) & “%” & return
  
set f to “英数字 :” & (repChar(“■”, ((alphaNumericRatio of aRec) div 10)) of me & “  “ & (alphaNumericRatio of aRec) as string) & “%” & return & return
  
set g to (“総文字数:” & encodeJapaneseNumText(totalCount of aRec) & ” 文字。 400字詰め原稿用紙で約 “ & ((totalCount of aRec) div 400) as string) & ” 枚分” & return
  
set all to a & b & c & d & e & f & g
  
return all
end retFormattedStr

on repChar(aChar, aTimes)
  set outStr to “”
  
repeat aTimes times
    set outStr to outStr & aChar
  end repeat
  
return outStr
end repChar

–数字文字列を日本語数値表現文字列に変換
on encodeJapaneseNumText(aText as string)
  set dotText to “.” as string
  
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 string
    
set lowerDigit to characters b thru -1 of aText
    
set lowerDigit to lowerDigit as string
  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
  
  
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 makeNewDocument given parameter:aStr
  tell application id “jp.co.artman21.JeditOmega”
    set aDoc to make new document with properties {text:aStr}
  end tell
end makeNewDocument

on retFrontDocsPath()
  tell application id “jp.co.artman21.JeditOmega”
    tell front document
      return path
    end tell
  end tell
end retFrontDocsPath

★Click Here to Open This Script 

2018/01/16 文字種別にカウントする v2.1(CotEditor版)

CotEditorの最前面の書類を文字種類別にカウントして結果を新規CotEditorドキュメントに出力するAppleScriptです。

cot2.png
▲結果出力

cot1.png
▲セキュリティ上の制約の大きいCotEditor内蔵のScript Menuからも実行可能

改行記号や英数字、特殊文字のカウントを追加してみました。改行文字の多すぎ/少なすぎを既存の文章から分析できるとよいと思います。「坊ちゃん」の改行文字0.6%はさすがにいま読むとちょっと少なすぎですね。

ほかにも、400字詰原稿用紙で何枚分に相当するかの計算もつけてみました。総文字数のカウント表示には、きちんと日本語数値表現エンコーダライブラリの機能を突っ込んでみました(無量大数まで対応)。

他のテキストエディタ用に転用するのもさほど難しくありません(たいした機能は使っていないので)。

ここにさらに「AppleScriptらしい」ひとひねりを加えるとしたら、音声読み上げしたときの所要時間を読み上げ速度別に計算してレポートするぐらいでしょうか。

AppleScript名:文字種別にカウントする v2.1
– Created 2018-1-11 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/5109

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

set aRes to getCotEditorText() of me
if aRes = false then return

set myPath to retFrontDocsPath() of me
if myPath = missing value then return

set aRec to detectCharKindRatio(aRes) of me
set bRes to retFormattedStr(aRec) of me
makeNewDocument of me given parameter:(myPath & return & return & bRes)

on detectCharKindRatio(aStr as string)
  set theCountedSet to NSCountedSet’s alloc()’s initWithArray:(characters of aStr)
  
set theEnumerator to theCountedSet’s objectEnumerator()
  
  
set cCount to 0
  
set hCount to 0
  
set kCount to 0
  
set oCount to 0
  
set lfCount to 0
  
set scCount to 0
  
set anCount to 0
  
  
set totalC to length of aStr
  
set otherList to {}
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
    
set aStr to aValue as string
    
set tmpCount to (theCountedSet’s countForObject:aValue)
    
    
set s1Res to chkKanji(aStr) of me
    
set s2Res to chkKatakana(aStr) of me
    
set s3Res to chkHiragana(aStr) of me
    
set s4Res to chkLineFeed(aStr) of me
    
set s5Res to chkSpecialSign(aStr) of me
    
set s6Res to chkAlphaNumeric(aStr)
    
    
if s1Res = true then
      set cCount to cCount + tmpCount
    else if s2Res = true then
      set kCount to kCount + tmpCount
    else if s3Res = true then
      set hCount to hCount + tmpCount
    else if s4Res = true then
      set lfCount to lfCount + tmpCount
    else if s5Res = true then
      set scCount to scCount + tmpCount
    else if s6Res = true then
      set anCount to anCount + tmpCount
    else
      set oCount to oCount + tmpCount
      
set the end of otherList to aStr
    end if
  end repeat
  
  
set ckRes to roundingUp((cCount / totalC) * 100, 1) of me
  
set kkRes to roundingUp((kCount / totalC) * 100, 1) of me
  
set hgRes to roundingUp((hCount / totalC) * 100, 1) of me
  
set otRes to roundingUp((oCount / totalC) * 100, 1) of me
  
set lfRes to roundingUp((lfCount / totalC) * 100, 1) of me
  
set scRes to roundingUp((scCount / totalC) * 100, 1) of me
  
set anRes to roundingUp((anCount / totalC) * 100, 1) of me
  
  
return {kanjiNum:cCount, kanjiRatio:ckRes, hiraganaNum:hCount, hiraganaRatio:hgRes, katakanaNum:kCount, katakanaRatio:kkRes, otherNum:oCount, otherRatio:otRes, otherContent:otherList, lineFeedCount:lfCount, lineFeedRatio:lfRes, specialSignNum:scCount, specialSignRatio:scRes, alphaNumericNum:anCount, alphaNumericRatio:anRes, totalCount:totalC}
end detectCharKindRatio

on chkKanji(aChar)
  return detectCharKind(aChar, “[一-龠]”) of me
end chkKanji

on chkHiragana(aChar)
  return detectCharKind(aChar, “[ぁ-ん]”) of me
end chkHiragana

on chkKatakana(aChar)
  return detectCharKind(aChar, “[ァ-ヶ]”) of me
end chkKatakana

on chkLineFeed(aChar)
  return aChar is in {string id 10, string id 13, string id 13 & string id 10}
end chkLineFeed

on chkSpecialSign(aChar)
  return aChar is in {“「”, “」”, “『”, “』”, “ー”, “―”, “〜”, “〜”, “!”, “?”, “&”, “/”, “《”, “》”, “#”, “…”, “・”, “♪”, “。”, “、”, “.”, “々”, ““”, “””, “*”, “(”, “)”, “(”, “)”, ” “, “ ”, “§”, “【”, “】”, “■”, “%”, “≒”}
end chkSpecialSign

on chkAlphaNumeric(aChar)
  return detectCharKind(aChar, “[a-zA-Z0-9a-zA-Z0-9]”) of me –半角全角英数字
end chkAlphaNumeric

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

on roundingUp(aNum, aDigit as integer)
  set a to aNum as real
  
set aFormatter to NSNumberFormatter’s alloc()’s init()
  
aFormatter’s setMaximumFractionDigits:aDigit
  
aFormatter’s setRoundingMode:(NSNumberFormatterRoundUp)
  
set aStr to aFormatter’s stringFromNumber:(NSNumber’s numberWithFloat:a)
  
return (aStr as text) as real
end roundingUp

on getCotEditorText()
  tell application “CotEditor”
    if (count every document) = 0 then return false
    
tell front document
      set aText to contents
    end tell
  end tell
end getCotEditorText

–処理結果から出力データの組み立て
on retFormattedStr(aRec)
  set a to “漢字  :” & (repChar(“■”, ((kanjiRatio of aRec) div 10)) of me & “  “ & (kanjiRatio of aRec) as string) & “%” & return
  
set b to “ひらがな:” & (repChar(“■”, ((hiraganaRatio of aRec) div 10)) of me & “  “ & (hiraganaRatio of aRec) as string) & “%” & return
  
set c to “カタカナ:” & (repChar(“■”, ((katakanaRatio of aRec) div 10)) of me & “  “ & (katakanaRatio of aRec) as string) & “%” & return
  
set d to “改行文字:” & (repChar(“■”, ((lineFeedRatio of aRec) div 10)) of me & “  “ & (lineFeedRatio of aRec) as string) & “%” & return
  
set e to “特殊記号:” & (repChar(“■”, ((specialSignRatio of aRec) div 10)) of me & “  “ & (specialSignRatio of aRec) as string) & “%” & return
  
set f to “英数字 :” & (repChar(“■”, ((alphaNumericRatio of aRec) div 10)) of me & “  “ & (alphaNumericRatio of aRec) as string) & “%” & return & return
  
set g to (“総文字数:” & encodeJapaneseNumText(totalCount of aRec) & ” 文字。 400字詰め原稿用紙で約 “ & ((totalCount of aRec) div 400) as string) & ” 枚分” & return
  
set all to a & b & c & d & e & f & g
  
return all
end retFormattedStr

on repChar(aChar, aTimes)
  set outStr to “”
  
repeat aTimes times
    set outStr to outStr & aChar
  end repeat
  
return outStr
end repChar

–数字文字列を日本語数値表現文字列に変換
on encodeJapaneseNumText(aText as string)
  set dotText to “.” as string
  
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 string
    
set lowerDigit to characters b thru -1 of aText
    
set lowerDigit to lowerDigit as string
  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
  
  
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 makeNewDocument given parameter:aStr
  tell application id “com.coteditor.CotEditor”
    activate
    
set newDoc to make new document
    
tell newDoc
      set contents to aStr
    end tell
  end tell
end makeNewDocument

on retFrontDocsPath()
  tell application id “com.coteditor.CotEditor”
    tell front document
      return path
    end tell
  end tell
end retFrontDocsPath

★Click Here to Open This Script 

2018/01/16 文字種別ごとにカウントする v2

指定のプレーンテキスト(UTF-8)を漢字、ひらがな、カタカナ、その他で個別に集計するAppleScriptです。

charkind1_resized.png

charkind2_resized.png

文学作品(夏目漱石の「坊ちゃん」)と小説家になろうサイトのラノベで比較してみたところ、カタカナの使用率であからさまに傾向が異なりました。1つの文章の文字数や改行コードの混入率などを調べてもあきらかに傾向が出ると思います。

文字種別の判定を正規表現で処理していますが、すべての文字をシーケンシャルにチェックすると時間がかかるので、NSCountedSetを用いて文字ごとに使用頻度の集計を行なってからループで合算。これで処理時間の短縮を行なっています。テキストの分量が増えると、テキストの文字列ごとの分割(characters of)が遅くなるので注意が必要です。

文章を書くときには、漢字の使用頻度が高くなりすぎないように気をつけているので、こういう集計はできないと困ります。OS側にそういうサービスがあってもよさそうなものですが、残念ながら日本語以外でこういうことに注意が必要な言語が少なさそうなので、標準搭載はされないことでしょう。

macOS 10.12.x〜macOS 10.13.0までの間で存在している「NSNotFoundの値の定義がまちがっているバグ」に対処してあります。

AppleScript名:文字種別にカウントする v2
– Created 2018-1-11 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/5104

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

set sourcePath to choose file of type {“public.plain-text”}
tell current application
  set aStr to (read sourcePath as «class utf8»)
end tell

set aRes to detectCharKindRating(aStr) of me
–> {kanjiNum:563289, kanjiRating:22.0, hiraganaNum:1311933, hiraganaRating:51.2, katakanaNum:210161, katakanaRating:8.2, otherNum:478690, otherRating:18.7, totalCount:2564073}–Light Novel
–> {kanjiNum:24960, kanjiRating:28.0, hiraganaNum:56080, hiraganaRating:62.9, katakanaNum:1063, katakanaRating:1.2, otherNum:7136, otherRating:8.0} –文学(坊ちゃん)

on detectCharKindRating(aStr as string)
  set theCountedSet to NSCountedSet’s alloc()’s initWithArray:(characters of aStr)
  
set theEnumerator to theCountedSet’s objectEnumerator()
  
  
set cCount to 0
  
set hCount to 0
  
set kCount to 0
  
set oCount to 0
  
set totalC to length of aStr
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
    
set aStr to aValue as string
    
set tmpCount to (theCountedSet’s countForObject:aValue)
    
    
set s1Res to chkKanji(aStr) of me
    
set s2Res to chkKatakana(aStr) of me
    
set s3Res to chkHiragana(aStr) of me
    
    
if s1Res = true then
      set cCount to cCount + tmpCount
    else if s2Res = true then
      set kCount to kCount + tmpCount
    else if s3Res = true then
      set hCount to hCount + tmpCount
    else
      set oCount to oCount + tmpCount
    end if
  end repeat
  
  
set ckRes to roundingUp((cCount / totalC) * 100, 1) of me
  
set kkRes to roundingUp((kCount / totalC) * 100, 1) of me
  
set hgRes to roundingUp((hCount / totalC) * 100, 1) of me
  
set otRes to roundingUp((oCount / totalC) * 100, 1) of me
  
  
return {kanjiNum:cCount, kanjiRating:ckRes, hiraganaNum:hCount, hiraganaRating:hgRes, katakanaNum:kCount, katakanaRating:kkRes, otherNum:oCount, otherRating:otRes}
end detectCharKindRating

on chkKanji(aChar)
  return detectCharKind(aChar, “[一-龠]”) of me
end chkKanji

on chkHiragana(aChar)
  return detectCharKind(aChar, “[ぁ-ん]”) of me
end chkHiragana

on chkKatakana(aChar)
  return detectCharKind(aChar, “[ァ-ヶ]”) of me
end chkKatakana

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

on roundingUp(aNum, aDigit as integer)
  set a to aNum as real
  
set aFormatter to NSNumberFormatter’s alloc()’s init()
  
aFormatter’s setMaximumFractionDigits:aDigit
  
aFormatter’s setRoundingMode:(NSNumberFormatterRoundUp)
  
set aStr to aFormatter’s stringFromNumber:(NSNumber’s numberWithFloat:a)
  
return (aStr as text) as real
end roundingUp

★Click Here to Open This Script 

2018/01/14 RTF本文内の色を置換 v2

指定したRTF書類の本文中の色をだいたいの色に分け(11色)、置換対象の色を指定色に置き換えるAppleScriptです。色のゆらぎを吸収しつつ、代表色11色単位で色の置き換えが可能です。

つまり、「赤っぽい」色は全部置換対象として色の置換を行う、といった処理を行えます。

rtf1.png
▲処理前

col_rep1_resized.png
▲処理内容(代表色の色名で指定して色置換)

rtf2.png
▲処理後

これまでRGB→HSBの変換に外部のフレームワークを使用していましたが、すべて標準の機能で処理できるように書き換えてみました。

65KバイトぐらいのRTF書類を色置換するのに2〜3秒程度です。同様の処理をテキストエディットで行うと8〜10秒程度はかかるので、かなり速いと言えますが、まだ高速化の余地はありそうです。

色のだいたいの名前を計算する処理で、

(1)RGB–> XYZ –> L*a*b*と色変換して、各代表色との色差ΔEを計算して一番近いものを返す
(2)RGB–>HSBと色変換してHueの角度(0〜360度)をブロック化して判定

の2つの処理の速度を計測してみたところ、(2)のほうが11倍ぐらい高速でしたが、1,000回ぐらいループで計測すると0.003秒 vs 0.001秒ぐらいの差しかなかったので、どっちでもいい気がします。どちらの演算結果もさほど変わりません。

最終的には、外部フレームワークを必要としない(2)の処理に落ち着きあるところです。

AppleScript名:RTF本文内の色を置換 v2
– Created 2018-01-13 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
–http://piyocast.com/as/archives/5102

property NSData : a reference to current application’s NSData
property NSUUID : a reference to current application’s NSUUID
property NSColor : a reference to current application’s NSColor
property NSString : a reference to current application’s NSString
property NSPredicate : a reference to current application’s NSPredicate
property NSDictionary : a reference to current application’s NSDictionary
property NSMutableArray : a reference to current application’s NSMutableArray
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName
property NSDocumentTypeDocumentAttribute : a reference to current application’s NSDocumentTypeDocumentAttribute

set targFilePath to POSIX path of (choose file of type {“public.rtf”})
set targColorNameList to {“blue”, “red”} –replace target color names
set toColor to NSColor’s blackColor() –to color
set aRes to replaceRTFColorsByColorName(targFilePath, targColorNameList, toColor, 65535) of me

–指定RTF書類本文中、名称で指定した色の該当箇所を指定色(NSColor)に置換する(複数色)
on replaceRTFColorsByColorName(targFilePath as string, targColorNameList as list, toColor, aColorMax as integer)
  script spd
    property hitList : {}
  end script
  
set (hitList of spd) to {}
  
set aFilePath to NSString’s stringWithString:(targFilePath)
  
set aData to NSData’s dataWithContentsOfFile:aFilePath options:0 |error|:(missing value)
  
set theStyledText to NSMutableAttributedString’s alloc()’s initWithData:aData options:(missing value) documentAttributes:(missing value) |error|:(missing value)
  
  
set attrList to getAttributeRunsFromAttrString(theStyledText, aColorMax) of me
  
set attrArray to NSMutableArray’s arrayWithArray:attrList
  
  
theStyledText’s beginEditing() ——
  
repeat with ii in targColorNameList
    set jj to contents of ii
    
set thePred to NSPredicate’s predicateWithFormat_(“colorName == %@”, jj)
    
set (hitList of spd) to ((attrArray’s filteredArrayUsingPredicate:thePred)’s valueForKey:“rangeVal”) as list
    
    
repeat with i in (hitList of spd)
      (theStyledText’s addAttribute:(NSForegroundColorAttributeName) value:toColor range:(contents of i))
    end repeat
    
  end repeat
  
theStyledText’s endEditing() ——
  
  
–Save RTF to desktop
  
set targFol to current application’s NSHomeDirectory()’s stringByAppendingPathComponent:“Desktop”
  
set aRes to saveStyledTextAsRTF(targFol, theStyledText) of me
  
return aRes as boolean
end replaceRTFColorsByColorName

–AttributedStringを書式でlist of record化
on getAttributeRunsFromAttrString(theStyledText, aColorMax)
  script aSpd
    property styleList : {}
  end script
  
  
set (styleList of aSpd) to {} —for output
  
  
set thePureString to theStyledText’s |string|() –pure string from theStyledText
  
  
set theLength to theStyledText’s |length|()
  
set startIndex to 0
  
  
repeat until (startIndex = theLength)
    set {theAtts, theRange} to theStyledText’s attributesAtIndex:startIndex longestEffectiveRange:(reference) inRange:{startIndex, theLength - startIndex}
    
    
–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()) * aColorMax
      
set aGreen to (aColor’s greenComponent()) * aColorMax
      
set aBlue to (aColor’s blueComponent()) * aColorMax
      
      
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
    
    
–Color Name
    
set cName to retColorName(aRed, aGreen, aBlue, aColorMax) of me
    
    
–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, rangeVal:theRange, colorName:cName}
    
    
set startIndex to current application’s NSMaxRange(theRange)
    
  end repeat
  
  
return (styleList of aSpd)
end getAttributeRunsFromAttrString

–RGB値から色名称(だいたいの色)を計算する
on retColorName(rCol as integer, gCol as integer, bCol as integer, aColMax as integer)
  set aCol to makeNSColorFromRGBAval(rCol, gCol, bCol, aColMax, aColMax) of me
  
set hueVal to aCol’s hueComponent() as real
  
set satVal to aCol’s saturationComponent() as real
  
set brightVal to aCol’s brightnessComponent() as real
  
  
if satVal 0.01 then set satVal to 0.0
  
  
if satVal = 0.0 then
    if brightVal 0.2 then
      set colName to “black”
    else if (brightVal > 0.95) then
      set colName to “white”
    else
      set colName to “gray”
    end if
  else
    if hueVal (15.0 / 360) or hueVal (330 / 360) then
      set colName to “red”
    else if hueVal (45.0 / 360) then
      set colName to “orange”
    else if hueVal < (70.0 / 360) then
      set colName to “yellow”
    else if hueVal < (150.0 / 360) then
      set colName to “green”
    else if hueVal < (190.0 / 360) then
      set colName to “cyan”
    else if (hueVal < 250.0 / 360.0) then
      set colName to “blue”
    else if (hueVal < 290.0 / 360.0) then
      set colName to “purple”
    else
      set colName to “magenta”
    end if
  end if
  
  
return colName
end retColorName

on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
  
return aColor
end makeNSColorFromRGBAval

–スタイル付きテキストを指定フォルダ(POSIX path)にRTFで書き出し
on saveStyledTextAsRTF(targFol, aStyledString)
  set bstyledLength to aStyledString’s |string|()’s |length|()
  
set bDict to NSDictionary’s dictionaryWithObject:“NSRTFTextDocumentType” forKey:(NSDocumentTypeDocumentAttribute)
  
set bRTF to aStyledString’s RTFFromRange:(current application’s NSMakeRange(0, bstyledLength)) documentAttributes:bDict
  
  
set theName to (NSUUID’s UUID()’s UUIDString())
  
set thePath to NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:“rtf”
  
return (bRTF’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsRTF

★Click Here to Open This Script 

2018/01/13 DBColorNamesで色の名称を取得する

任意のNSColorの色名称を948色のテーブルから取得するオープンソースの「DBColorNames」(By Daniel Beard)をフレームワーク化したdbColNamesKitを呼び出して色の詳細な名称を取得するAppleScriptです。

実行には、dbColNamesKit.frameworkのインストールを必要とします。アーカイブをダウンロードして展開し、~/Library/Frameworksフォルダに入れてください(あくまで自己責任で)。

–> Download Framework Binary

だいたいざっくり「緑色ぐらい」といった判別ではなく、詳細な色見本帳のような判定を行います。性能云々というよりは、処理の方向性が違うといったところでしょうか。

AppleScript名:dbColNamesKitで色の名称を取得する
– Created 2018-01-11 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “dbColNamesKit” –https://github.com/daniel-beard/DBColorNames/
–http://piyocast.com/as/archives/5098

property NSColor : a reference to current application’s NSColor

set {rVal, gVal, bVal} to choose color
set aColor to makeNSColorFromRGBAval(rVal, gVal, bVal, 65535, 65535) of me
set aCDB to current application’s DBColorNames’s alloc()’s init()

set aColorStr to (aCDB’s nameForColor:aColor) as string

on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
  
return aColor
end makeNSColorFromRGBAval

★Click Here to Open This Script 

2018/01/13 TextEditで本文色をポスタライズ v1

TextEdit書類の本文色をポスタライズするAppleScriptです。

複数のユーザーでRTFに対して色をつけてチェックを行なったような場合に、指定色が微妙にゆらいでしまっても色のゆらぎを吸収するためのものです。

TextEditでオープン中の最前面のRTF書類中の文字色のゆらぎを吸収します。

オープンソースの「Colours」(By Ben Gordon)をフレームワーク化したcolorsKitを呼び出して、RGB→HSBA変換を行なっています。2D List中のリスト項目検索のためにShane StanleyのBridge Plus AppleScript Librariesを利用しています。

実行には、Bridge PlusおよびcolorsKit.frameworkのインストールを必要とします。colorsKit.frameworkについてはアーカイブをダウンロードして展開し、~/Library/Frameworksフォルダに入れてください(あくまで自己責任で)。

–> Download Framework Binary

te1png.png
▲処理前(緑色の文字の色にゆらぎがある)

t22.png
▲処理後(文字色が12色程度の原色に統一される)

AppleScript名:TextEditで本文色をポスタライズ v1
– Created 2018-01-08 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “colorsKit” –https://github.com/bennyguitar/Colours
use bPlus : script “BridgePlus” –https://www.macosxautomation.com/applescript/apps/BridgePlus.html
–http://piyocast.com/as/archives/5097

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

script spd
  property colList : {}
  
property attList : {}
end script

load framework

set cList to retTextEditColors() of me
set dList to {}

repeat with i in cList
  copy i to {rVal, gVal, bVal}
  
set newColList to posterizeColor(rVal, gVal, bVal, 65535) of me
  
repTextEditColor(i, newColList) of me
end repeat

on repTextEditColor(targColor, newColor)
  set hitIndex to {}
  
  
tell application “TextEdit”
    tell text of front document
      set colList to color of every attribute run
    end tell
  end tell
  
  
set hitIndex to (current application’s SMSForder’s indexesOfItem:targColor inArray:(colList) inverting:false) as list
  
  
tell application “TextEdit”
    tell text of front document
      repeat with i in hitIndex
        ignoring application responses
          set color of attribute run (i + 1) to newColor –0 based index to 1 based index conversion
        end ignoring
      end repeat
    end tell
  end tell
end repTextEditColor

on posterizeColor(rCol as integer, gCol as integer, bCol as integer, aColorMax)
  set aRes to makeNSColorFromRGBAval(rCol, gCol, bCol, aColorMax, aColorMax) of me
  
set aDic to aRes’s hsbaDictionary()
  
  
set hueVal to (|HSBA-h| of aDic) as real
  
set satVal to (|HSBA-s| of aDic) as real
  
set brightVal to (|HSBA-b| of aDic) as real
  
set alphaVal to (|HSBA-a| of aDic) as real
  
  
if satVal 0.01 then set satVal to 0.0
  
  
if satVal = 0.0 then
    if brightVal 0.2 then
      set colVal to {0, 0, 0} –Black
    else if (brightVal > 0.95) then
      set colVal to {65535, 65535, 65535} –White
    else
      set colVal to {32768, 32768, 32768} –Gray
    end if
  else
    if hueVal (15.0 / 360) or hueVal (330 / 360) then
      set colVal to {65535, 0, 0} –red
    else if hueVal (45.0 / 360) then
      set colVal to {65535, 32768, 0} –orange
    else if hueVal < (70.0 / 360) then
      set colVal to {65533, 63639, 2654} –yellow
    else if hueVal < (150.0 / 360) then
      set colVal to {4626, 35488, 17789} –green
    else if hueVal < (190.0 / 360) then
      set colVal to {0, 60802, 65535} –cyan, light blue
    else if (hueVal < 250.0 / 360.0) then
      set colVal to {0, 0, 65535} –blue
    else if (hueVal < 290.0 / 360.0) then
      set colVal to {32768, 0, 32768} –purple
    else
      set colVal to {65535, 0, 65535} –magenta, pink
    end if
  end if
  
  
return colVal
end posterizeColor

on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aCocoaList to {aRedCocoa, aGreenCocoa, aBlueCocoa, aAlphaCocoa}
  
set aColor to NSColor’s colorFromRGBAArray:aCocoaList
  
return aColor
end makeNSColorFromRGBAval

on retTextEditColors()
  tell application “TextEdit”
    set dCount to count every document
    
if dCount = 0 then return
    
tell text of front document
      set aList to color of every character
    end tell
  end tell
  
  
set ap1List to uniquify1DList(aList, true) of me
  
set cList to {}
  
repeat with i in ap1List
    set the end of cList to contents of i
  end repeat
  
  
return cList
end retTextEditColors

–1D Listをユニーク化
on uniquify1DList(theList as list, aBool as boolean)
  set aArray to NSArray’s arrayWithArray:theList
  
set bArray to aArray’s valueForKeyPath:“@distinctUnionOfObjects.self”
  
set bList to bArray as list
  
return bList
end uniquify1DList

★Click Here to Open This Script 

2018/01/11 RGB色をHSBAに変換して色名称を計算

オープンソースの「Colours」(By Ben Gordon)をフレームワーク化したcolorsKitを呼び出して、指定色が「だいたいどんな色」かを計算するAppleScriptの別バージョンです。

hsba_color_picker.png

自分のやり方(色差ΔEで代表的な色との距離を計算する)のほかにもないものかと調べてみたら、RGB色をHSBA色に変換して色判定を行うものを見つけました。ロジックがとても簡潔で技術的な難易度もおっそろしく低かったので、Objective-Cで書かれたプログラムをAppleScriptに置き換えて検証してみました。

RGB色をHSBAに変換して、Hue(色相)の角度を細分化して「この数値からこの数値まではこの色」といったセグメント分けを行なっています。

実行には、colorsKit.frameworkのインストールを必要とします。アーカイブをダウンロードして展開し、~/Library/Frameworksフォルダに入れてください(あくまで自己責任で)。

–> Download Framework Binary

とてもよくわかるのが、やっぱりこのプログラムでもWhite〜Gray〜Blackの判定を最初に行なっていること。また、LightとDarkの判定も行なっています。

色のセグメント分けの箇所が自分のプログラムとは違いはするものの、とてもよく分かる内容でした。ちなみに、さらに細分化した色名称を取得するものがgithub上で公開されています

AppleScript名:RGB色をHSBAに変換して色名称を計算
– Created 2018-01-08 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “colorsKit” –https://github.com/bennyguitar/Colours
–http://piyocast.com/as/archives/5094

property NSColor : a reference to current application’s NSColor

set {rCol, gCol, bCol} to choose color
set cName to retColorName(rCol, gCol, bCol) of me

on retColorName(rCol as integer, gCol as integer, bCol as integer)
  set aRes to makeNSColorFromRGBAval(rCol, gCol, bCol, 65535, 65535) of me
  
set aDic to aRes’s hsbaDictionary()
  
  
set hueVal to (|HSBA-h| of aDic) as real
  
set satVal to (|HSBA-s| of aDic) as real
  
set brightVal to (|HSBA-b| of aDic) as real
  
set alphaVal to (|HSBA-a| of aDic) as real
  
  
if satVal 0.01 then set satVal to 0.0
  
  
set colName to “”
  
  
if satVal = 0.0 then
    if brightVal 0.2 then
      set colName to “black”
    else if (brightVal > 0.95) then
      set colName to “white”
    else
      set colName to “gray”
      
      
if (brightVal < 0.33) then
        set colorName to “dark “ & colorName
      else if (brightVal > 0.66) then
        set colorName to “light “ & colorName
      end if
      
    end if
  else
    if hueVal (15.0 / 360) or hueVal (330 / 360) then
      set colName to “red”
    else if hueVal (45.0 / 360) then
      set colName to “orange”
    else if hueVal < (70.0 / 360) then
      set colName to “yellow”
    else if hueVal < (150.0 / 360) then
      set colName to “green”
    else if hueVal < (190.0 / 360) then
      set colName to “cyan”
    else if (hueVal < 250.0 / 360.0) then
      set colName to “blue”
    else if (hueVal < 290.0 / 360.0) then
      set colName to “purple”
    else
      set colName to “magenta”
    end if
    
    
if (brightVal < 0.5) then
      set colName to “dark “ & colName
    else if (brightVal > 0.0) then
      set colName to “light “ & colName
    end if
  end if
  
  
return colName
end retColorName

on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aCocoaList to {aRedCocoa, aGreenCocoa, aBlueCocoa, aAlphaCocoa}
  
set aColor to NSColor’s colorFromRGBAArray:aCocoaList
  
return aColor
end makeNSColorFromRGBAval

★Click Here to Open This Script 

2018/01/09 Dictionaryのキー名称の置換

Dictionaryのキー名称の置換を行うAppleScriptです。

さまざまなWeb APIやCocoaのメソッドからNSMutableDictionary形式でデータを受け取った場合に、キーの名称にAppleScriptのrecordで扱えない文字列(記号、空白、数字で始まる文字列などなど)が入っていると、recordにcastしたあとでデータが取り出しにくくなります(NSDictionaryの状態のときにvalueForKeyPath:でデータを取り出せばいいんですが)。

そこで、NSMutableDictionaryの状態でキー名称を置換してしまえば、recordにcastしても値が取り出せるようになります。そういう用途のために作ったものです。

キー名称の置換リストを、

  {{”キー名称1″, “新規キー名称1″}, {”キー名称2″, “新規キー名称2″}}

のように作成して呼び出します。

一応、キー値の重複がないかはチェックしていますが、ただ単に2D Listを1D Listに変換して重複項目がないか調べているだけなので、もう少し気の利いたチェックも考えられなくもありません。

AppleScript名:Dictionaryのキー名称の置換
– Created 2018-01-07 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/5092

property NSCountedSet : a reference to current application’s NSCountedSet
property NSMutableDictionary : a reference to current application’s NSMutableDictionary

set aDicLabels to {“HSBA-s”, “HSBA-b”, “HSBA-a”, “HSBA-h”}
set aDicVals to {0.922195169646, 0.902540624142, 1.0, 0.566439336687}

set aDic to NSMutableDictionary’s dictionaryWithObjects:aDicVals forKeys:aDicLabels

set repList to {{“HSBA-s”, “s”}, {“HSBA-b”, “b”}, {“HSBA-a”, “a”}, {“HSBA-h”, “h”}}
set bRecord to repDictionaryKeys(aDic, repList) of me as record
–>  {s:0.922195169646, b:0.902540624142, a:1.0, h:0.566439336687}

on repDictionaryKeys(aDic, repList)
  set rep2List to FlattenList(repList) of me
  
set rep3 to returnDuplicatesOnly(rep2List) of me
  
if rep3 is not equal to {} then error “Duplicate Keys”
  
  
repeat with i in repList
    copy i to {origKey, newKey}
    
set tmpVal to (aDic’s valueForKey:origKey)
    (
aDic’s setObject:tmpVal forKey:newKey)
    (
aDic’s removeObjectForKey:origKey)
  end repeat
  
  
return aDic
end repDictionaryKeys

–By Paul Berkowitz
on FlattenList(aList)
  set oldDelims to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to {“????”}
  
set aString to aList as text
  
set aList to text items of aString
  
set AppleScript’s text item delimiters to oldDelims
  
return aList
end FlattenList

on returnDuplicatesOnly(aList as list)
  set aSet to 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

★Click Here to Open This Script 

2018/01/08 Coloursで指定色がだいたいどんな色なのか推測 v3(白、黒、グレーの判別機能つき)

オープンソースの「Colours」(By Ben Gordon)をフレームワーク化したcolorsKitを呼び出して、指定色が「だいたいどんな色」かを計算するAppleScriptの改良版です。

特徴的な色(Red, Yellow, Pink, Blue, Green, Black, White, Gray, Purple, Light Blue)からの色差を計算して、最も色の距離が近いものをその特徴的な色(Color Domain)とみなして名前(Color Domain Name)を返します。

実行には、colorsKit.frameworkのインストールを必要とします。アーカイブをダウンロードして展開し、~/Library/Frameworksフォルダに入れてください(あくまで自己責任で)。

–> Download Framework Binary

col31.png

col32.png

改良点1:Black〜Gray〜Whiteの判定を最初に行うようにした。これらはRGBの各色の値がほぼイコールで構成されているので除外しやすい。また、濃い色で「Black」ではないものを「Black」と判定されないように、Blackの判定範囲をきわめて狭くした

改良点2:NSColorを作成するのに、Colourの機能を用いて行うようにした。これによって、色差の計算を行なったときにおかしな値が出ることがなくなった

改良点3:Black、Whiteに近い値でこれらではない色をBlack、Whiteにしないように、後処理を行なってみた

col30.png

これらの改良の結果、クレヨンカラーピッカーのうち、首をひねりたくなるようなおかしな判定は1色ぐらいに抑えられるようになりました(本当)。緑色に見える「ティール」{0, 32896, 32896}が「Light Blue」に判定される以外はきわめていい感じです。

AppleScript名:Coloursで指定色がだいたいどんな色なのか推測 v3(白、黒、グレーの判別機能つき)
– Created 2018-01-05 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “colorsKit” –https://github.com/bennyguitar/Colours
(*
http://piyocast.com/as/archives/5088

*)

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

set aColList to choose color
set aRes to retColorDomainName(aColList, 65535) of me

on retColorDomainName(aColList, aColMax)
  set aCocoaList to retCocoaColorList(aColList, aColMax) of me
  
set aCol to NSColor’s colorFromRGBAArray:aCocoaList
  
  
copy aColList to {rVal, gVal, bVal}
  
  
set colorDomainList to {{colName:“Red”, colValue:{64615, 0, 1767}}, {colName:“Yellow”, colValue:{65530, 65344, 2686}}, {colName:“Pink”, colValue:{64551, 0, 57891}}, {colName:“Blue”, colValue:{1636, 0, 65417}}, {colName:“Green”, colValue:{8866, 65535, 2217}}, {colName:“Black”, colValue:{0, 0, 0}}, {colName:“White”, colValue:{65535, 65535, 65535}}, {colName:“Purple”, colValue:{27963, 0, 65430}}, {colName:“Light Blue”, colValue:{7557, 59465, 65463}}}
  
  
–White, Black, Grayの判定。32で整数序算しているのはゆらぎの吸収のため
  
set aDivNum to (aColMax div 32)
  
set rTmp to rVal div aDivNum
  
set gTmp to gVal div aDivNum
  
set bTmp to bVal div aDivNum
  
if {rTmp = gTmp, gTmp = bTmp, bTmp = rTmp} = {true, true, true} then
    if rVal > (aColMax * 0.9) then
      return “White”
    else if rVal < (aColMax * 0.1) then
      return “Black”
    else
      return “Gray”
    end if
  end if
  
  
–各Color Domainからの距離を計算する
  
set nsColList to {}
  
repeat with i in colorDomainList
    set aColV to colValue of i
    
set aColN to colName of i
    
set bCocoaList to retCocoaColorList(aColV, aColMax) of me
    
set bCol to (NSColor’s colorFromRGBAArray:bCocoaList)
    
set aDist to (aCol’s distanceFromColor:bCol type:1) –ColorDistanceCIE94
    
if (aDist as string) = “NaN” then set aDist to 65535
    
set the end of nsColList to {colObj:bCol, colDist:aDist, colName:aColN}
  end repeat
  
  
–距離でソート
  
set aRes to sort1DRecList(nsColList, “colDist”, true) of me
  
set aFirst to first item of aRes
  
set aName to colName of aFirst
  
  
  
–White & Blackを除外(濃い紫などが「Black」と判定される場合への対応)
  
set hitF to false
  
if aName is in {“Black”, “White”} then
    repeat with i in aRes
      set aColD to colDist of i
      
set aColN to colName of i
      
if aColN is not in {“Black”, “White”} and aColD is not equal to 65535 then
        set aName to aColN
        
set hitF to true
        
exit repeat
      end if
    end repeat
    
    
–Black & Whiteの除外処理を行なっても適当なものがない場合の処理
    
if hitF = false then
      set aFirst to first item of aRes
      
set aName to colName of aFirst
    end if
  end if
  
  
return aName
end retColorDomainName

on retCocoaColorList(aColorList, aMax)
  set cocoaColorList to {}
  
repeat with i in aColorList
    set the end of cocoaColorList to i / aMax
  end repeat
  
set the end of cocoaColorList to 1.0
  
return cocoaColorList
end retCocoaColorList

–数値の1D List with Recordをソート
on sort1DRecList(aList as list, aKey as string, ascendingF as boolean)
  set aArray to NSArray’s arrayWithArray:aList
  
set desc1 to NSSortDescriptor’s sortDescriptorWithKey:aKey ascending:ascendingF selector:“compare:”
  
set bList to (aArray’s sortedArrayUsingDescriptors:{desc1}) as list
  
return bList
end sort1DRecList

★Click Here to Open This Script 

2018/01/05 Coloursで指定色がだいたいどんな色なのか推測

オープンソースの「Colours」(By Ben Gordon)をフレームワーク化したcolorsKitを呼び出して、指定色が「だいたいどんな色」かを計算するAppleScriptです。

実行には、colorsKit.frameworkのインストールを必要とします。アーカイブをダウンロードして展開し、~/Library/Frameworksフォルダに入れてください(あくまで自己責任で)。

NSColorでも色のRGBデータの配列でもなんでもよいのですが、それが「だいたいどのような色なのか」を計算してくれる機能はOS内にも各種オープンソース系のプログラムにもなさそうです。

「だいたいGreen」といった判定を行なってほしいケースはいろいろあります。

textedit2.png

のように、他の書類から取得してきた色のリストに対して「Color 1」といった表示を行うよりは「Black」のように表示できたほうがいいに決まっています。

そこで、ざっくりと計算してみることにしてみました。あまり真面目ではない方法で。

赤、青、黄色といった主要な色(Color Domain)を決定し、それらとの色差を計算して一番(距離が)近いものを求め、「赤に近い色だから赤」といった推測を行います。

col22.png
▲上記プログラムに実際に色推測ロジックを組み込んで動かしてみたところ

ただし、推測のロジックが穴だらけなので、白に近い色(薄い水色)などを「白」と判定するケースも多々ありますし、そもそも緑(Green)と青(Blue)の境界色など、判断基準が文化的バックボーンや年齢、職業によりかなりバラツキが出る箇所などがあるので、真剣にやりだすとキリがないし、案外ざっくりこの程度でもいいのかもしれません。

ただ、「灰色」(Gray)「白」(White)「黒」(Black)の判定はもっと主観的に行うべきだと思いますし、カラードメインのリストから上記の色を削除してみると、「もっとひどい計算結果」しか出てきません。水色(Light Blue)を灰色と推測するケースがひどかったので、灰色だけはリストから除去しました。

ColorDomainをもっと細かく設定するべきなのか、何か数値のRange的なもので定義するべきなのか(3次元的に?)、あるいは数値的なデータと知覚される色の違いがあって機械学習的な「データを大量に集めて特徴量を計算するけどロジックはよくわからない」的なやり方で結果を出すのか、いまひとつぱっと思いつきだけでは計算し切れません。そもそも、OS側にこういう機能は用意されていてほしいところです。

色差の計算結果を見ると、

–> {{colObj:(NSCachedRGBColor) NSCalibratedRGBColorSpace 1 1 1 1, colDist:25.499740796083, colName:”White”}, {colObj:(NSCachedRGBColor) NSCalibratedRGBColorSpace 0 0 0 1, colDist:90.533813281336, colName:”Black”}, {colObj:(NSCalibratedRGBColor) NSCalibratedRGBColorSpace 0.98 0 0.02 1, colDist:3.40282346638529E+38, colName:”Red”}, {colObj:(NSCalibratedRGBColor) NSCalibratedRGBColorSpace 0.99 0.99 0.04 1, colDist:3.40282346638529E+38, colName:”Yellow”}, {colObj:(NSCalibratedRGBColor) NSCalibratedRGBColorSpace 0.98 0 0.88 1, colDist:3.40282346638529E+38, colName:”Pink”}, {colObj:(NSCalibratedRGBColor) NSCalibratedRGBColorSpace 0.02 0 0.99 1, colDist:3.40282346638529E+38, colName:”Blue”}, {colObj:(NSCalibratedRGBColor) NSCalibratedRGBColorSpace 0.13 1 0.03 1, colDist:3.40282346638529E+38, colName:”Green”}, {colObj:(NSCalibratedRGBColor) NSCalibratedRGBColorSpace 0.42 0 0.99 1, colDist:3.40282346638529E+38, colName:”Purple”}, {colObj:(NSCalibratedRGBColor) NSCalibratedRGBColorSpace 0.11 0.9 0.99 1, colDist:3.40282346638529E+38, colName:”Light Blue”}}

などとおかしな値(3.40282346638529E+38)になっている箇所があり、その結果として計算結果に疑問が残る箇所がままありました。なんでしょうね、これは。

→ 普通にNSColorで作った色データとColoursの機能を使って作成した色データの色差を計算するとこの値になることが判明。ルーチン内部で色データはColoursの機能を使うように統一したら問題は発生しなくなりました。

AppleScript名:Coloursで指定色がだいたいどんな色なのか推測
– Created 2018-01-03 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “colorsKit” –https://github.com/bennyguitar/Colours

(*
http://piyocast.com/as/archives/5086
*)

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

set {rVal, gVal, bVal} to choose color
set aRes to retColorDomainName(rVal, gVal, bVal, 65535) of me

on retColorDomainName(rVal, gVal, bVal, aColMax)
  set selNSCol to makeNSColorFromRGBAval(rVal, gVal, bVal, aColMax, aColMax) of me
  
  
set colorDomainList to {{colName:“Red”, colValue:{64615, 0, 1767}}, {colName:“Yellow”, colValue:{65530, 65344, 2686}}, {colName:“Pink”, colValue:{64551, 0, 57891}}, {colName:“Blue”, colValue:{1636, 0, 65417}}, {colName:“Green”, colValue:{8866, 65535, 2217}}, {colName:“Black”, colValue:{0, 0, 0}}, {colName:“White”, colValue:{65535, 65535, 65535}}, {colName:“Purple”, colValue:{27963, 0, 65430}}, {colName:“Light Blue”, colValue:{7557, 59465, 65463}}}
  
  
set nsColList to {}
  
repeat with i in colorDomainList
    set aColV to colValue of i
    
set aColN to colName of i
    
copy aColV to {rVal, gVal, bVal}
    
set aColor to makeNSColorFromRGBAval(rVal, gVal, bVal, 65535, 65535)
    
set aDist to (selNSCol’s distanceFromColor:aColor type:2) –ColorDistanceCIE2000
    
set the end of nsColList to {colObj:aColor, colDist:aDist, colName:aColN}
  end repeat
  
  
set aRes to sort1DRecList(nsColList, “colDist”, true) of me
  
set aFirst to first item of aRes
  
set aName to colName of aFirst
  
  
return aName
end retColorDomainName

on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
  
return aColor
end makeNSColorFromRGBAval

–数値の1D List with Recordをソート
on sort1DRecList(aList as list, aKey as string, ascendingF as boolean)
  set aArray to NSArray’s arrayWithArray:aList
  
set desc1 to NSSortDescriptor’s sortDescriptorWithKey:aKey ascending:ascendingF selector:“compare:”
  
set bList to (aArray’s sortedArrayUsingDescriptors:{desc1}) as list
  
return bList
end sort1DRecList

★Click Here to Open This Script 

2018/01/05 Coloursで指定色の輝度をMAX状態に変更した色を取得する

オープンソースの「Colours」(By Ben Gordon)をフレームワーク化したcolorsKitを呼び出して、指定色の輝度を最大状態に変更した色のデータを計算するAppleScriptです。

4471e317-f308-4575-81fa-9cfe7b3bca1a.png

実行には、colorsKit.frameworkのインストールを必要とします。アーカイブをダウンロードして展開し、~/Library/Frameworksフォルダに入れてください(あくまで自己責任で)。

もともと、Coloursにlighten: というメソッドがあり、「指定色の現在の輝度よりも相対的にどの程度明るくするか」という動作内容だったので、最大値(1.0)を指定すると、現在の値+1.0という結果になってしまい、最大値(1.0)を超える数値が返ってきていました。そのため、AppleScript側でNSColorから値を取得する際に最大値チェックを行なっています。

–> Download Framework Binary

AppleScript名:Coloursで指定色の輝度をMAX状態に変更した色を取得する
– Created 2018-01-03 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “colorsKit” –https://github.com/bennyguitar/Colours
–http://piyocast.com/as/archives/5085

property NSColor : a reference to current application’s NSColor

set {rVal, gVal, bVal} to choose color
set aCol to makeNSColorFromRGBAval(rVal, gVal, bVal, 65535, 65535) of me

set bCol to aCol’s lighten:1.0

set cList to retColListFromNSColor(bCol, 65535)
choose color default color cList

on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
  
return aColor
end makeNSColorFromRGBAval

–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

★Click Here to Open This Script 

2018/01/04 Coloursで色バリエーション展開を計算して表示 v2

オープンソースの「Colours」(By Ben Gordon)をフレームワーク化したcolorsKitを呼び出して、指定色のカラーバリエーションを4通り計算して表示するAppleScriptです。

実行には、colorsKit.frameworkのインストールを必要とします。アーカイブをダウンロードして展開し、~/Library/Frameworksフォルダに入れてください(あくまで自己責任で)。スクリプトエディタ上でControl-Command-Rにより実行します。

–> Download Framework Binary

col2.png

col1_resized.png

Coloursが用意しているColorSchemeAnalagous, ColorSchemeMonochromatic, ColorSchemeTriad, ColorSchemeComplementaryの4通りのカラーバリエーション計算を行なってNSColorWellで表示します。

AppleScript名:Colorsで色バリエーション展開を計算して表示 v2
– Created 2017-12-20 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “colorsKit” –https://github.com/bennyguitar/Colours
–http://piyocast.com/as/archives/5081

property NSView : a reference to current application’s NSView
property NSColor : a reference to current application’s NSColor
property NSString : a reference to current application’s NSString
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property NSColorWell : a reference to current application’s NSColorWell
property NSWindowController : a reference to current application’s NSWindowController

property windisp : false

set aWidth to 500
set aHeight to 250

set {rVal, gVal, bVal} to choose color
set aNSCol to makeNSColorFromRGBAval(rVal, gVal, bVal, 65536, 65536) of me

dispCustomView(aWidth, aHeight, “Color Variation Result”, “OK”, 180, aNSCol) of me

on dispCustomView(aWidth as integer, aHeight as integer, aTitle as text, aButtonMSG as text, timeOutSecs as number, aNSCol)
  
  
–Check If this script runs in foreground
  
if not (current application’s NSThread’s isMainThread()) as boolean then
    error “This script must be run from the main thread (Command-Control-R in Script Editor).”
  end if
  
  
set (my windisp) to true
  
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(aWidth / 4, 0, aWidth / 2, 40)))
  
bButton’s setTitle:aButtonMSG
  
bButton’s setButtonType:(current application’s NSMomentaryLightButton)
  
bButton’s setBezelStyle:(current application’s NSRoundedBezelStyle)
  
bButton’s setKeyEquivalent:(return)
  
bButton’s setTarget:me
  
bButton’s setAction:(“clicked:”)
  
  
–NSViewをつくる
  
set aNSV to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aHeight, aWidth))
  
aNSV’s addSubview:bButton
  
aNSV’s setNeedsDisplay:true
  
  
–NSColorWellをつくる
  
repeat with ii from 0 to 3 by 1
    set colorArray1 to (aNSCol’s colorSchemeOfType:ii) as list
    
set the beginning of colorArray1 to aNSCol
    
set tmpLen to (length of colorArray1)
    
set aStep to 0
    
repeat with i in colorArray1
      set aColorWell to (NSColorWell’s alloc()’s initWithFrame:(current application’s NSMakeRect((100 * aStep), (((3 - ii) * 50) + 40), 100, 40)))
      (
aColorWell’s setColor:i)
      (
aColorWell’s setBordered:true)
      (
aNSV’s addSubview:aColorWell)
      
set aStep to aStep + 1
    end repeat
  end repeat
  
  
set aWin to makeWinWithView(aNSV, aWidth, aHeight, aTitle, 1.0)
  
  
set wController to NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
wController’s showWindow:me
  
  
aWin’s makeKeyAndOrderFront:me
  
  
set aCount to timeOutSecs * 10 –timeout seconds * 10
  
repeat aCount times
    if (my windisp) = false then
      exit repeat
    end if
    
delay 0.1
  end repeat
  
  
my closeWin:aWin
  
end dispCustomView

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

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

–close win
on closeWin:aWindow
  repeat with n from 10 to 1 by -1
    (aWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
aWindow’s |close|()
end closeWin:

on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
  
return aColor
end makeNSColorFromRGBAval

★Click Here to Open This Script 

2018/01/04 Numbers上で選択中の列のデータからIPアドレスを抽出

Numbersで選択中の列のセルからデータを取得して、正規表現でIPアドレスとおぼしき文字列をリスト(配列)で抽出するAppleScriptです。

アクセス解析データをWebブラウザからNumbersにコピペした状態で、IPアドレスとして出力される(ドメイン名などが不明)ものを別サービスで位置情報やドメイン情報を計算するために作ったものです。

Numbersの表データ上で処理対象範囲のセルを選択しておいて実行するとスクリプトエディタの結果欄に出力されます。

scrn1.png

開発環境のマシン(MacBook Pro 2012 Retina)で1,000件程度のデータからの抽出が0.08秒程度です。

AppleScript名:Numbers上で選択中の列のデータからIPアドレスを抽出
– Created 2018-01-03 by Takaaki Naganoya
– 2018 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/5080

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

set aList to getSelectionDataFromNumbers() of me
set anArray to NSArray’s arrayWithArray:aList
set aPred to NSPredicate’s predicateWithFormat:“SELF MATCHES ’[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}’”
set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list
–>  {”XX.XX.XX.XXX”, “XXX.XX.XXX.XXX”, “XXX.XXX.XX.XXX”, …..}

on getSelectionDataFromNumbers()
  tell application “Numbers”
    tell front document
      tell active sheet
        tell table 1
          set aList to value of every cell of selection range
        end tell
      end tell
    end tell
  end tell
  
return aList
end getSelectionDataFromNumbers

★Click Here to Open This Script 

2018/01/01 Blogの移転を検討??

2018年2月で設置以来10年になる本Blog。ホスティング時にXserver.jpが提供しているWordPressの自動インストール機能を用いてWordPress ME 2.0.11を導入し、とくにアップデートなしにそのままWordPressの古いバージョンを用いて運用してきました。

WordPressの古いバージョンを使い続けるということは、古いバージョンに存在していたセキュリティーホールが存在し続けるということで、基本的にはいいことではありません。

並行して、新しいバージョンのWordPressをインストールして試していたのですが、新しければ新しいでいろいろ問題があります。

新しいバージョンのWordPressは管理UIがかなりリッチで、使いやすくなっています。その反面、長めの文章や本Blogに掲載しているようなAppleScriptのリスト(HTMLで色分け+URLリンク埋め込み)を投稿すると、Webブラウザごとクラッシュする頻度がものすごく高くなります。

また、本BlogではWordPressのソース自体を(ほんの少し)いじくって、「applescript://」のCustom URL Protocol入りのコンテンツを投稿できるようにしています。標準状態ではこれはできません。

そんなこんなで、WordPressのバージョン移行について検討していたものの、移行リスクを無視できないため、「そのまま」になっていました。

そんな中、ホスティングしているXServer.ne.jpがすべてのアカウントをバーチャルホスティングに移行するとの案内が来ました。

いまどき、バーチャルホスティング自体は珍しくもなんともないのですが、このバーチャルホスティング移行にともない、WordPressの環境そのものが維持されずに新バージョンに変更された場合に、予期しない問題が発生する可能性もあります。

一応、新しいバーチャルホスティングの環境への移行テストサービスなども存在しているので、試してみる価値はあります。ただし、この移行テストで問題が発生した場合には移転なども検討する必要があることでしょう。

カスタムURL Protocolの許可を行うWordPressのプラグインでもあれば、WordPress.comに移転してもよさそうな気もしないではありません。ああ、でもWordPress.comってプラグインの追加インストールができないのか、、、