Archive for the 'NSRegularExpressionSearch' Category

2017/09/06 ツイ4のページで新規連載マンガの画像を取得してPDF化(新規連載のPDF化)v3

Safariで表示中のWebマンガサイト「ツイ4」(更新情報をTwitterに投稿)のマンガを全エピソードダウンロードしてPDFにまとめるAppleScriptです。

実行にあたってはShane StanleyのAppleScript Libraries「BridgePlus」のインストールを必要とします(~/ibrary/Script Librariesフォルダに入れるだけ)。

実行開始時にはSafariでツイ4の特定のマンガのページをオープンしている必要があります。

tui4.png

Safariの最前面のウィンドウからURLやTitle、リンクされている画像の詳細情報を取得し、条件チェックなどを行なったのちに詳細なデータの抽出を行います。

次に、PDFの保存先を選択するダイアログを表示。このさい、デフォルトの保存先を「ピクチャ」フォルダ、ファイル名をマンガのタイトルに指定。

ページにリンクされていた画像(ツイではファイル名はシーケンシャル番号)から番号の情報だけを抽出して最大値、最小値を計算。この範囲で画像のダウンロード、PDFへの追記を行います。ただし、実運用してみたところ、Safariからすべての画像を取得できないようで(非同期表示しているようなので)、とりあえず1〜9999までの番号の画像を順次ダウンロードし、画像が存在しなければ処理を終了しています。

画像をダウンロードするたびにPDFに追記していますが、このあたりは途中でエラーが出て停止してもそれまでの処理内容が保存されることを意図してのことです。SSD搭載機では問題のない処理ですが、HDD搭載機では若干遅く感じるかもしれません(もはやHDD搭載機が身の回りにないので不明)。

これまでは、マンガの新規連載がはじまるとcurlコマンドで画像をダウンロードしてPDFに連結する作業を手で行なっていたのですが(誰も頼んでねえよ)、新規連載が増えたので自動化してみました。それでもありあわせの部品を組み合わせただけなので、それほど手間はかかっていません。

本Scriptとは別に更新された差分をPDFに連結するAppleScriptを作って日々実行し、大きな画面でブラウズするのに役立てています。割とこういう、ごくごく私的なScriptで野心的な処理を先行してテストしているものです。

AppleScript名:ツイ4のページで新規連載マンガの画像を取得してPDF化(新規連載のPDF化)v3
– Created 2016-09-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “QuartzCore”
use BridgePlus : script “BridgePlus”
–http://piyocast.com/as/archives/4808

property SMSForder : a reference to current application’s SMSForder
property |NSURL| : a reference to current application’s |NSURL|
property NSURLRequest : a reference to current application’s NSURLRequest
property NSURLConnection : a reference to current application’s NSURLConnection
property NSArray : a reference to current application’s NSArray
property NSFileManager : a reference to current application’s NSFileManager
property NSNumberFormatter : a reference to current application’s NSNumberFormatter
property NSPredicate : a reference to current application’s NSPredicate
property PDFPage : a reference to current application’s PDFPage
property PDFDocument : a reference to current application’s PDFDocument
property NSURLRequestUseProtocolCachePolicy : a reference to current application’s NSURLRequestUseProtocolCachePolicy
property NSNumberFormatterPadBeforePrefix : a reference to current application’s NSNumberFormatterPadBeforePrefix
property NSImage : a reference to current application’s NSImage
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSNumber : a reference to current application’s NSNumber
property NSRegularExpressionDotMatchesLineSeparators : a reference to current application’s NSRegularExpressionDotMatchesLineSeparators
property NSRegularExpressionAnchorsMatchLines : a reference to current application’s NSRegularExpressionAnchorsMatchLines
property NSRegularExpression : a reference to current application’s NSRegularExpression
property NSString : a reference to current application’s NSString

property theTargetSite : “http://sai-zen-sen.jp/”

tell application “Safari”
  if (count every document) = 0 then
    display notification “Safari does not open web page”
    
return
  end if
  
  
set docTitle to (do JavaScript “document.title” in front document) –Title
  
  
tell front document –URL
    set aURL to URL
  end tell
end tell

if aURL does not start with theTargetSite then
  display notification “This site is not the target”
  
return
end if

–Safariの最前面のウィンドウから画像リンクをすべて取得(Height, Width, URL)
set aList to getImageSizeAndURLOfFrontSafariDocument() of me

–取得した画像情報の2D Listをサイズで降順ソート
load framework –Force loading BridgePlus framework
set sortIndexes to {0, 1} –Key Item id: begin from 0
set sortOrders to {false, false}
set sortTypes to {“compare:”, “compare:”}
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:sortIndexes ascending:sortOrders sortTypes:sortTypes |error|:(missing value))

–画像が取得できなかったら処理終了
if (resList as list) = {} then
  display notification “There is no images on this page”
  
return –No Result
end if

–最大サイズの画像情報を取得する(おそらくマンガ)
set {maxHeight, maxWidth, maxURL} to contents of first item of (resList as list)

set aNSURL to |NSURL|’s URLWithString:maxURL
set aNSURLfilename to (aNSURL’s lastPathComponent())
set aNSURLpure to aNSURL’s URLByDeletingLastPathComponent()
set aNSURLextension to aNSURLfilename’s pathExtension() as string
set aNSURLfilenameLen to (aNSURLfilename’s stringByDeletingPathExtension())’s |length|() as integer –画像ファイル名から拡張子を除去した部分の文字列長

–画像情報リストを画像サイズで抽出
set maxHeightStr to (maxHeight as integer) as string
set maxWidthStr to (maxWidth as integer) as string
set thePred to NSPredicate’s predicateWithFormat:(“(self[0] == “ & maxHeightStr & “) AND (self[1] == “ & maxWidthStr & “)”)
set bArray to (resList’s filteredArrayUsingPredicate:thePred) as list

–URLからファイル名の数値部分のみ抽出
set imageArray to current application’s NSMutableArray’s new()
repeat with i in bArray
  set j to contents of last item of i –(Image URL)
  
set aTmpURL to (|NSURL|’s URLWithString:j)
  
set aTmpfilename to (aTmpURL’s lastPathComponent()) as string
  
set numStr to first item of (my findPattern:(“^\\d{1,” & (aNSURLfilenameLen as string) & “}”) inString:aTmpfilename)
  
set jj2 to (SMSForder’s transformedFrom:numStr ICUTransform:“Fullwidth-Halfwidth” inverse:false) as integer
  (
imageArray’s addObject:jj2)
end repeat

–ファイル名から抽出した数値の最小値と最大値を求める。ただ、実運用したらWeb側から画像をすべて取得されない(非同期読み込みを行なっているらしい)ケースがあったため、ここの値は参考値程度にしか使えなかった
set maxRes to (imageArray’s valueForKeyPath:“@max.self”)’s intValue() –最大値
set minRes to (imageArray’s valueForKeyPath:“@min.self”)’s intValue() –最小値
log {minRes, maxRes}

–PDFのファイル名と場所をユーザーに確認
set pdfFile to (choose file name with prompt “Select PDF Name & Location” default location (path to pictures folder) default name (docTitle & “.pdf”))
set pdfFilePOSIX to POSIX path of pdfFile
set newFilePath to current application’s NSString’s stringWithString:pdfFilePOSIX

–Make Blank PDF
set aPDFdoc to PDFDocument’s alloc()’s init()

–Download each image and append to blank PDF
set insCount to 1 –画像ダウンロード用のページ数(Loop Counter)とPDF連結用のページ番号(insCount)を分離

–repeat with i from minRes as integer to maxRes as integer
repeat with i from 1 to 9999
  –URL部品の連結
  
set aFILENAME to numToZeroPaddingStr(i, aNSURLfilenameLen, “0″) of me
  
set aFULLURL to (aNSURLpure’s absoluteString() as string) & (aFILENAME as string) & “.” & (aNSURLextension as string)
  
set aURL to (|NSURL|’s URLWithString:aFULLURL)
  
  
–URL(画像)をダウンロード
  
set {uRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me
  
  
if uRes = true then
    display notification “Episode “ & (i as string) & ” exists…”
    
set bImage to (NSImage’s alloc()’s initWithData:aData)
    (
aPDFdoc’s insertPage:(PDFPage’s alloc()’s initWithImage:bImage) atIndex:(insCount - 1))
    (
aPDFdoc’s writeToFile:newFilePath) –1Page更新するたびにファイル保存
    
set changedF to true –PDFにページが追記されたことを検出
  else
    display notification “No more new episode….”
    
exit repeat
  end if
  
  
set insCount to insCount + 1
end repeat

–FinderコメントにURLを記入
tell application “Finder”
  set comment of (pdfFile as alias) to (aNSURLpure’s absoluteString() as string)
end tell

–生成したPDFをオープン。ビューワー経由ではなくFinder経由でopen命令を送って表示
tell application “Finder”
  open (pdfFile as alias)
end tell
–ここで処理終了

—————

on getImageSizeAndURLOfFrontSafariDocument()
  set aList to {}
  
  
tell application “Safari”
    if its running then
      if (count every document) = 0 then return {}
      
set aRes to (do JavaScript “document.images.length” in front document)
      
      
repeat with i from 0 to (aRes - 1)
        set aHeight to do JavaScript ((“document.images[” & i as string) & “].height”) in front document
        
set aWidth to do JavaScript ((“document.images[” & i as string) & “].width”) in front document
        
set aSRC to do JavaScript ((“document.images[” & i as string) & “].src”) in front document
        
set the end of aList to {aHeight, aWidth, aSRC}
      end repeat
    end if
  end tell
  
  
return aList
end getImageSizeAndURLOfFrontSafariDocument

on findPattern:thePattern inString:theString
  set theOptions to ((NSRegularExpressionDotMatchesLineSeparators) as integer) + ((NSRegularExpressionAnchorsMatchLines) as integer)
  
set theRegEx to 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
  
set theResult to {}
  
set theNSString to NSString’s stringWithString:theString
  
  
repeat with i in theFinds
    set theRange to (contents of i)’s range()
    
set end of theResult to (theNSString’s substringWithRange:theRange) as string
  end repeat
  
return theResult
end findPattern:inString:

–1D List(文字)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DList:theList ascOrder:aBool
  set aDdesc to NSSortDescriptor’s sortDescriptorWithKey:“self” ascending:aBool selector:“localizedCaseInsensitiveCompare:”
  
set theArray to NSArray’s arrayWithArray:theList
  
return (theArray’s sortedArrayUsingDescriptors:{aDdesc}) as list
end sort1DList:ascOrder:

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

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (NSURLRequest’s requestWithURL:aURL cachePolicy:(NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to 404
  end if
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

–指定PDFのページ数をかぞえる(10.9対応。普通にPDFpageから取得)
–返り値:PDFファイルのページ数(整数値)
on pdfPageCount(aFile)
  set aFile to POSIX path of aFile
  
set theURL to |NSURL|’s fileURLWithPath:aFile
  
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:theURL
  
set aRes to aPDFdoc’s pageCount()
  
return aRes as integer
end pdfPageCount

★Click Here to Open This Script 

2015/10/13 数字以外を削除して返す

与えられた文字列のうち、数字以外を削除して返すAppleScriptです。

正規表現で数字以外をヌルに置換して返します。スペースを許容するものと、スペースと改行を許容するものも作っておきました。

後で加工することを考えると、地味にスペースも取り出せると処理が楽だったので、、、

AppleScript名:ASOCで数字以外を削除して返す
– Created 2015-10-13 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set aStr to "<< 98158999992
>>"

set bStr to returnNumberCharsOnly(aStr)
–>  "98158999992"

set cStr to returnNumberCharsAndSpaceOnly(aStr)
–> " 98158999992 "

set dStr to returnNumberCharsAndSpaceAndReturnOnly(aStr)
–>
(*
" 98158999992
"
*)

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

on returnNumberCharsAndSpaceOnly(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 returnNumberCharsAndSpaceOnly

on returnNumberCharsAndSpaceAndReturnOnly(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 returnNumberCharsAndSpaceAndReturnOnly

★Click Here to Open This Script 

2015/09/09 続・伏字文字列を作成する

ここに掲載するScriptのMACアドレスやらシリアル番号やらを伏字にするため「だけに」作ったAppleScript。1行のテキストのうちの数文字だけ伏字にするため、速度も何も重視していなかったほぼ作り捨てレベルのこのScriptに技術的な課題を見出してしまった人物がいます。

Shane Stanleyです。なぜだ〜(^ー^;;。

自分が作ったPure AppleScript版(A)、Shaneによる英数字しか考慮していないASOC版(B)、Shaneによる2バイト文字も考慮したASOC版(C)の3つのバージョンが登場。

実行速度は、

 (A):◼️◼️ 0.0001976 sec
 (B):◼️◼️◼️◼️ 0.00038 sec
 (C):◼️◼️◼️◼️◼️◼️◼️◼️◼️◼️ 0.001 sec

ぐらい違います(◼️が少ない方が速い)。

v3vsv4.png

伏字と考えると分かりにくいですが(日本語の伏字は、「伏せてもなぜか意味が分かる、ハイレベルな文芸活動」だったりするので)、「文字グループを指定した文字置換」ととらえると、技術的にツッコミを入れるべき対象に見えるかもしれません。

AppleScript名:伏字文字列を作成する v3
– Created 2015-09-09 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aStr to “This is my secret information.”
set bStr to makeUnprintableChars(aStr)
–>  ”Xxxx xx xx xxxxxx xxxxxxxxxxx.”

on makeUnprintableChars(aStr)
  set anNSString to current application’s NSString’s stringWithString:aStr
  
set anNSString to anNSString’s stringByReplacingOccurrencesOfString:“[A-Z0-9]” withString:“X” options:(current application’s NSRegularExpressionSearch) range:{0, anNSString’s |length|()}
  
set anNSString to anNSString’s stringByReplacingOccurrencesOfString:“[a-z]” withString:“x” options:(current application’s NSRegularExpressionSearch) range:{0, anNSString’s |length|()}
  
return anNSString as text
end makeUnprintableChars

★Click Here to Open This Script 

AppleScript名:伏字文字列を作成する v4
– Created 2015-09-09 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aStr to “これは秘密のInformationです。” –Alphabet & Numeric以外でも置換可能
set bStr to makeUnprintableChars(aStr)
–>  ”xxxxxxXxxxxxxxxxxxx。”

on makeUnprintableChars(aStr)
  set anNSString to current application’s NSString’s stringWithString:aStr
  
set anNSString to anNSString’s stringByReplacingOccurrencesOfString:“[\\p{Lu}\\p{Lt}\\p{Nd}]” withString:“X” options:(current application’s NSRegularExpressionSearch) range:{0, anNSString’s |length|()}
  
set anNSString to anNSString’s stringByReplacingOccurrencesOfString:“[\\p{Ll}\\p{Lm}\\p{Lo}]” withString:“x” options:(current application’s NSRegularExpressionSearch) range:{0, anNSString’s |length|()}
  
return anNSString as text
end makeUnprintableChars

★Click Here to Open This Script 

2014/11/22 Keynote 6.5で各スライドのタイトル、マスタースライド名を取得してデータ化

Keynote 6.5で作成中の書類(開発中のシステムの仕様書)から、各ページタイトルを取得。さらに各スライド(ページ)のマスタースライド名を取得しておいて、目次の文字の大きさに違いをつけようとして、データを作成するAppleScriptの試作品です。

実際に、一般的なアプリケーションであるKeynoteをコントロールしつつ、データ処理をASOCベースのサブルーチンで行わせてみました。

40ページ強あるKeynoteのデータの処理を1秒以下で行えます(MacBook Pro Retina mid 2012)。

また、各スライド(ページ)のマスタースライド名については、出現頻度をカウントし、出現頻度の少ないものが各章のトビラであると仮定して、各タイトルにレベル設定(トビラページは1、通常ページは2)を行っています。

実際に、OmniGraffleではこうした処理(各ページのタイトルを求めて、目次ページを動的に作成してすべての項目に実際のページへのリンクを設定)をすべてAppleScriptで行っていますが(PDFに書き出したときに便利)・・・OmniGraffleで行うよりも、(ユーザーの多い)Keynote上で行えたほうが便利です。

Keynote 6.5もけっこうAppleScript対応機能が向上してきてはいるのですが、たとえばテキストオブジェクトを生成しても・・・左寄せ/センタリング/右寄せを指定できないとか、フォントと文字サイズも設定できないとか(ここはまだ試行錯誤の余地あり)、他のスライド(ページ)へのリンク設定が行えないなど、実践的な処理を記述するためには「いまひとつ」な印象です。

とはいえ、Keynote 6.5のAppleScript用語辞書を見ていると、オブジェクトにScript Labelを(将来的に)設定できるように考えられているなど、楽しみです(グラフ方面は手付かずだったり)。

Keynoteには、早く完全体になってほしいところです(永遠に未完成ということはないと思いたいですが、なかなか進捗しないですね)。

ちなみに、Keynoteへのtellブロック内でcocoaの機能にアクセスするコードを直接書くと、実行時にScript Editorがクラッシュするなどなかなかたいへんでした。ASOCのコードは通常のアプリケーションへのアクセスと分けたほうが得策のようです。

AppleScript名:keynote_test
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

property sPage : 3 –1ページ目が表紙、2ページ目が目次として3ページ目以降を処理対象とする

–最前面のドキュメントを取得する
tell application “Keynote”
  set aDocRef to front document
end tell

set tList to retKeynoteSlideTitleFrom(3, aDocRef) of me
–> {”システム概要”, “ハードウェア構成概要”, “ソフトウェア構成概要”,….}

–ドキュメント中の3ページ以降のslideの各マスタースライドの名称を取得して、各マスタースライドの出現頻度を取得して昇順ソート
set bList to retKeynoteSlideBaseSlideNameFrom(sPage, aDocRef) of me
–> {{”タイトル(中央)”, 8}, {”タイトル(上)”, 32}}–{マスタースライド名, 登場頻度カウント}

set {masterList, freqList} to conv2dListTo1dLists(bList) of me
–> {{”タイトル(中央)”, “タイトル(上)”}, {8, 32}}

set tOutList to {}

tell application “Keynote”
  tell aDocRef
    repeat with i from sPage to (count every slide)
      tell slide i
        –Title
        
set aIndex to (i - sPage + 1)
        
set aTitle to contents of item aIndex of tList
        
        
–Base Slide
        
set aBaseName to name of base slide
        
set aLevel to offseOfList(masterList, aBaseName) of me
        
        
set the end of tOutList to {aTitle, aLevel}
        
      end tell
    end repeat
  end tell
end tell

return tOutList
–> {{”システム概要”, 1}, {”ハードウェア構成概要”, 2}, {”ソフトウェア構成概要”, 2}, {”プログラム概要”, 2}, {”プログラム呼称一覧”, 2}, ….}
–1=マスタースライドが”タイトル(中央)”
–2=マスタースライドが “タイトル(上)”

–List中の指定項目の出現位置を返す(複数ヒットした場合には最初の項目番号)。1はじまりのAS仕様のインデックスを使用
on offseOfList(aList, anItem)
  set aResList to (current application’s SMSFord’s indexesOfItem:anItem inArray:(aList) inverting:false) as list
  
set aRes to (first item of aResList)
  
return (aRes + 1)
end offseOfList

–指定ページ(slide)から末尾までの各ページのTitleを取得して返す
on retKeynoteSlideTitleFrom(startPageNum as integer, aDocRef)
  
  
set tList to {}
  
  
try
    –全ページ(slide)のtitleを一括で取得するのが一番高速
    
tell application “Keynote”
      tell aDocRef
        set sCount to count every slide
        
        
if sCount < startPageNum then error
        
if startPageNum < 1 then return {}
        
        
set tList to object text of default title item of every slide
      end tell
    end tell
  on error
    return {}
  end try
  
  
–取得したタイトルから、前後の改行、前後の空白、および途中に入っている改行を削除する
  
set t2List to {}
  
repeat with i in tList
    set j to contents of i
    
set jj to cleanUpText(j) of me
    
set jj to cleanUpCRLF(jj) of me
    
set the end of t2List to jj
  end repeat
  
  
  
  
–一括取得した内容を適宜加工して返すのがベスト
  
set ttList to contents of items startPageNum thru -1 of t2List
  
  
return ttList
  
end retKeynoteSlideTitleFrom

–文字列の前後の改行と空白文字を除去
on cleanUpText(someText)
  set theString to current application’s NSString’s stringWithString:someText
  
set theString to theString’s stringByReplacingOccurrencesOfString:” +” withString:” “ options:(current application’s NSRegularExpressionSearch) range:{location:0, |length|:length of someText}
  
set theWhiteSet to current application’s NSCharacterSet’s whitespaceAndNewlineCharacterSet()
  
set theString to theString’s stringByTrimmingCharactersInSet:theWhiteSet
  
return theString as text
end cleanUpText

–文字置換
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’s ASify()) as string
  
return cString
end repChar

–指定文字列からCRLFを除去
on cleanUpCRLF(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set bString to aString’s stringByReplacingOccurrencesOfString:(string id 10) withString:“” –remove LF
  
set cString to bString’s stringByReplacingOccurrencesOfString:(string id 13) withString:“” –remove CR
  
set dString to (cString’s ASify()) as string
  
return dString
end cleanUpCRLF

–2D Listを1D Listに変換
on conv2dListTo1dLists(aList as list)
  
  
set newList to {}
  
set aLen to length of first item of aList
  
  
repeat aLen times
    set the end of newList to {}
  end repeat
  
  
  
repeat with i in aList
    repeat with ii from 1 to aLen
      set the end of item ii of newList to (item ii of i)
    end repeat
  end repeat
  
  
return newList
  
end conv2dListTo1dLists

–指定ページ(slide)から末尾までの各ページのbase slide名を取得してユニーク化して返す
on retKeynoteSlideBaseSlideNameFrom(startPageNum, aDocRef)
  
  
set aList to {}
  
  
tell application “Keynote”
    tell aDocRef
      set sCount to count every slide
      
if sCount < startPageNum then error
      
      
repeat with i from startPageNum to sCount
        tell slide i
          set aBase to name of base slide
          
set the end of aList to aBase
        end tell
      end repeat
      
    end tell
  end tell
  
  
  
–結果をユニーク化する
  
set aArray to current application’s NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:“@distinctUnionOfObjects.self”
  
  
set bList to bArray’s ASify() as list
  
–> {1, 1.1, 2, 3, 4}
  
  
  
–Base Slide名の出現頻度を調べる
  
set cList to {}
  
  
repeat with i in bList
    set aName to contents of i
    
set aCount to countSpecifiedItem(aList, aName) of me
    
set the end of cList to {aName, aCount}
  end repeat
  
  
  
–出現頻度(aCount)をキーにして昇順ソート
  
set dList to sort2DList(cList, 2, {true}) of me
  
  
return dList
  
end retKeynoteSlideBaseSlideNameFrom

–リスト中の指定項目の出現回数を返す
on countSpecifiedItem(aList, countItem)
  set aRes to (current application’s SMSFord’s indexesOfItem:countItem inArray:aList inverting:false) as list
  
set aCount to length of aRes
  
return aCount
end countSpecifiedItem

–2D Listをソート
on sort2DList(aList as list, sortIndexes as list, sortOrders as list)
  
  
–index値をAS流(アイテムが1はじまり)からCocoa流(アイテムが0はじまり)に変換
  
set newIndex to {}
  
repeat with i in sortIndexes
    set j to contents of i
    
set j to j - 1
    
set the end of newIndex to j
  end repeat
  
  
–Sort TypeのListを作成(あえて外部から指定する内容でもない)
  
set sortTypes to {}
  
repeat (length of sortIndexes) times
    set the end of sortTypes to “compare:”
  end repeat
  
  
–Sort
  
set resList to (current application’s SMSFord’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list
  
  
return resList
  
end sort2DList

★Click Here to Open This Script