スタイルつきテキストの中をスタイルつきテキストで検索するAppleScriptです。フォント、サイズ、色の属性を考慮して文字とこれらの属性値が合っている場合に合致しているものとみなします。
最初のバージョンはChatGPTに書かせたもので、実際に動かしてみたら激遅だったので、2パスで検索することで高速化してみました。オリジナルより100倍以上速くなっているはずです。
Step1: 検索対象文字列、検索文字列の両方をテキスト化して、テキストベースで出現情報を計算
Step2: 出現情報をもとにスタイルつきテキスト(NSAttributedString)の書式情報の照合を行い、合致するものを出力
という処理に変更しました。ChatGPTが出力してきたAppleScriptは、1文字ずつチェック範囲を変更しながら書式情報とテキスト情報の照合を行うという「脳筋処理」だったので、少なく見積もっても100倍。データ量が増えれば増えるほど高速化の度合いが上昇します。
AppleScript名:find Styled Text in Styled Text_v1.1.scptd |
— – Created by: Takaaki Naganoya – Created on: 2025/01/12 — – Copyright © 2025 Piyomaru Software, All Rights Reserved — use AppleScript use framework "Foundation" use scripting additions property NSString : a reference to current application’s NSString property NSLiteralSearch : a reference to current application’s NSLiteralSearch property NSMutableArray : a reference to current application’s NSMutableArray — サンプルデータ set targetText to "これはサンプルテキストです。サンプルは重要です。サンプルだよー。サンプルサンプル" set searchText to "サンプル" — 属性付き文字列の作成 set targetAttributedString to current application’s NSMutableAttributedString’s alloc()’s initWithString:targetText set searchAttributedString to current application’s NSMutableAttributedString’s alloc()’s initWithString:searchText — 属性を設定 (例: フォントと色) set targetFont to current application’s NSFont’s fontWithName:"HiraginoSans-W2" |size|:13 set targetColor to current application’s NSColor’s redColor() set searchFont to current application’s NSFont’s fontWithName:"HiraginoSans-W2" |size|:13 set searchColor to current application’s NSColor’s redColor() — 属性を追加 targetAttributedString’s addAttribute:(current application’s NSFontAttributeName) value:targetFont range:{0, targetAttributedString’s |length|()} targetAttributedString’s addAttribute:(current application’s NSForegroundColorAttributeName) value:targetColor range:{0, targetAttributedString’s |length|()} searchAttributedString’s addAttribute:(current application’s NSFontAttributeName) value:searchFont range:{0, searchAttributedString’s |length|()} searchAttributedString’s addAttribute:(current application’s NSForegroundColorAttributeName) value:searchColor range:{0, searchAttributedString’s |length|()} — 属性付き検索を実行 set matches to searchAttributedStringWithAttributes(targetAttributedString, searchAttributedString) of me –> {{location:3, |length|:4}, {location:14, |length|:4}, {location:24, |length|:4}, {location:32, |length|:4}, {location:36, |length|:4}} — NSAttributedStringの属性付き検索を行うハンドラー(複数一致対応) on searchAttributedStringWithAttributes(targetAttributedString, searchAttributedString) set targText to targetAttributedString’s |string|() as string set searchAttributes to searchAttributedString’s attributesAtIndex:0 effectiveRange:(missing value) set searchString to searchAttributedString’s |string|() as string –テキストベースで検索 set strRangeList to searchWordRanges(targText, searchString) of me –あとは、検索箇所の文字書式をループで照合する set matList to {} — 結果を格納するリスト — ループで対象の文字列が含まれる位置の書式情報を検索 repeat with i in strRangeList set j to contents of i set tmpLoc to location of j set tmpLen to |length| of j — 対象範囲の属性を取得 set targetAttributes to (targetAttributedString’s attributesAtIndex:(tmpLoc) effectiveRange:(current application’s NSMakeRange(tmpLoc, tmpLen))) if (targetAttributes = searchAttributes) then set the end of matList to {location:(tmpLoc as integer), |length|:(tmpLen as integer)} — 属性が一致した場合 end if end repeat return matList — 一致したすべての範囲を返す end searchAttributedStringWithAttributes –プレーンテキストベースで検索文字列の出現情報を返す(複数対応) on searchWordRanges(aTargText as string, aSearchStr as string) set aStr to NSString’s stringWithString:aTargText set bStr to NSString’s stringWithString:aSearchStr set hitArray to NSMutableArray’s alloc()’s init() set cNum to (aStr’s |length|()) as integer set aRange to current application’s NSMakeRange(0, cNum) repeat set detectedRange to aStr’s rangeOfString:bStr options:(NSLiteralSearch) range:aRange set aLen to (detectedRange’s |length|) as number if aLen = 0 then exit repeat hitArray’s addObject:detectedRange set aNum to (detectedRange’s location) as number set bNum to (detectedRange’s |length|) as number set aRange to current application’s NSMakeRange(aNum + bNum, cNum – (aNum + bNum)) end repeat return hitArray end searchWordRanges |