« Mac版SafariのiCloudタブの中身は削除できるのか | トップページ | メモ.appエクスポートAppleScriptを作った[更新] »

2012年8月20日 (月)

メモ.appインポートAppleScriptを作ってみた[更新]

(2015/10/06追記:この記事に記載されている Apple Script は OS X 10.10 Yosemite 以前にのみ対応している。OS X El Capitan 対応版はこちら)


短いテキストを iPhone と同期するために、これまで Evernote を活用してきた。

だが、Evernote は PIXELA 社の Capty TV と同時起動ができない(画面キャプチャーアプリと認識され、テレビの受信や録画した番組の再生をストップしてしまう)ので、Evernote をログイン項目に入れてしまうと、Capty TV による留守録に支障を来す。そのため、Evernote を常駐はさせておらず、使用のつど立ち上げることにしているのだが、残念なことに Evernote の起動速度は快速とは言いがたく、ちょっとメモを参照しようとするたびに10秒ほど待たなければならないのである。

そこで、かねてから Mountain Lion を導入した暁には付属の メモ.app を活用しようと考えていた。実際に導入してみると、ページ内の検索ができないという欠点はあるものの(苦笑)、短いテキストをさっと書き留めたり参照したりするには意外と役に立つアプリだ。

メモ.app をちょっと触っただけは気づかないかもしれないが、各メモをフォルダーに分けて整理する機能が備わっている。デフォルトではフォルダーリストが非表示になっており、メモリストの右下にあるボタンを押せば表示される。

フォルダーを1つも作っていなければ、フォルダーリストには「iCloud のすべて」と「メモ」という二つのフォルダーのみが存在する。但し、「iCloud のすべて」はフォルダーではなく、すべてのメモを一括表示するためのものであり、実際には「メモ」ただ1つしかない。

メモリストの「iCloud」にマウスポインターを合わせるとその右横に「+」マークが表示される。それをクリックすると、フォルダーを作成することができる。

筆者は、そのフォルダーの中に、1つのテキストファイルを一定の法則により分割して複数のメモとして簡単にインポートしたい、と考えた。そこで作成したのが下に掲載する AppleScript である。

なお、筆者はプログラミングの専門教育を受けたわけではないので、お世辞にもきれいなスクリプトとは言えない(笑)。ただ、AppleScript の熟練者でこれからメモ.app によるスクリプティングを始めようという方々にとっては多少は参考になる部分もあるのではないかとは思う(メモ.app 内における「note」や「folder」の扱いなど)。ちなみに、「メモ」フォルダーは日本語環境ではメモと表示されるが、実体は「Notes」フォルダーという名前である。AppleScript で扱う際は必ず「folder "Notes"」 と指定しなければならない。

断っておくが、以下のスクリプトを実行して何らかの損害を被ったとしても、筆者はいっさいの責任を負わない。あしからずご了承願いたい。

なお、使用方法は記事の最後に掲載している。



(更新2013/03/29)


 (*
 ToDo 一行目に""の字が含まれている項目をインポートする場合の調整(現在は暫定対応中)
 *)
 (*
 メモ.app にテキストファイルの内容をインポートするスクリプト。
 指定した区切り文字列でテキストファイルを分割してそれぞれを1つのメモとしてインポートする。
 
 なお、当スクリプトは改行コードなどをエスケープした状態で表示している(「AppleScript エディタ」の環境設定の「編集」タブで「詳細:文字列中のタブや改行をエスケープ」がチェックされているという前提)
 *)
 
 tell application "Notes"
   set folderList to name of every folder of account "iCloud"
   --「メモ」フォルダーの実体は Notes という名前なので、考慮する
   set modified_folderList to {}
   repeat with fL in folderList
     if (fL as text) = "Notes" then set fL to "メモ"
     if (fL as text) = "false" then set fL to "false\t" --falseというフォルダー名だとキャンセルされてしまうので回避
     set the end of modified_folderList to fL
   end repeat
   
   set folderName to (choose from list modified_folderList with prompt "テキストファイルの内容を分割して、「メモ」アプリ内のフォルダにインポートします。\n\nまず「メモ」アプリ内のフォルダの名前を指定してください。")
   set folderName to (folderName as text)
   if folderName is "false" then error number -128 --キャンセルボタンを押した場合の処理
   if folderName is "false\t" then set folderName to "false"
   if folderName is "メモ" then set folderName to "Notes"
   
   repeat
     set textImported to choose file of type {"txt"} with prompt "インポートするテキストファイルを指定してください。"
     tell application "Finder"
       set textImported_name to name of textImported --あとで表示する
     end tell
     
     set textImported to POSIX path of textImported
     --改行コードが CRLF  LF かもしれないテキストを読み込み、CR に統一する。
     set textContents to do shell script "perl -pe 's/(\r)\n/$1/g; s/\n/\r/g;' < " & quoted form of textImported without altering line endings
     
     --HTMLタグを考慮
     set textContents to my replace_text(textContents, "&", "&amp;")
     set textContents to my replace_text(textContents, "<", "&lt;")
     set textContents to my replace_text(textContents, ">", "&gt;")
     --改行を変換しておく
     set textContents to my replace_text(textContents, "\r", "<br>")
     
     if length of textContents > 1000000 then
       display dialog "大きなファイルをインポートしようとしています。インポートに時間がかかるかもしれません。続けますか?" buttons {"中止する", "やり直す", "続ける"} default button 3
       set bReturned2 to button returned of result
       if bReturned2 is "中止する" then
         error number -128
       else if bReturned2 is "続ける" then
         exit repeat
       end if
     else
       exit repeat
     end if
   end repeat
   
   repeat
     display dialog "テキストファイルを分割するための「区切り文字列」を指定してください。\n\n改行は<br>、タブは<tab>と記述してください。\n\n空白の場合、分割せずにそのままインポートします。" default answer ""
     set divMarker to text returned of result
     if divMarker is "" then
       display dialog "区切り文字列が入力されていません。分割せずにインポートしますか?" buttons {"入力をやり直す", "分割しない"} default button 2
       set bReturned2 to button returned of result
       if bReturned2 is "分割しない" then
         set textParts to {textContents}
         exit repeat
       end if
     else
       set divMarker to my replace_text(divMarker, "<tab>", "\t")
       set tmp to AppleScript's text item delimiters
       set AppleScript's text item delimiters to divMarker --区切り文字列を設定
       set textParts to every text item of (textContents as text)
       set AppleScript's text item delimiters to tmp
       
       if length of textParts < 2 then
         display dialog "入力された区切り文字列は、読み込まれたテキストファイルに含まれていないようです。" buttons {"入力をやり直す"} default button 1
       else if length of textParts > 50 then
         display dialog "入力された区切り文字列では50以上に分割されます。区切り文字列を正しく入力しましたか?\n\nこのまま続けるかどうか選択してください。" buttons {"続ける", "入力をやり直す"} default button 2
         set bReturned3 to button returned of result
         if bReturned3 is "続ける" then
           exit repeat
         end if
       else
         exit repeat
       end if
     end if
   end repeat
   
   display dialog "最終確認です。\n\n「" & folderName & "」フォルダに「" & textImported_name & "」をインポートします。"
   
   set importCount to 0
   repeat with i in reverse of textParts
     
     set tmp_i to (i as text)
     set tmp_i to my replace_text(tmp_i, "<br>", "")
     set tmp_i to my replace_text(tmp_i, "\t", "")
     set tmp_i to my replace_text(tmp_i, " ", "")
     set tmp_i to my replace_text(tmp_i, " ", "")
     --分割されて出来たパーツが空白、もしくは改行やタブやスペースのみの場合は除外する
     if tmp_i is not equal to "" then
       set tmp2 to AppleScript's text item delimiters
       set AppleScript's text item delimiters to "<br>"
       set aParts to every text item of (i as text)
       set AppleScript's text item delimiters to tmp2
       
       --一行目を各メモのタイトルにする。一行目が空白、もしくはタブやスペースのみの場合は二行目以降をタイトルにする
       set title to "新規メモ"
       set pLength to length of aParts
       repeat with apCount from 1 to pLength
         set tmpPart to item apCount of aParts
         set tmpPart to my replace_text(tmpPart, "\t", "")
         set tmpPart to my replace_text(tmpPart, " ", "")
         set tmpPart to my replace_text(tmpPart, " ", "")
         if (tmpPart as text) is not "" then
           set title to item apCount of aParts
           exit repeat
         end if
       end repeat
       
       --「メモ」アプリの各メモの内容は実体としては(改行コードが全くない)HTML なので、以下で変換する。
       set bodyText to ""
       repeat with ap in aParts
         --行が空白、もしくはタブやスペースのみの場合は<br>を追加する
         set ap_tmp to ap
         set ap_tmp to my replace_text(ap_tmp, "\t", "")
         set ap_tmp to my replace_text(ap_tmp, " ", "")
         set ap_tmp to my replace_text(ap_tmp, " ", "")
         if (ap_tmp is "") then
           set np to "<div>" & ap & "<br></div>"
         else
           set np to "<div>" & ap & "</div>"
         end if
         set bodyText to bodyText & np
       end repeat
       
       make new note in folder folderName of account "iCloud"
       
       set bodyText to "<html><head></head><body style=\"word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; \">" & bodyText & "</body></html>"
       set body of note "新規メモ" to bodyText
       
       --各メモを作成すると、普通は一行目が自動的にメモのタイトルになるが、
       --スクリプトで作成するとそうならないので、タイトルを付けなければならない。
       --メモの一行目が長い場合、そのままではタイトルまで長くなってしまうため、適宜短縮する。
       
       if (title as string) contains "節" then -- title ""が含まれているとなぜかうまく行かないことがあるので暫定回避
         set title to my replace_text(title, "節", "せつ")
       end if
       set wn to the number of words of title
       if wn > 15 then
         set title to text from word 1 to word 15 of title
       end if
       set name of note "新規メモ" to title
       set importCount to importCount + 1
     end if
   end repeat
   display dialog "完了しました。\n\n" & importCount & "件のメモをインポートしました。" buttons {"終了"} default button 1
 end tell
 
 on replace_text(obj_text, search_str, replace_str)
   set astid_tmp to AppleScript's text item delimiters
   set AppleScript's text item delimiters to search_str
   set astid_texts to every text item of obj_text
   set AppleScript's text item delimiters to replace_str
   set obj_text to astid_texts as string
   set AppleScript's text item delimiters to astid_tmp
   return obj_text
 end replace_text


次に、このスクリプトが実際にどのように動くかについて述べる。

今ここに以下のようなテキストファイルがあるとする (文字コードは unicode でも Shift JIS でも かまわない)。

[smile.txt]
ハッピー
みゆき
-----
サニー
あかね
-----
ピース
やよい
-----
マーチ
なお
-----
ビューティー
れいか

まずメモ.app 内に「スマイル」というフォルダーを作る。そして上記のスクリプトを実行する。実行中にフォルダー名を訊かれるので「スマイル」と入力する。そして、インポートするファイルを選択するように指示されたら、このテキストファイルを指定する。最後に区切り文字列を訊かれたら「-----<br>」と入力する。

最終確認ボタンを押すと、メモ.app の「スマイル」フォルダー内に、「ハッピー」「サニー」「ピース」「マーチ」「ビューティー」という五つのメモが作成される。


« Mac版SafariのiCloudタブの中身は削除できるのか | トップページ | メモ.appエクスポートAppleScriptを作った[更新] »

コメント

コメントを書く

(ウェブ上には掲載しません)

« Mac版SafariのiCloudタブの中身は削除できるのか | トップページ | メモ.appエクスポートAppleScriptを作った[更新] »