Vanilla AppleScript フォルダ階層(子フォルダ)対応 フォルダ内の全ファイル名を取得 AppleScript [04]

AppleScript[04](CatchImage)

AppleScript [04] Vanilla AppleScript 最終版 フォルダ階層(子フォルダ)対応 フォルダ内の全ファイル名を取得!
 ①一番シンプルな ②真っさらな という意味で 従来の AppleScript を Vanilla AppleScript と呼ぶ。
 macOS 用 Cocoa API 利用の Cocoa AppleScript と区別するための修飾だそうだ。 macOS の真の実力を引き出す為に筆者も当AppleScriptTaskの Cocoa対応 を進めており、デバッグの真っ最中...
 来週中には記事にできると思うので、とにかく速いのが欲しいという方は期待してください!
 通称 Cocoa AS を正式には AppleScriptObjC ( ASOC ) と呼ぶ。

・最終版は AppleScript 流儀に従い List(配列)に行データをひたすら格納し、最後にテキストデリミタ利用で改行コードを付加 → カスタマイズが楽(かつ、若干 高速)に!
・Object Pascal で実装した "Macintosh System9" 以前とは異なり、 Objective-C で実装した macOS10 以降のAPI を Cocoa と呼ぶ
・( "Finder" 利用の ) Vanilla AppleScript は低速なだけで、ソート(並び順)とか細かい事を意識することなく カスタマイズが簡単(つまり、初心者向け!)
・Cocoa は本来 Objective-C や Swift 用部品のため、その知識が少しは無いと(ヘッダファイルを読めないと...) Vanilla から Cocoa 変換は大変! Vanilla と違いエラー発生場所が判らず!

 (注) AppleScript にて、フォルダ選択ダイアログ あるいは ファイル選択ダイアログ を利用します!

2021/09/06   Ver. 2.0「Vanilla AppleScript 最終版」に変更
→ AppleScript のみ("filePath.scpt" ファイル内のコード全て)、差替をお願い致します 



 【準備】 AppleScript [04] Vanilla AppleScript 最終版 フォルダ階層(子フォルダ)対応 フォルダ内の全ファイル名を取得! 

 まず、Excel メニューバーの [ヘルプ] - [更新プログラムのチェック] にて、適用されていないアップデートがあれば行ってください。


 VBA の AppleScriptTask コマンド パラメータの注意点 

  ファイルパスと区別するため フォルダパス指定には 末尾に必ず / を付加 してください! フォルダフルパス なら 先頭と末尾が必ず / となります。
 OneDriveiCloudDropboxBox 等のサービスをブラウザ利用でなくフォルダにリンクしている場合も(リンク)パスが判れば指定可能ですが、https:// が先頭に付いたり ネットワーク経由のアクセスのためとんでも無く時間がかかりますので ローカルPC(Mac本体内の高速なSSDやHDDドライブ)上のフォルダパスを指定してください。


 最終版 Vanilla AppleScript コードへの置換 

(1)  以前に  作成したExcelファイルをマクロを有効にして開き、続いて VBEウィンドウ を開く。

(2) ~/ライブラリ/Application Scripts/com.microsoft.Excel/ フォルダ内に保存した filePath.scpt をダブルクリック等で("スクリプトエディタ"アプリにて)開き、 ファイル内の全AppleScriptコードを以下のコードで置換し、 コンパイル後に ファイルを保存 したら "スクリプトエディタ"アプリは終了してください。

 上記の操作方法がよく解らない方は、  以前の投稿  をお読みください。

 VBA、AppleScript 両方のコードに コメントをたくさん記述しておいたので、宜しければ ご覧ください!

 2021/09/06  Ver. 2.0「Vanilla AppleScript 最終版」に変更
→ AppleScript のみ("filePath.scpt" ファイル内のコード全て)、差替をお願い致します 



 以下、ハンドラー毎に AppleScript を貼り付けますので、順番に全コードを コピー&ペースト(貼り付け)後 コンパイル後に ファイルを保存 してください。


--filePath.scpt Ver.2.0 Copyright 2021- ataruchi. [ https://twitter.com/ataruchi ]
--   AppleScript を学んで1ヶ月の作者が実装したため、"Finder" 利用で 問題点は「速度」!
--    いつかは 速度重視の "Cocoa API" 実装にする予定
--   著作権は放棄していませんが、ご自由に 利用・改造して頂いて構いません
--   なお 不都合等ありましても、作者は 何の補償も致しかねます。 ご注意ください!
--    1行めの「スクリプトの著作権表示部分」を削除することはできません。
--    また、改造したことが分かるよう 改造者へのリンクを表示するようにしてください。
--2021/08/26 Ver.1.0 全ハンドラーにて、実行結果テキストを クリップボードにも 保存(Excel対応)
--2021/08/31 Ver.1.1 「フィルタ参照による指定拡張子の抽出」版に変更
--2021/09/08 Ver.2.0 Vanilla AppleScript 最終版 → 文字列連結を止め、「文字列リストに要素(1行分の文字列)を追加」版に書き替え



-- (global) 定数の宣言
--  Excel対応のクリップボードに 区切り文字 vbCrLf を利用する理由
--  Excelでは「セル内の改行コードとしてvbLf」が用いられているため、
--  「改行コードとしてvbCrLf」を挟まないと [command]+[V]失敗!
property LF : ASCII character (10) -- vbLf [MACosX~ を含むUnix系の改行コード] for Unix
property CR : ASCII character (13) -- vbCr [~macOS9 の改行コード] for (OLD Mac)
property CRLF : CR & LF -- vbCrLf [MS Windows系の改行コード] for Win10, Win7



-- Test AppleScript Handler example --
set the clipboard to {} --クリップボードの初期化
--set paramStr to "★プロンプト文字列 Test★" & LF & (POSIX path of (path to home folder)) & LF & "css" & LF & "html" & LF & "txt" & LF & "scpt" & LF & "xml" & LF & "png"
set paramStr to "" & LF & "" & LF & "css" & LF & "html" & LF & "js" & LF & "scpt" & LF & "xml" & LF & "png"
getFileListOfChildFoldersMultiExt(paramStr)




--2021/08/31 「フィルタ参照」にて、指定拡張子のみ抽出
--2021/09/06 文字列連結を止め、文字列リストに要素(1行分の文字列)を追加
on foldersHierarchies(parentDir, extList, stringList, isPath)
  
  set isFirst to true --最初かどうか?
  
  try
    --display dialog (POSIX path of (parentDir as string))
    tell application "Finder"
      
      --フォルダ内のファイルListを取得(2021/08/31 「フィルタ参照」にて、指定拡張子のみ抽出)
      set fileList to (every file of parentDir whose (name extension is in extList))
      
      repeat with f in fileList --全ファイルを繰り返し、処理
        
        if ((not isPath) and isFirst) then --((getFileList) and isFirst)
          set fDir to (POSIX path of (parentDir as string)) --HFSパス経由
          set end of stringList to fDir --フォルダPOSIXフルパスを追加
          set isFirst to false
        end if --((getFileList) and isFirst)
        
        if (isPath) then --(getPathList)
          set fPath to (POSIX path of (f as string)) --HFSパス経由でフルパスを取得
          set end of stringList to fPath --POSIXフルパスを追加
        else --(getFileList)
          set fNameExt to (f's name as string) --  拡張子付きファイル名
          set end of stringList to fNameExt --ファイル名を行追加
        end if --(getPathList) or (getFileList)
        
      end repeat -- stringList は参照渡しのため、変更(要素の追加)可能!
      
      
      (*
      --クリップボードへtextを格納&クリップボードからtextを取得 
      activate --ウィンドウの前面に表示!
      set clipBoardInfo to (clipboard info for string) --目的のデータがstring(text)型?
      set clipBoardString to ""
      if clipBoardInfo ≠ {} then --目的のデータがない場合は、空のリストが返る
        set clipBoardList to the clipboard
        set clipBoardString to (clipBoardList as string)
      end if
      display dialog clipBoardString
      *)
      
      
      set childDirList to (every folder of parentDir) --子フォルダのListを取得
      repeat with childDir in childDirList
        ----フォルダ階層(子フォルダ)対応のため、再帰ハンドラを呼び出し
        my foldersHierarchies(childDir, extList, stringList, isPath)
      end repeat
      
    end tell -- application "Finder"
    
  on error
    --display dialog (count stringList)
    set stringList to {} --文字列リストを初期化
    display dialog "★ AppleScriptTask (foldersHierarchies) ★" & return & return & "   キャンセル あるいは 異常終了" buttons {"10秒で閉じます!"} with icon caution giving up after 10
  end try -- 「キャンセル」ボタン押下時用のエラーハンドリング
  
  --display dialog (count stringList)
  
end foldersHierarchies





--文字列リストを任意のデリミタ(通常は改行コード)付きで、テキストに変換
on getTextWithDelimiters(stringList, withDelimiters)
  
  set returnText to "" --ハンドラーの戻り値を初期化
  
  try
    set currentDelimiters to (AppleScript's text item delimiters) --デフォルトのデリミタを保存
    set (AppleScript's text item delimiters) to withDelimiters --デリミタを変更
    set returnText to (stringList as string) --デリミタ付きテキストに変換 Not as text!
    
    (*
    -- http://www.script-factory.net/monologue/FastDataOperation/index.xhtml
    --全要素へ高速なアクセスを行う方法(テキスト処理への応用: paragraphs要素を利用して、
    script list_wrapper --スクリプトオブジェクトのpropertyのリストにアクセス)
      property paragList : paragraphs of returnText
    end script
    repeat with parag in paragList of list_wrapper
      --display dialog (get contents of parag)
    end repeat
    *)
    
    set (AppleScript's text item delimiters) to currentDelimiters --デフォルトのデリミタに戻す
    
  on error
    --display dialog returnText
    --display dialog (count stringList)
    set returnText to "" --  ハンドラーの戻り値を初期化
    set stringList to {} --  文字列リストを初期化
    set (AppleScript's text item delimiters) to currentDelimiters --デフォルトのデリミタに戻す
    display dialog "★ getTextWithDelimiters ★" & return & return & "   キャンセル あるいは 異常終了" buttons {"10秒で閉じます!"} with icon caution giving up after 10
  end try
  
  return returnText --display dialog returnText
  
end getTextWithDelimiters





--選択ディレクトリの(POSIX)パス名+「(拡張子なしの)全ファイル名」を取得
-- パラメータ[1]  プロンプト文字列:""なら、当ハンドラー設定の初期値
-- パラメータ[2]  初期表示フォルダ:""なら、無指定(前回と同じフォルダを開く)
-- パラメータ[3]  ファイル拡張子:"html"のように 1つだけ 指定可
-- 実行結果[0]     指定フォルダ(ディレクトリ)の POSIXフルパス
-- 実行結果[1~n] (拡張子なしの)ファイル名
--2021/08/31 「フィルタ参照」にて、指定拡張子のみ抽出
on getFileListOfFolderExt(paramStr) --AppleScriptは、文字列比較で大文字と小文字の文字を区別しない
  
  set promptStr to "フォルダを選択してください!" --初期値
  set paramList to {} --パラメータのリスト
  
  try
    set tmp to (AppleScript's text item delimiters) --現在のデリミタを保存
    set (AppleScript's text item delimiters) to {LF} --デリミタを変更
    set paramList to (every text item of paramStr) --分割し、List格納
    set (AppleScript's text item delimiters) to tmp --保存したデリミタに戻す
    
    set str to ((first item of paramList) as string)
    if (str ≠ "") then -- not=は「/=」と記述
      set promptStr to str
    end if
    set paramList to (rest of paramList) -- 最初の要素を削除
    set defaultLocation to ((first item of paramList) as string)
    set paramList to (rest of paramList) -- 最初の要素を削除
    
    activate --ウィンドウの前面に表示!
    if (defaultLocation = "") then
      set theAlias to (choose folder with prompt promptStr)
    else
      set defaultLocation to (POSIX path of defaultLocation)
      set theAlias to (choose folder with prompt promptStr default location defaultLocation)
    end if --選択フォルダの「エイリアス値」が返る
    
    set stringList to {} --文字列リストを初期化
    set isFirst to true -- 最初かどうか?
    
    tell application "Finder"
      --フォルダ内のファイルListを取得(2021/08/31 「フィルタ参照」にて、指定拡張子のみを抽出)
      set aliasList to (every file of theAlias whose (name extension is in paramList))
      
      repeat with f in aliasList
        if (isFirst) then
          set fDirHFS to (f's folder as string) --(フォルダ)HFSパス
          set fDir to (POSIX path of fDirHFS) --(フォルダ)POSIXパス
          set end of stringList to fDir --フォルダパスを行追加
          set isFirst to false
        end if
        --set fName to (f's name as string) --  「ファイル名+拡張子」を取得
        --「ファイル名(拡張子なし)」を取得 abc.scpt -> items 1 thru -6
        set fExt to (f's name extension as string) --「拡張子のみ」を取得
        set fName to ((f's name as string)'s items 1 thru -((fExt's length) + 2) as string)
        set end of stringList to fName --「ファイル名(拡張子なし)」を行追加
      end repeat
    end tell
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {CRLF})
    set the clipboard to {} --クリップボードの初期化
    set the clipboard to returnText --クリップボードへ格納
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {LF}) --ハンドラ-の戻り値へ 格納
    
    set stringList to {} --  文字列リストを初期化
    
  on error
    -- display dialog returnText
    set returnText to "" --  ハンドラーの戻り値を初期化
    set stringList to {} --  文字列リストを初期化
    set (AppleScript's text item delimiters) to tmp --保存したデリミタに戻す
    display dialog "★ AppleScriptTask (getFileListOfFolderExt) ★" & return & return & "   キャンセル あるいは 異常終了" buttons {"10秒で閉じます!"} with icon caution giving up after 10
  end try -- 「キャンセル」ボタン押下時用のエラーハンドリング
  
  return returnText -- display dialog returnText
  
end getFileListOfFolderExt




--選択ディレクトリの(POSIX)パス名+「(拡張子付きの)全ファイル名」を取得
-- パラメータ[1]  プロンプト文字列:""なら、当ハンドラー設定の初期値
-- パラメータ[2]  初期表示フォルダ:""なら、無指定(前回と同じフォルダを開く)
-- パラメータ[3~n]  ファイル拡張子:"html" "css"のように複数指定可
-- 実行結果[0]     指定フォルダ(ディレクトリ)の POSIXフルパス
-- 実行結果[1~n] (拡張子を含めた)ファイル名
--2021/08/31 「フィルタ参照」にて、指定拡張子のみ抽出
on getFileListOfFolderMultiExt(paramStr) --AppleScriptは文字列比較で大文字と小文字の文字を区別しない
  
  set promptStr to "フォルダを選択してください!" --初期値
  set paramList to {} --パラメータのリスト
  
  try
    set tmp to (AppleScript's text item delimiters) --現在のデリミタを保存
    set (AppleScript's text item delimiters) to {LF} --デリミタを変更
    set paramList to (every text item of paramStr) --分割し、List格納
    set (AppleScript's text item delimiters) to tmp --保存したデリミタに戻す
    
    set str to ((first item of paramList) as string)
    if (str ≠ "") then -- not=は「/=」と記述
      set promptStr to str
    end if
    set paramList to (rest of paramList) -- 最初の要素を削除
    set defaultLocation to ((first item of paramList) as string)
    set paramList to (rest of paramList) -- 最初の要素を削除
    
    activate --ウィンドウの前面に表示!
    if (defaultLocation = "") then
      set theAlias to (choose folder with prompt promptStr)
    else
      set defaultLocation to (POSIX path of defaultLocation)
      set theAlias to (choose folder with prompt promptStr default location defaultLocation)
    end if --選択フォルダの「エイリアス値」が返る
    
    set stringList to {} --文字列リストを初期化
    set isFirst to true -- 最初かどうか?
    
    tell application "Finder"
      --フォルダ内のファイルListを取得(2021/08/31 「フィルタ参照」にて、指定拡張子のみを抽出)
      set aliasList to (every file of theAlias whose (name extension is in paramList))
      
      repeat with f in aliasList
        if (isFirst) then
          set fDirHFS to (f's folder as string) --(フォルダ)HFSパス
          set fDir to (POSIX path of fDirHFS) --(フォルダ)POSIXパス
          set end of stringList to fDir --フォルダパスを行追加
          set isFirst to false
        end if
        set fNameExt to (f's name as string) --「ファイル名+拡張子」を取得
        set end of stringList to fNameExt --ファイル名を行追加
      end repeat
    end tell
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {CRLF})
    set the clipboard to {} --クリップボードの初期化
    set the clipboard to returnText --クリップボードへ格納
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {LF}) --ハンドラ-の戻り値へ 格納
    
    set stringList to {} --  文字列リストを初期化
    
  on error
    -- display dialog returnText
    set returnText to "" --  ハンドラーの戻り値を初期化
    set stringList to {} --  文字列リストを初期化
    set (AppleScript's text item delimiters) to tmp --保存したデリミタに戻す
    display dialog "★ AppleScriptTask (getFileListOfFolderMultiExt) ★" & return & return & "   キャンセル あるいは 異常終了" buttons {"10秒で閉じます!"} with icon caution giving up after 10
  end try -- 「キャンセル」ボタン押下時用のエラーハンドリング
  
  return returnText -- display dialog returnText
  
end getFileListOfFolderMultiExt





-- 選択ディレクトリの(POSIX)パス名+「(拡張子ありの)全ファイル名」を取得
-- パラメータ[1]  プロンプト文字列:""なら、当ハンドラー設定の初期値
-- パラメータ[2]  初期表示フォルダ:""なら、無指定(前回と同じフォルダを開く)
-- 実行結果[0]     指定フォルダ(ディレクトリ)の POSIXフルパス
-- 実行結果[1~n] (拡張子を含めた)ファイル名
on getFileListOfFolder(paramStr) --  拡張子を指定しないため、フォルダ内の全ファイルを返す
  
  set promptStr to "フォルダを選択してください!" --フォルダ選択時のプロンプト文字列
  set paramList to {} --パラメータのリスト
  
  try
    set tmp to (AppleScript's text item delimiters) --現在のデリミタを保存
    set (AppleScript's text item delimiters) to {LF} --デリミタを変更
    set paramList to (every text item of paramStr) --分割し、List格納
    set (AppleScript's text item delimiters) to tmp --保存したデリミタに戻す
    
    set str to ((first item of paramList) as string)
    if (str ≠ "") then -- not=は「/=」と記述
      set promptStr to str
    end if
    set paramList to (rest of paramList) -- 最初の要素を削除
    set defaultLocation to ((first item of paramList) as string)
    set paramList to (rest of paramList) -- 最初の要素を削除
    
    activate --ウィンドウの前面に表示!
    if (defaultLocation = "") then
      set theAlias to (choose folder with prompt promptStr)
    else
      set defaultLocation to (POSIX path of defaultLocation)
      set theAlias to (choose folder with prompt promptStr default location defaultLocation)
    end if --選択フォルダの「エイリアス値」が返る
    
    set stringList to {} --文字列リストを初期化
    set isFirst to true -- 最初かどうか?
    
    tell application "Finder"
      set aliasList to (every file of theAlias) --  指定フォルダ内の ファイル List を取得
      
      repeat with f in aliasList
        if (isFirst) then
          set fDirHFS to (f's folder as string) --    (フォルダ)HFSパス
          set fDir to (POSIX path of fDirHFS) --(フォルダ)POSIXパス
          set end of stringList to fDir --フォルダパスを行追加
          set isFirst to false
        end if
        set fNameExt to (f's name as string) --「ファイル名+拡張子」を取得
        set end of stringList to fNameExt --ファイル名を行追加
      end repeat
    end tell
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {CRLF})
    set the clipboard to {} --クリップボードの初期化
    set the clipboard to returnText --クリップボードへ格納
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {LF}) --ハンドラ-の戻り値へ 格納
    
    set stringList to {} --  文字列リストを初期化
    
  on error
    set returnText to "" --  ハンドラーの戻り値を初期化
    set stringList to {} --  文字列リストを初期化
    set (AppleScript's text item delimiters) to tmp --保存したデリミタに戻す
    display dialog "★ AppleScriptTask (getFileListOfFolder) ★" & return & return & "   キャンセル あるいは 異常終了" buttons {"10秒で閉じます!"} with icon caution giving up after 10
  end try -- 「キャンセル」ボタン押下時用のエラーハンドリング
  
  return returnText -- display dialog returnText
  
end getFileListOfFolder




--選択したフォルダ階層(子フォルダを含む)に含まれるファイルのフルパスを取得
-- パラメータ[1]  プロンプト文字列:""なら、当ハンドラー設定の初期値
-- パラメータ[2]  初期表示フォルダ:""なら、無指定(前回と同じフォルダを開く)
-- パラメータ[3~n]  ファイル拡張子:"html" "css"のように複数指定可
-- 実行結果[0~n] フォルダ階層に含まれるファイルの フルパス
on getPathListOfChildFoldersMultiExt(paramStr) --AppleScriptは文字列比較で大文字と小文字の文字を区別せず
  
  set promptStr to "フォルダを選択してください!(子フォルダ対応)" --初期値
  
  try
    set tmp to (AppleScript's text item delimiters) --現在のデリミタを保存
    set (AppleScript's text item delimiters) to {LF} --デリミタを変更
    set paramList to (every text item of paramStr) --分割し、List格納
    set (AppleScript's text item delimiters) to tmp --保存したデリミタに戻す
    
    set str to ((first item of paramList) as string)
    if (str ≠ "") then -- not=は「/=」と記述
      set promptStr to str
    end if
    set paramList to (rest of paramList) --最初の要素を削除
    set defaultLocation to ((first item of paramList) as string)
    set paramList to (rest of paramList) --最初の要素を削除
    --1,2番目の要素を削除したため、「paramList=拡張子文字列のList」
    
    activate --ウィンドウの前面に表示!
    if (defaultLocation = "") then
      set theFolder to (choose folder with prompt promptStr)
    else
      set defaultLocation to (POSIX path of defaultLocation)
      set theFolder to (choose folder with prompt promptStr default location defaultLocation)
    end if --選択フォルダの「エイリアス値」が返る
    
    --フォルダ階層(子フォルダ)対応のため、再帰ハンドラを呼び出し
    set stringList to {} --  文字列リストを初期化
    set isPath to true --  getPathList
    foldersHierarchies(theFolder, paramList, stringList, isPath) --デフォルトは参照渡し
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {CRLF})
    set the clipboard to {} --クリップボードの初期化
    set the clipboard to returnText --クリップボードへ格納
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {LF}) --ハンドラ-の戻り値へ 格納
    
    set stringList to {} --  文字列リストを初期化
    
  on error
    --display dialog returnText
    --display dialog (count stringList)
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set stringList to {} --  文字列リストを初期化
    set (AppleScript's text item delimiters) to tmp --保存したデリミタに戻す
    display dialog "★ AppleScriptTask (getPathListOfChildFoldersMultiExt) ★" & return & return & "   キャンセル あるいは 異常終了" buttons {"10秒で閉じます!"} with icon caution giving up after 10
  end try -- 「キャンセル」ボタン押下時用のエラーハンドリング
  
  return returnText -- display dialog returnText
  
end getPathListOfChildFoldersMultiExt





--選択したフォルダ階層(子フォルダを含む)に含まれるファイルのフルパスを取得
-- パラメータ[1]  プロンプト文字列:""なら、当ハンドラー設定の初期値
-- パラメータ[2]  初期表示フォルダ:""なら、無指定(前回と同じフォルダを開く)
-- パラメータ[3~n]  ファイル拡張子:"html" "css"のように複数指定可
-- 実行結果[0〜n] (子フォルダを含む)フォルダのフルパス あるいは ファイル名
on getFileListOfChildFoldersMultiExt(paramStr) --AppleScriptは文字列比較で大文字と小文字の文字を区別せず
  
  set promptStr to "フォルダを選択してください!(子フォルダ対応)" --初期値
  
  try
    set tmp to (AppleScript's text item delimiters) --現在のデリミタを保存
    set (AppleScript's text item delimiters) to {LF} --デリミタを変更
    set paramList to (every text item of paramStr) --分割し、List格納
    set (AppleScript's text item delimiters) to tmp --保存したデリミタに戻す
    
    set str to ((first item of paramList) as string)
    if (str ≠ "") then -- not=は「/=」と記述
      set promptStr to str
    end if
    set paramList to (rest of paramList) --最初の要素を削除
    set defaultLocation to ((first item of paramList) as string)
    set paramList to (rest of paramList) --最初の要素を削除
    --1,2番目の要素を削除したため、「paramList=拡張子文字列のList」
    
    activate --ウィンドウの前面に表示!
    if (defaultLocation = "") then
      set theFolder to (choose folder with prompt promptStr)
    else
      set defaultLocation to (POSIX path of defaultLocation)
      set theFolder to (choose folder with prompt promptStr default location defaultLocation)
    end if --選択フォルダの「エイリアス値」が返る
    
    --フォルダ階層(子フォルダ)対応のため、再帰ハンドラを呼び出し
    set stringList to {} --  文字列リストを初期化
    set isPath to false --  getFileList
    foldersHierarchies(theFolder, paramList, stringList, isPath) --デフォルトは参照渡し
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {CRLF})
    set the clipboard to {} --クリップボードの初期化
    set the clipboard to returnText --クリップボードへ格納
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {LF}) --ハンドラ-の戻り値へ 格納
    
    set stringList to {} --  文字列リストを初期化
    
  on error
    --display dialog returnText
    --display dialog (count stringList)
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set stringList to {} --  文字列リストを初期化
    set (AppleScript's text item delimiters) to tmp --保存したデリミタに戻す
    display dialog "★ AppleScriptTask (getFileListOfChildFoldersMultiExt) ★" & return & return & "   キャンセル あるいは 異常終了" buttons {"10秒で閉じます!"} with icon caution giving up after 10
  end try -- 「キャンセル」ボタン押下時用のエラーハンドリング
  
  return returnText -- display dialog returnText
  
end getFileListOfChildFoldersMultiExt





-- 選択したファイルのパスを取得する(複数ファイルの選択不可)
-- パラメータ[1]  プロンプト文字列:""なら、当ハンドラー設定の初期値
-- パラメータ[2]  初期表示フォルダ:""なら、無指定(前回と同じフォルダを開く)
-- パラメータ[3~n]  UTI(type identifier):"css" "html"のように複数限定可(4つまで)
--  厳密には「拡張子ではなくUTI限定」のため、無効だと全ファイルが選択可能
-- 実行結果[0] 指定フォルダ(ディレクトリ)の POSIXフルパス
-- 実行結果[1] (拡張子を含めた)ファイル名
on getFilePath(paramStr)
  set promptStr to "ファイルの選択(複数ファイルの選択不可)" --  フォルダ選択時のプロンプト文字列
  set paramList to {} --パラメータのリスト
  
  try
    set tmp to (AppleScript's text item delimiters) --  現在のデリミタを保存
    set (AppleScript's text item delimiters) to {LF} -- デリミタを変更
    set paramList to (every text item of paramStr) -- 分割し、List格納
    set (AppleScript's text item delimiters) to tmp --  保存したデリミタに戻す
    
    set str to ((first item of paramList) as string)
    if (str ≠ "") then --not=は「/=」と記述
      set promptStr to str
    end if
    set paramList to (rest of paramList) --最初の要素を削除
    set defaultLocation to ((first item of paramList) as string)
    set paramList to (rest of paramList) --最初の要素を削除
    
    activate --ウィンドウの前面に表示!
    if (defaultLocation = "") then
      set f to (choose file with prompt promptStr of type paramList)
    else
      set defaultLocation to (POSIX path of defaultLocation)
      set f to (choose file with prompt promptStr of type paramList default location defaultLocation)
    end if --選択したファイルの「エイリアス値」が返される
    
    tell application "Finder"
      set fDirHFS to (f's folder as string) --  (フォルダ)HFSパス
      set fDir to (POSIX path of fDirHFS) --(フォルダ) POSIXパス
      set fNameExt to (f's name as string) --  拡張子付きファイル名
    end tell
    
    set stringList to {} --        文字列リストを初期化
    set end of stringList to fDir --    フォルダフルパスを行追加
    set end of stringList to fNameExt --  ファイル名を行追加
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {CRLF})
    set the clipboard to {} --クリップボードの初期化
    set the clipboard to returnText --クリップボードへ格納
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {LF}) --ハンドラ-の戻り値へ 格納
    
    set stringList to {} --  文字列リストを初期化
    
  on error
    set returnText to "" --  ハンドラーの戻り値を初期化
    set stringList to {} --  文字列リストを初期化
    set (AppleScript's text item delimiters) to tmp --  保存したデリミタに戻す
    display dialog "★ AppleScriptTask (getFilePath) ★" & return & return & "   キャンセル あるいは 異常終了" buttons {"10秒で閉じます!"} with icon caution giving up after 10
  end try -- 「キャンセル」ボタン押下時用のエラーハンドリング
  
  return returnText -- display dialog returnText
  
end getFilePath





-- 選択した(複数)ファイルのパスを取得する(複数ファイルの選択可能)
-- パラメータ[1]  プロンプト文字列:""なら、当ハンドラー設定の初期値
-- パラメータ[2]  初期表示フォルダ:""なら、無指定(前回と同じフォルダを開く)
-- パラメータ[3~n]  UTI(type identifier):"css" "html"のように複数限定可(4つまで)
--  厳密には「拡張子ではなくUTI限定」のため、無効だと全ファイルが選択可能
-- 実行結果[0]     指定フォルダ(ディレクトリ)の POSIXフルパス
-- 実行結果[1~n] (拡張子を含めた)ファイル名
on getMultiFilePath(paramStr)
  set multiFile to true
  set promptStr to "ファイルの選択(複数ファイルの選択可能)" --  フォルダ選択時のプロンプト文字列
  set paramList to {} --パラメータのリスト
  
  try
    set tmp to (AppleScript's text item delimiters) --  現在のデリミタを保存
    set (AppleScript's text item delimiters) to {LF} -- デリミタを変更
    set paramList to (every text item of paramStr) -- 分割し、List格納
    set (AppleScript's text item delimiters) to tmp --  保存したデリミタに戻す
    
    set str to ((first item of paramList) as string)
    if (str ≠ "") then --not=は「/=」と記述
      set promptStr to str
    end if
    set paramList to (rest of paramList) --最初の要素を削除
    set defaultLocation to ((first item of paramList) as string)
    set paramList to (rest of paramList) --最初の要素を削除
    
    activate --ウィンドウの前面に表示!
    if (defaultLocation = "") then
      set aliasList to (choose file with prompt promptStr of type paramList multiple selections allowed multiFile)
    else
      set defaultLocation to (POSIX path of defaultLocation)
      set aliasList to (choose file with prompt promptStr of type paramList default location defaultLocation multiple selections allowed multiFile)
    end if --選択したファイルの「エイリアス値」が返される
    
    set stringList to {} --文字列リストを初期化
    set isFirst to true -- 最初かどうか?
    
    tell application "Finder"
      repeat with f in aliasList
        set fDirHFS to (f's folder as string) --    (フォルダ)HFSパス
        set fDir to (POSIX path of fDirHFS) --  (フォルダ)POSIXパス
        set fNameExt to (f's name as string) --    拡張子付きファイル名
        
        if (isFirst) then
          set end of stringList to fDir --  フォルダパスを行追加
          set end of stringList to fNameExt --ファイル名を行追加
          set isFirst to false
        else
          set end of stringList to fNameExt --ファイル名を行追加
        end if
      end repeat
    end tell
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {CRLF})
    set the clipboard to {} --クリップボードの初期化
    set the clipboard to returnText --クリップボードへ格納
    
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set returnText to getTextWithDelimiters(stringList, {LF}) --ハンドラ-の戻り値へ 格納
    
    set stringList to {} --  文字列リストを初期化
    
  on error
    set returnText to "" --  ハンドラ-の戻り値を初期化
    set stringList to {} --  文字列リストを初期化
    set (AppleScript's text item delimiters) to tmp --  保存したデリミタに戻す
    display dialog "★ AppleScriptTask (getMultiFilePath) ★" & return & return & "   キャンセル あるいは 異常終了" buttons {"10秒で閉じます!"} with icon caution giving up after 10
  end try -- 「キャンセル」ボタン押下時用のエラーハンドリング
  
  return returnText -- display dialog returnText
  
end getMultiFilePath




AppleScript[02] Png03

 【解説】 AppleScript [04] Vanilla AppleScript 最終版 フォルダ階層(子フォルダ)対応 フォルダ内の全ファイル名を取得! 


 AppleScript のみの変更で、入出力インターフェースを含め VBAコードの変更なし! → 前回のまとめ 


 上記画面は AppleScript 呼び出し用のサンプルで、パラメータをセット後に AppleScriptTaskコマンド を呼び出し、結果文字列を取得。(結果文字列をクリップボードにも格納)
 (1) AppleScriptTaskコマンド 実行結果(文字列)を イミディエイト ウィンドウ に表示
 (2) VBAで クリップボードの内容を [A1:An] セルに貼り付け
 (3) クリップボードの内容をVBAの変数に格納し、 イミディエイト ウィンドウ に表示

 AppleScriptTaskコマンド 実行結果(文字列)は Macで表示しやすいよう区切り文字に LF (Unix系の改行コード)を挟んでいましたが、クリップボード出力は CRLF (Windows系の改行コード)を挟みました。
Excel がセル内改行コードとして既に LF を利用していて、 CRLF にしないと [command]+[V] で複数行に正しく貼り付けできないからです。

 ActiveSheet.Paste Destination:=Range("A1")
上記VBAコードにて、「[A1] セル選択後に [command]+[V] 貼り付け操作」を代替可能。

  AppleScriptTaskコマンド 実行結果(文字列)と同様 何もしなくても UTF-8 文字コードがクリップボードにも適用されるので、フォルダ名やファイル名に日本語が含まれていても問題無し
実装後に テキストエディタに [command]+[V] で貼り付けしても全く問題は無く、超絶便利! 自動判別不可の場合も手動で「UTF-8文字コード & CRLF改行コード」を設定すれば そのまま編集も可能です。

 入出力のインターフェースは以前から全く変更していません(VBAコードの変更なし)ので、詳細は こちら  を参照ください。


 文字列連結を止め、「文字列リストに要素(1行分の文字列)を追加」版に書き替え 

 「子フォルダを含めた指定フォルダ内の合計数」が100ファイル以下なら問題ないと思いますが、 AppleScript の流儀に従った効率の良い方法に書き替えました!
 以下 (2) または (3) を行う専用のハンドラーとして、 getTextWithDelimiters() を実装。

(1) List(配列)に、ファイル(フォルダ)フルパスあるいはファイル名のみ、つまり 1ファイル1行分の文字列を ひたすら格納
(2) 全格納後、テキストの区切り文字(デリミタ)を変更して、改行コード(CRLF)を付加し、クリップボードにテキストデータを格納
(3) 全格納後、テキストの区切り文字(デリミタ)を変更して、改行コード(LF)を付加し、 AppleScriptTask コマンドの結果文字列にテキストデータを格納

 デリミタ文字変更後に List(配列)オブジェクトから Textオブジェクトに変換すれば、要素の前後にデリミタ文字が付加される仕様。 逆に デリミタ変更後に Textオブジェクトから List(配列)オブジェクトに変換すれば、デリミタ文字が削除され List(配列)に要素が格納される仕様。 VBA でセットした LF 区切りの パラメータ文字列を分割して List(配列)に格納しています。 さらに Textオブジェクト内の文字列の置換も、この仕組みを利用して実装可能! (専用のハンドラーを組んでいる人が多いそうで、ググると出てくるはず...)




 [command] + [Q] にてまず VBE を終了し、Excel のウィンドウ内を選択して [command] + [Q] にて Excel も終了させます。 「作業中のブック」を保存するか確認のダイアログ画面が表示された場合は 「保存」しましょう。 「自動保存」済みの場合、保存するかどうかの確認ダイアログ画面は表示されません。


 AppleScriptTask コマンドの結果文字列(エラーがあれば、空文字 "" を返す)だけでなく、クリップボードにも同じ内容(改行コードは異なる)をセットしているため、必要があれば「片方のみ」に変更してください。
 AppleScript から VBA に数百ファイル以上結果が返されるのであれば、大量データが渡されるオーバーヘッドも含め、クリップボードのみの利用(結果文字列は、正常終了/異常終了のみ判れば良い)がオススメです。 また、バックグラウンド処理前提の場合は 相互で クリップボードの中身を消してしまう可能性 があるため、結果文字列のみの利用が良いでしょう。

 1日2時間くらい1ヶ月 AppleScript を勉強した成果として、今回の記事を書きました。 AppleScript に関してはまだまだ初心者のため、実行速度に問題があります!
 Cocoa API を直利用したコード(Windows APIを直利用するようなもの)に書き替えたら、全件読み込み処理1回だけなら100倍程速くなる感じ。 ただ、並び順が不定のため "Finder" と同等の並び順にするだけで2回ソート(並び替え)処理が必要だったりしますが、それでも10倍以上の速度が出ます。 Vanilla 以上に Cocoa AppleScript は(プログラマーとして)敷居が高いため、C言語を経験した人でないとカスタマイズもできないのではと筆者は思います。 幸い、筆者は Objective-C の経験があったので... Cocoa だとエラー発生箇所も全く判らずデバッグが大変なため、有料の  Script Debugger  必須だそうです!(買い切り100ドルで、メジャーアップデートなら半額の50ドル) ちなみに、VBA が組める人であれば Vanilla AppleScript のカスタマイズなら可能かと...

 Vanilla AppleScript 最終版もテストは結構しましたが、不具合があればコメント等で教えて頂けると嬉しいです。

 最後に、カスタマイズ無しで利用するだけなら 最低10倍は高速な Cocoa AppleScript は有用だと思いますので、来週アップ予定の記事をお待ちくださいませ! 100% Cocoa 対応 AppleScript コードに変わるわけではないため、 Vanilla 部分のカスタマイズは問題無くできるはずです。








Macブログ ランキング アイコン
最後まで読んでいただき、ありがとうございます。 また、お越しくださいませ。
// アタル
For follow LINE Reader Group!Subscribe to this blog on Feedly!

Next Post Previous Post
1 Comments
  • アタル
    アタル 2021年11月5日 22:44

    -- Copyright 2021- ataruchi. [ https://twitter.com/ataruchi ] with (Only Vanilla AppleScript)
    -- 「スクリプトエディタ.app」に以下の AppleScript を貼り付け後 [command]+[R] にて実行すると、
    --指定フォルダ内に含まれる全ファイル名のフルパスを取得して、クリップボードに格納します!
    --予め、6行めの extList に抽出ファイルの拡張子を設定すること


    ------------------------------------------------------------
    property LF : ASCII character (10) -- vbLf [MACosX~ を含むUnix系の改行コード] for Unix
    property CR : ASCII character (13) -- vbCr [~macOS9 の改行コード] for (OLD Mac)
    property CRLF : CR & LF -- vbCrLf [MS Windows系の改行コード] for Win10, Win7

    set the clipboard to {} --クリップボードの初期化
    set extList to {"xlsm", "xlsx", "pdf", "rtf", "txt"} --抽出ファイルの拡張子を設定後に、実行
    getPathListOfChildFoldersMultiExt(extList)



    on getPathListOfChildFoldersMultiExt(extList)
    try
    activate --ウィンドウの前面に表示!
    set theFolder to (choose folder) --選択フォルダのエイリアス値が返る

    --フォルダ階層(子フォルダ)対応のため、再帰ハンドラを呼び出し
    set stringList to {} -- 文字列リストを初期化
    foldersHierarchies(theFolder, extList, stringList) --Listは、参照(ポインタ)渡し

    if stringList = {} then
    activate
    display alert "エラー発生か、対象ファイルなし" as critical buttons {"OK"}
    return ""
    else
    set countFiles to ((count stringList) as string)
    end if

    set returnText to "" -- ハンドラ-の戻り値を初期化
    --Use {LF} for TextEditor
    set returnText to getTextWithDelimiters(stringList, {CRLF}) --Use for Excel's paste
    set the clipboard to {} --クリップボードの初期化
    set the clipboard to returnText --クリップボードへ格納
    set stringList to {} -- 文字列リストを初期化

    activate
    display alert ("抽出ファイル件数= " & countFiles) as informational buttons {"OK"}
    return returnText

    on error --エラー時の処理
    set stringList to {} -- 文字列リストを初期化
    activate
    display alert "エラー発生!" as critical buttons {"OK"}
    return ""
    end try -- 「キャンセル」ボタン押下時用のエラーハンドリング
    end getPathListOfChildFoldersMultiExt



    on foldersHierarchies(parentDir, extList, stringList) --再帰 呼び出し ハンドラー
    try
    tell application "Finder"
    --フォルダ内のファイルListを取得(「フィルタ参照」にて、指定拡張子のみ抽出)
    set fileList to (every file of parentDir whose (name extension is in extList))

    repeat with f in fileList --全ファイルを繰り返し、処理
    set fPath to (POSIX path of (f as string)) --HFSパス経由でフルパスを取得
    set (end of stringList) to fPath --POSIXフルパスを追加
    end repeat -- stringList は参照渡しのため、変更(要素の追加)可能!

    set childDirList to (every folder of parentDir) --子フォルダのListを取得
    repeat with childDir in childDirList
    ----フォルダ階層(子フォルダ)対応のため、再帰 呼び出し
    my foldersHierarchies(childDir, extList, stringList)
    end repeat
    end tell -- application "Finder"

    on error --エラー時の処理
    set stringList to {} --文字列リストを初期化
    end try
    end foldersHierarchies



    --文字列リストを任意のデリミタ(通常は改行コード)付きで、テキストに変換
    on getTextWithDelimiters(stringList, withDelimiters)
    try
    set returnText to "" --ハンドラーの戻り値を初期化

    set currentDelimiters to (AppleScript's text item delimiters) --デフォルトのデリミタを保存
    set (AppleScript's text item delimiters) to withDelimiters --デリミタを変更

    set returnText to (stringList as string) --デリミタ付きテキストに変換 Not as text!

    set (AppleScript's text item delimiters) to currentDelimiters --デフォルトのデリミタに戻す

    return returnText

    on error --エラー時の処理
    set (AppleScript's text item delimiters) to currentDelimiters --デフォルトのデリミタに戻す
    set stringList to {} -- 文字列リストを初期化
    return ""
    end try
    end getTextWithDelimiters
    ------------------------------------------------------------

Add Comment
comment url