Finder上で選択中のMarkdown書類を取得し、ファイル名で昇順ソート(A→Z)して、各Markdown書類中のタイトルのうち最もレベルの高い(重要な)ものを抽出し、まとめてテキストにしてクリップボードに転送するAppleScriptです。
大量にあるMarkdown書類の本文中から一番重要なタイトルを抽出する作業を……さすがに手作業で行うわけには行かなかったので、AppleScriptを書いて処理してみました。ただし、新規に書いた処理はほとんどなく、既存のルーチンの寄せ合わせで構成しています。
Finder上でMarkdown書類を選択した状態で本Scriptを実行すると(Markdown書類以外は除外して)、AppleScriptでMarkdown書類を読み込んで(Markdown書類がUTF-8固定なのでUTF-8を指定して読み込み)、正規表現で書類中のタイトルを抽出し、重要なタイトル(#の個数が少ない)をピックアップ。これをすべての書類について行います。
処理結果をクリップボードに転送します。
最終的には、(手作業で加工して)このようになります。
若干の手作業は発生してしまいますが、このScriptを組まなかったら、とてもその手作業を行う気も起こらなかったわけで、、、
AppleScript名:Finder上で選択中のMarkdown書類をファイル名で昇順ソート(A→Z)して、各書類のタイトル見出しを取得する |
— Created 2018-06-26 by Takaaki Naganoya — 2018 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "Quartz" use mdLib : script "Metadata Lib" version "1.0.0" use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html property |NSURL| : a reference to current application’s |NSURL| property NSArray : a reference to current application’s NSArray property NSString : a reference to current application’s NSString property SMSForder : a reference to current application’s SMSForder property NSIndexSet : a reference to current application’s NSIndexSet property NSPredicate : a reference to current application’s NSPredicate property NSMutableSet : a reference to current application’s NSMutableSet property NSFileManager : a reference to current application’s NSFileManager property NSCountedSet : a reference to current application’s NSCountedSet property NSURLPathKey : a reference to current application’s NSURLPathKey property NSMutableArray : a reference to current application’s NSMutableArray property NSURLNameKey : a reference to current application’s NSURLNameKey property NSSortDescriptor : a reference to current application’s NSSortDescriptor property NSURLIsPackageKey : a reference to current application’s NSURLIsPackageKey property NSRegularExpression : a reference to current application’s NSRegularExpression property NSURLIsDirectoryKey : a reference to current application’s NSURLIsDirectoryKey property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey property NSURLContentModificationDateKey : a reference to current application’s NSURLContentModificationDateKey property NSRegularExpressionAnchorsMatchLines : a reference to current application’s NSRegularExpressionAnchorsMatchLines property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles property NSRegularExpressionDotMatchesLineSeparators : a reference to current application’s NSRegularExpressionDotMatchesLineSeparators load framework –set inFiles to (choose file of type {"pdf"} with prompt "Choose your PDF files:" with multiple selections allowed) tell application "Finder" set inFiles to selection as alias list end tell if inFiles = {} then return –指定のAlias listのうちMarkdown書類のみ抽出 set filRes1 to filterAliasListByUTI(inFiles, "net.daringfireball.markdown") of me –指定のPOSIX path listから、各Markdown書類中の一番重要な見出しを抽出して返す set tRes to listTitlesFromMarkdownDocPathList(filRes1) of me –取得したタイトル一覧リストをテキストに変換 set t2Res to retStrFromArrayWithDelimiter(tRes, return) of me –クリップボードに結果を転送 set the clipboard to t2Res on listTitlesFromMarkdownDocPathList(inFiles) set outList to {} set inFilesSorted to my filesInListSortAscending(inFiles) repeat with i in inFilesSorted –POSIX pathからaliasにパス変換してテキスト読み込み set j to POSIX file (contents of i) set jj to j as alias set aStr to (read jj as «class utf8») set aList to retHeaders(aStr) of me –Markdown書類中の見出しをリストアップ –> {{1, " 2008/3/9 5桁の乱数を生成"}} if aList is not equal to {} then –2D Listの昇順ソート set sortIndexes to {0} –Key Item id: begin from 0 set sortOrders to {true} –ascending = true set sortTypes to {"compare:"} set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:sortIndexes ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list set aCon to contents of second item of first item of resList set the end of outList to aCon end if end repeat return outList end listTitlesFromMarkdownDocPathList on filesInListSortAscending(aliasList as list) set cList to {} repeat with i in aliasList set j to contents of i set aFileName to ((current application’s NSString’s stringWithString:j)’s valueForKeyPath:"lastPathComponent") set the end of cList to {fileName:aFileName, pathDat:j} end repeat set aResList to sortRecListByLabel(cList, "fileName", true) of me –昇順ソート set bResList to (aResList’s valueForKeyPath:"pathDat") as list of string or string return bResList end filesInListSortAscending –Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す on filterAliasListByUTI(aList, targUTI) set newList to {} repeat with i in aList set j to POSIX path of i set tmpUTI to my retUTIfromPath(j) set utiRes to my filterUTIList({tmpUTI}, targUTI) if utiRes is not equal to {} then set the end of newList to j end if end repeat return newList end filterAliasListByUTI –指定のPOSIX pathのファイルのUTIを求める on retUTIfromPath(aPOSIXPath) set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value) if theResult = true then return theValue as string else return theResult end if end retUTIfromPath –UTIリストが指定UTIに含まれているかどうか演算を行う on filterUTIList(aUTIList, aUTIstr) set anArray to NSArray’s arrayWithArray:aUTIList set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr) set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list return bRes end filterUTIList 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 sortRecListByLabel(aRecList as list, aLabelStr as string, ascendF as boolean) set aArray to current application’s NSArray’s arrayWithArray:aRecList set sortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF set sortDescArray to current application’s NSArray’s arrayWithObjects:sortDesc set sortedArray to aArray’s sortedArrayUsingDescriptors:sortDescArray return sortedArray end sortRecListByLabel –見出し抽出用サブルーチン群 on retHeaders(aCon) set tList to {} set regStr to "^#{1,6}[^#]*?$" set headerList to my findPattern:regStr inString:aCon repeat with i in headerList set j to contents of i set regStr2 to "^#{1,6}[^#]*?" set headerLevel to length of first item of (my findPattern:regStr2 inString:j) set the end of tList to {headerLevel, text (headerLevel + 1) thru -1 in j} end repeat return tList end retHeaders 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 — so we can loop through set theResult to {} — we will add to this set theNSString to NSString’s stringWithString:theString repeat with i from 1 to count of items of theFinds set theRange to (item i of theFinds)’s range() set end of theResult to (theNSString’s substringWithRange:theRange) as string end repeat return theResult end findPattern:inString: –リストを指定デリミタをはさんでテキスト化 on retStrFromArrayWithDelimiter(aList, aDelim) set anArray to current application’s NSArray’s arrayWithArray:aList set aRes to anArray’s componentsJoinedByString:aDelim return aRes as list of string or string end retStrFromArrayWithDelimiter |