macのショートカットアプリでJSONを扱う方法と注意点

macのショートカットアプリではJSONファイルの読み込み/書き込みが可能だが、落とし穴が有って苦労したので情報をまとめる。

JSONファイルの読み込み

  1. 「ファイル」アクションで読み込むファイルを指定
    (ファイルをドロップすると1発で指定出来て楽)
  2. 「入力から辞書を取得」アクションでパース

これだけ。
後は内容に応じて処理を組めば良い。

例えば次のようなJSONなら

[
    {"title": "entry1", "contents": "example1"},
    {"title": "entry2", "contents": "example2"},
    {"title": "entry3", "contents": "example3"}
]

「各項目を繰り返す」+「辞書の値を取得」で内容を読める。

落とし穴

ファイル名が「example.json」のように拡張子が.jsonだと「ショートカットの実行に問題がありました。」とエラーメッセージが出て止まってしまう。
「example.json.txt」のように拡張子を.txtに変更すれば読み込めるようになる。

JSON(と言うか辞書)の内容変更

「辞書の値を設定」アクションで辞書の内容を更新出来る。

落とし穴

値を更新しても変数が更新前の辞書を参照し続けているようで、明示的に更新後の辞書を変数に再設定する必要がある。

JSONの保存

辞書を「ファイルを保存」や「テキストファイルに追加」アクションに渡せばJSONで保存される。

読み込みと違って拡張子.jsonでも問題ない。

古いバージョンのBluetoothではパスキーを使えない

Windowsデスクトップに古いBluetooth USBアダプターを繋いでスマートフォンのパスキーを使用しようとしたのだが、QRコード読み取り後の接続が失敗してしまう。
この際、原因が推測できそうなメッセージは出ず、ただ接続が上手く行かなかった事しか分からない。
新しいBluetoothアダプターに買い替えた所、すんなり認証が完了した。

最初に使用したBluetoothアダプターは随分しまい込んでいた物で、Bluetooth3.0対応の物だった。
新しい方は5.4対応の品だ。
流石に3.0は古すぎたのだろう。

PC自体はそんなに古くなくても、Bluetoothアダプターは古い物を使いまわしているという状況は普通に有りうるだろうし、Windows側でエラーメッセージくらい出してくれても良いと思うのだが。

VS CodeはDev ContainersとSSH Agentを繋いでくれる

環境: Windows11, Windows標準のOpenSSH, Visual Studio Code, Dev Containers拡張, Docker Desktop

Windows付属のOpenSSHでSSH Agentを使用している場合、VS CodeのDev Containers拡張でLinuxコンテナを立ち上げると、コンテナ内からホストのSSH Agentに接続出来るようになる。

何も設定せずともコンテナ内でssh-add -lを叩くとWindowsssh-addした鍵がずらっと表示されるのだ。
おまけに~/.ssh/known_hostsをコンテナ内にコピーしてくれている。
~/.ssh/configについては何もしてくれないようだが、そこはVS Codeなのでファイルをドロップするなりしてコピーしてしまえば良いだけの話。

ログを確認するとなんらかの方法で\\.\pipe\openssh-ssh-agentと繋いでくれているようなのだが、どうやって実現しているのかは分からなかった。
Dockerの呼び方でどうにかなる話なのか、それともVS Codeや拡張側で橋渡しの処理をしているのか。

コンテナ内のPlaywrightでcodegenを実行する方法(Mac)(ホストに追加ソフト不要)

  1. コンテナ内で次のようにしてcodegenを立ち上げる

     xvfb-run --auth-file /tmp/xvfb-run --server-args="-screen 0 1920x1080x24" -- npx playwright codegen
    
  2. コンテナ内でx11vncを起動

     x11vnc -display :99 -auth /tmp/xvfb-run -passwd パスワード -forever
    
  3. macOS標準の「画面共有」アプリからx11vncに繋ぐ

これだけ。
この辺明るく無いのでもっと良い方法があるかも知れないけれど、とりあえずこれで動く。

CSVをパースするJavaScript(改行や"の表現対応)

Excelから出力したCSVをJavaScriptで読みたいという要望をよく受けており、その度に10年ほど前に自作したパーサーを使い回して対応してきた。
ふと「今ならもっと良いものが作れるのではないか」と思い立って書いてみたところ、昔の自分が作ったものより短く可読性が高い物が出来た。

Excel産CSVは「"」によるエスケープの処理が面倒なのだが、それについては「"の出現数が偶数の状態で,\nが来たら列/行確定とする」と言うシンプルなルールで簡単に対応出来てしまった。
(書き上げてから気付いたのだが、Excel前提なのに\nベースで組んでしまった。まあ入力時にreplaceAllすれば良いので問題ないだろう。)

2026-02-21追記: GitHubにCRLFやBOM対応、パフォーマンス改善を施した最新コードがあります。
https://github.com/crabspider/CSVParser.js

// Copyright (c) 2025 crabspider
// MIT License
// https://github.com/crabspider/CSVParser.js

class CSVParser {
    static parse(csvString, config = {}) {
        // パース手法 「"の出現数が偶数の状態で,\nが来たら列/行確定とする」
        const result = [];
        let row = config.useHeaderAsKey ? {} : [];
        let cellStart = 0;
        let qmCount = 0;

        // useHeaderAsKey用
        let firstRow = [];
        let isFirstRow = true;
        let currentCol = 0;

        // 最終行の処理を簡単にするため、最後が必ず改行コードになるようにする
        csvString = csvString.trimEnd() + '\n';

        for (let i = 0; i < csvString.length; i++) {
            if (csvString[i] === '"') {
                qmCount++;
            } else if ((csvString[i] === ',' || csvString[i] === '\n') && qmCount % 2 === 0) {
                let cellString;
                if (csvString.charAt(cellStart) === '"') {
                    cellString = csvString.slice(cellStart + 1, i - 1);
                } else {
                    cellString = csvString.slice(cellStart, i);
                }
                cellString = cellString.replaceAll('""', '"');

                if (config.useHeaderAsKey) {
                    if (isFirstRow) {
                        firstRow.push(cellString);
                    } else {
                        row[firstRow[currentCol]] = cellString;
                    }
                } else {
                    row.push(cellString);
                }

                cellStart = i + 1;
                qmCount = 0;
                currentCol++;

                if (csvString[i] === '\n') {
                    if (!(isFirstRow && config.useHeaderAsKey)) {
                        result.push(row);
                    }
                    row = config.useHeaderAsKey ? {} : [];
                    currentCol = 0;
                    isFirstRow = false;
                }
            }
        }

        return result;
    }
}

Mac標準機能でWindowsでも開ける圧縮ファイルを作る方法

Mac標準機能でzipファイルを作ると「余分なメタデータが含まれているためWindowsでの解凍時に不要なファイルが出てくる」「Windowsで解凍すると日本語のファイル名が文字化けする」という問題がある。

幸い、近年のWindows/Macは共にメジャーな圧縮形式の解凍に対応しているため、tarコマンドで.tar.xzファイルを作ればこの問題を回避できる。

COPYFILE_DISABLE=1 tar --create --xz --verbose --file 出力.tar.xz 入力

# 圧縮レベルを指定する場合
COPYFILE_DISABLE=1 tar --create --xz --options="xz:compression-level=9" --verbose --file 出力.tar.xz 入力

この手法には次のようなメリットが有る。

  • Mac標準添付のtarコマンドを使うため、ソフトウェアのインストールが不要
  • Windows/Mac共に標準で.tar.xzの解凍に対応しており、この手順で作ったファイルはダブルクリックするだけで開ける。
  • COPYFILE_DISABLE=1指定によりMac特有のゴミファイルが含まれなくなる。
  • xzは7zipと同じくLZMAで圧縮を行うため、圧縮率も期待できる。
    (この点に拘らなければ.tar.gzでも良い)

ファイルを圧縮する度にこんなコマンドを打つのは面倒だが、Automatorでクイックアクションを作る事で右クリックメニューから実行出来るようになる。
その手順についてはChatGPTあたりに相談すると詳しく教えてくれる。

PS Remote Playの「接続先のPS5にログインできませんでした」エラーを解決した話

前提

LAN内のPS5に対しMacからリモートプレイを繋いでいた。

現象

ある日突然「接続先のPS5にログインできませんでした」というエラーが出るようになり、リモートプレイが出来なくなった。
原因になりそうなネットワーク構成・設定の変更は一切無し。

対応

「設定 - ユーザーとアカウント - ログイン設定 - PS5に自動ログイン」をオフにした。

結果

問題無くリモートプレイが遊べるようになった。