指定のPDFの本文テキストを取り出し、文字数をカウントするAppleScriptです。
▲「AppleScriptによるWebブラウザ自動操縦ガイド」の文字数をカウントしようとした
300ページを超える、わりと大きな本のPDFデータから文字を取り出したので、それなりの文字数になりました。つまり、Cocoaの有効活用を考えないとデータサイズ的につらそうなデータ量になることが予想されました。
当初、(文字処理については)Cocoaの機能をあまり活用しないv2を作ったものの、処理にM1 Mac miniで30秒ほどかかりました。すべてNSStringのまま(AppleScriptのstringに型変換せずに)処理してみたら、案の定、大幅に処理が高速化され6秒あまりで完了。
ただし、両者でカウントした文字数が1万文字ぐらい違っていたので、(PDFから取得した文字の)Unicode文字のNormalize方式を変更したところ、両者で同じ結果になりました。また、処理速度に改変前から大幅な変化はありませんでした。
文字数を数えるという処理だとさすがにデータ数が膨大になるため、NSStringで処理したほうがメリットが大きいようです。
# あれ? 5文字ぐらい違う、、、、絵文字の部分か?
AppleScript名:指定のPDFの本文テキストの文字数を数える v2 |
use AppleScript version "2.8" –macOS 12 or later use framework "Foundation" use framework "PDFKit" –Comment Out under macOS 11 –use framework "Quartz"–Uncomment under macOS 11 use scripting additions script spd property cRes : "" property cList : {} end script set (cRes of spd) to "" set (cList of spd) to {} set (cRes of spd) to getTextFromPDF(POSIX path of (choose file of type {"pdf"})) of me set (cList of spd) to current application’s NSArray’s arrayWithArray:(characters of (cRes of spd)) set cLen to (cList of spd)’s |count|() return cLen –> 256137 (24.763sec) on getTextFromPDF(posixPath) set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL return (thePDF’s |string|()’s precomposedStringWithCompatibilityMapping()) as text end getTextFromPDF |
AppleScript名:指定のPDFの本文テキストの文字数を数える v3 |
use AppleScript version "2.8" –macOS 12 or later use framework "Foundation" use framework "PDFKit" –Comment Out under macOS 11 –use framework "Quartz"–Uncomment under macOS 11 use scripting additions script spd property cRes : "" property cList : {} end script set (cRes of spd) to "" set (cList of spd) to {} set (cRes of spd) to getTextFromPDF(POSIX path of (choose file of type {"pdf"})) of me set cLen to (cRes of spd)’s |length| return cLen as anything –> 256142 (6.28 sec) on getTextFromPDF(posixPath) set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL return (thePDF’s |string|()’s precomposedStringWithCompatibilityMapping()) end getTextFromPDF |
わずかとはいえ、違いが出ていることは確かなので、1つのPDFに対して2つの処理方法でテキストを取り出して、それを配列に入れて集合演算して差分をとってみました。M1でも処理に1分少々かかりました。こういう処理は、M1 MaxでもM1 Ultraでも所要時間は変わらないことでしょう(逆にM1の方が処理時間が短い可能性まである)。
どうやら改行コードの解釈で文字数カウント結果に違いが出たようです。
AppleScript名:テキストの抽出方法による文字数の相違チェック.scptd |
use AppleScript version "2.8" –macOS 12 or later use framework "Foundation" use framework "PDFKit" –Comment Out under macOS 11 –use framework "Quartz"–Uncomment under macOS 11 use scripting additions script spd property cRes : "" property cList : {} end script set (cRes of spd) to "" set (cList of spd) to {} set docPath to POSIX path of (choose file of type {"pdf"}) set (cRes of spd) to getTextFromPDF1(docPath) of me set (cList of spd) to characters of (cRes of spd) set anArray to current application’s NSArray’s arrayWithArray:(cList of spd) set bStr to getTextFromPDF2(docPath) of me set bArray to current application’s NSMutableArray’s new() set bLen to (bStr’s |length|) as anything repeat with i from 0 to (bLen – 1) set tmpStr to (bStr’s substringWithRange:(current application’s NSMakeRange(i, 1))) (bArray’s addObject:(tmpStr)) end repeat set aRes to diffLists(anArray, bArray) of me set bRes to diffLists(bArray, anArray) of me return {aRes, bRes} on getTextFromPDF1(posixPath) set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL return (thePDF’s |string|()’s precomposedStringWithCompatibilityMapping()) as text end getTextFromPDF1 on getTextFromPDF2(posixPath) set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL return (thePDF’s |string|()’s precomposedStringWithCompatibilityMapping()) end getTextFromPDF2 –1D List同士のdiffを計算する on diffLists(aList, bList) set aSet to current application’s NSMutableSet’s setWithArray:aList set bSet to current application’s NSMutableSet’s setWithArray:bList set aRes to calcSetDifference(aSet, bSet) of me return aRes end diffLists –2つのNSMutableSetの補集合を求める on calcSetDifference(aSet, bSet) aSet’s minusSet:bSet –補集合 set aRes to aSet’s allObjects() as list return aRes end calcSetDifference |