青空文庫のテキストのルビタグをすべて削除するAppleScriptです。
CotEditorでオープン中の青空文庫のテキストからルビタグを削除し、元のドキュメントに置換結果を反映させます。
テストに使用したのは、夏目漱石の「こころ」のテキストです。上記ページの「テキストファイル(ルビあり)」をダウンロードして、Zipアーカイブを展開して使用しました。
ファイルサイズ373KB、当該部分4,570箇所。開始文字「《」、終了文字「》」で囲われたエリアをすべて削除するという、AppleScriptにはあからさまに不得意そうな処理で、最初に書いたAppleScriptでは1分半以上かかっていました。内容は、おおよそ常識的なサブルーチンを組み合わせてループで回しただけです。わざと遅くなるように組んだりはしていません。
これを、
(1)CotEditorからの文章テキストの取得
(2)置換当該箇所のリストアップ
(3)文字置換
(4)CotEditorへの文章テキストの転送
の4つのステージに分け、それぞれ処理時間を計測。すると、(1)、(2)、(4)については1秒かかるかかからないかぐらいの速度で実行していることが判明。圧倒的に(3)文字置換の処理に時間がかかっていました。
もともと文字置換には、AppleScript処理系最速のtext item delimitersを用いるサブルーチンを使用していました。これ以上、この方向に頑張っても速く処理することはできません。一応、ダメ元で4,570個の要素を持つ巨大なtext item delimitersを作成し一括処理できないか試してみたものの、さすがに処理系のキャパシティを超過しているようで処理が戻ってきません(迷走状態)。完全にお手上げです。
そこで、AppleScriptの処理系に依存したtext item delimitersによる処理をやめ、メモリ管理効率がよくないAppleScriptのstring型のデータで保持することをやめ、置換のたびにAppleScriptのstring型に変換(cast)することをやめ、置換中は最初から最後までNSMutableStringで管理するようにしました。
このように大幅に書き換えたところ、トータルで3.58秒で処理終了するようになりました。
すべての置換が終了したあとにNSMutableStringをAppleScriptのstringに変換し、CotEditorの最前面のドキュメントに結果を転送しています。
AppleScript名:青空文庫のテキストのルビタグを削除 |
— – Created by: Takaaki Naganoya – Created on: 2019/03/18 — – Copyright © 2019 Piyomaru Software, All Rights Reserved — use AppleScript version "2.5" use scripting additions use framework "Foundation" property NSScanner : a reference to current application’s NSScanner property NSOrderedSet : a reference to current application’s NSOrderedSet property NSMutableString : a reference to current application’s NSMutableString property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch tell application "CotEditor" tell front document set aCon to contents end tell end tell set bCon to trimStrFromTo(aCon, "《", "》") of me tell application "CotEditor" tell front document set contents to bCon end tell end tell –開始文字と終了文字に囲われた文字列をすべて削除する on trimStrFromTo(aParamStr, fromStr, toStr) script hsAry property anArray : {} property curStr : "" end script set theScanner to NSScanner’s scannerWithString:aParamStr set (anArray of hsAry) to {} repeat until (theScanner’s isAtEnd as boolean) set {aResult, theKey} to theScanner’s scanUpToString:fromStr intoString:(reference) theScanner’s scanString:fromStr intoString:(missing value) set {bResult, theValue} to theScanner’s scanUpToString:toStr intoString:(reference) if theValue is missing value then set theValue to "" theScanner’s scanString:toStr intoString:(missing value) set the end of (anArray of hsAry) to (fromStr & theValue & toStr) end repeat –Case: Not found if length of (anArray of hsAry) = 0 then return aParamStr –Uniquefy set (anArray of hsAry) to makeUniqueListFrom((anArray of hsAry)) of me –Replace strings as NSMutableString set (curStr of hsAry) to NSMutableString’s stringWithString:aParamStr repeat with i in (anArray of hsAry) set j to contents of i set (curStr of hsAry) to ((curStr of hsAry)’s stringByReplacingOccurrencesOfString:(j) withString:"" options:(NSRegularExpressionSearch) range:{location:0, |length|:((curStr of hsAry)’s |length|())}) end repeat return (curStr of hsAry) as string end trimStrFromTo –1D Listをユニーク化(重複削除) on makeUniqueListFrom(theList) set theSet to NSOrderedSet’s orderedSetWithArray:theList return (theSet’s array()) as list end makeUniqueListFrom |