pgbigorokuのブログ

プログラムの再利用できそうなコードをアップ

AIでコーディングが楽にしよう!でも油断すると痛い目を見るよ

【初心者必見】

はじめに:AI、強すぎて笑う。でも油断は禁物

最近の開発現場、もうAI抜きでは考えられないですよね。

  • ClaudeやChatGPTでコードを書いてもらって、説明とコメントを整えて
  • 自分は貼り付けて、確認して、はい提出!

こんな流れで、「とりあえず動く」コードなら本当に一瞬で完成します。

でも、ここに落とし穴があるんです。

提出したコードを、AIにもう一度触らせると壊れることがあります。そう、AIは有能だけど無慈悲。「整えますね〜」と言いながら、動いていたコードを平気で壊してきます。

だからこそ、AIを「使うとき」と「使わないとき」の境界線を明確にすることが重要なんです。

提出まではAIにフル依存でOK!

初期の実装フェーズや、動作確認の段階までは、ClaudeでもChatGPTでも使い倒しましょう

AIが得意な作業: - インデント・命名の統一 - コメント補完 - 余計なコードの削除 - 命名整理 & スタイル修正

これらはAIの十八番。手動でやるより圧倒的に早くて綺麗に仕上がります。

ルールは最初に渡しておこう

AIはルールを渡せば優秀ですが、渡さないとズレた結果になることがあります。

例:最初に伝えておくべき命名規則

- camelCaseで関数・変数名を書く
- クラス名やコンポーネント名はPascalCase  
- ファイル名はkebab-case
- 関数コメントはJSDoc形式

これだけで、出てくるコードの質が格段に向上します。

関数には「挙動メモコメント」を必ず書こう(最強テク)

これは本当に効果絶大です。

関数の上に、その関数が何をするか1行でもいいから書くんです。

// ユーザー一覧をAPIから取得して画面に表示する
async function fetchUserList() {
    // ...
}

AIにも人間にも優しく、意図が伝われば整形・修正・リファクタの時に壊されづらくなります

複雑な関数には「詳細メモ」を書け

コードが複雑になるほど、次の情報を書いておくと後々楽になります:

  • 処理の目的
  • 引数の型とその意味(取ってはいけない値も)
  • 戻り値の意味と型
  • 想定されるエラー・例外条件
  • 利用しているライブラリ/API
  • 処理のアルゴリズム(DFS/正規表現パースなど)
  • 特記事項(副作用・依存関係・仕様制限など)

「慣れないと、この項目自体何言ってるの?状態」 だと思いますが、心配無用!Claudeさんがある程度やってくれます

初心者なら先輩に「おー、そこまで気を使ってるのか!でも間違えてるぞw」とか言ってもらえて、むしろ好印象だったりします。

そもそも初心者のコードをそのまま納品するなんてありえないので、きっと全世界の納品されるソースコードは先輩のレビューを通してるはず!?

だから、出しちゃえw

詳細コメントの例

/**
 * 概要: ユーザーの状態を確認し、必要に応じて警告メッセージを返す
 * 引数: user (User型) - ユーザー情報オブジェクト
 * 戻り値: string|null - 警告メッセージ、不要な場合はnull
 * 利用ライブラリ: dayjs
 * 注意: statusプロパティがnullの場合、警告は出さずsilent return
 */
function checkUserStatus(user) {
    // ...
}

⚠️ 提出後の修正はAIに「触らせるな」!

ここが超重要なポイントです。

AIが「ちょっと整えますね〜」とやった結果起こりがちなこと: - 動いていたコードがバグる - 外部との連携が壊れる
- 表面的には整っても、深いところで機能しなくなる

どうすべきか?

  1. 元のコードとAIが修正したコードをdiffで比較
  2. コメントや説明だけコピペして使う
  3. 本体コードは自分の責任で手で書き直す

AIからもらうのは「ヒント」だけ。本体はいじらせない。これが鉄則です。

さらに進んだテク:誰が、なぜ、どうやって作ったかも記録しよう

これは地味ですが、非常に効果的なテクニックです。

理想的なドキュメントコメント例

/**
 * 作成者: HanaSato(Claude原案)
 * 作成日: 2025-05-20
 * 実装環境: Node.js 20 / TypeScript 5.3
 * 概要: 管理画面の月次レポート集計処理
 * テスト: ローカル環境で3種類のダミーデータで確認済み
 * 注意点: データ件数が多いと時間がかかる(要改善)
 * 
 * 改定履歴:
 * - 2025-05-22: null除外条件のバグを修正(by TaroYamada)
 * - 2025-05-24: 出力形式をCSVからJSONに変更(by Claude)
 */

未来のあなた、あるいは他の開発者がこれを見たときの安心感は本当に別次元です。

まとめ:AIは使え。でもコードを守るのは自分だ

フェーズ 使い方
コーディング中 AIに任せてOK。コメント・整形・命名までやらせよう
提出前 自分の目で見直し、挙動コメントや注意点を加える
提出後 AIにコードは触らせるな。コメントだけ抜き取る
保守 改定履歴と背景を残せば、将来の自分も助かる

おわりに

ClaudeやChatGPTは、本当に超有能です。

でもAIを「使う道具」として適切に扱えるかどうかが、現代の開発者に求められるスキルです。

AIに任せるべきところは任せて、でも最後は自分の判断でコードを守る。

コードの未来は、コメントと文脈で決まるんです。


この記事が、AI時代のコーディングで悩む初心者の方の助けになれば幸いです。質問やコメントがあれば、お気軽にどうぞ!

ChatGPTの隠れた環境コスト:サステナブル企業が見落とすAIの落とし穴

目次

はじめに:便利なAIの背後にある環境問題

「AIで業務効率化」「ペーパーレス化でCO₂削減」──これらのフレーズは、サステナビリティを掲げる現代企業にとって日常的なキーワードになっています。

しかし、ChatGPTやGPT-4などのAI利用の裏で消費している膨大な電力について、どれだけの企業が真剣に考慮しているでしょうか?

この記事では、企業のサステナビリティ活動とAI活用の間に生じる矛盾と、その解決策について掘り下げていきます。

ChatGPTの電力消費量:知られざる真実

1回の利用で消費される電力は?

ChatGPT(OpenAI)を1回使用するごとに消費される電力は、モデルの規模にもよりますが、約0.3Whと推定されています。一見わずかに見える数字ですが、企業内で毎日数百、数千のクエリが生成されれば、その合計はLED電球を何時間も点灯させるのと同等のエネルギー消費になります。

Googleの検索と比較すると?

調査によると、ChatGPTのクエリ1回あたりの消費エネルギーは、Google検索の約10倍に相当します。つまり「検索エンジンの代替」として何気なく使うだけでも、想像以上の環境負荷がかかっているのです。

AIモデルによる違い

GPT-4oのような最新モデルは効率性が向上していますが、それでも従来のデジタルツールと比較すると、エネルギー消費は相対的に高いままです。

サステナブル企業が陥る「グリーン・パラドックス

見えない環境コスト

企業が「環境に配慮した経営」をアピールする一方で、AIを日常的に活用していると、実質的なエネルギー使用量が大幅に増加するという矛盾が生じます。

グリーンウォッシングの危険性

意図せずとも、企業の実態と環境メッセージに乖離があれば、それは見せかけの環境配慮と批判される可能性があります。

特に、ESG投資(環境・社会・ガバナンスを重視する投資)が拡大する現在、企業には誠実で透明性のある情報開示が求められています。

データセンターの電力源

AIモデルの多くは大規模データセンターで運用されており、その電力源は必ずしも再生可能エネルギーばかりではありません。AIプロバイダー各社は再生可能エネルギーへの移行を進めていますが、完全な移行にはまだ時間がかかるのが現状です。

AIを環境に配慮して活用する3つの戦略

環境負荷を抑えながらAIの恩恵を受けるために、企業や個人が取り組むべき具体的な対策を紹介します。

AIの使用頻度と用途の最適化

  • 必要性の再評価: すべての業務にAIが必要とは限りません。ルーチン化されたAI利用を見直し、本当に必要な場面に限定しましょう。
  • 使用基準の策定: 組織内でAIの使用ガイドラインを作成し、不必要な使用を減らします。
  • バッチ処理の活用: 類似のクエリをまとめて処理することで、全体的なエネルギー効率を高めることができます。
  • 画像・動画は一髪で出す:1回の画像生成にはテキスト生成の何十倍もの電力が使われます。先にテキストでやりとりして出来るだけ一髪でだしましょう。

AIプロバイダーの選定と協働’(特に大企業)

  • 電力源の確認: AIサービスを提供している企業がどのような電力でデータセンターを運用しているか確認します。
  • 持続可能性の評価: AIプロバイダーの環境への取り組みを評価基準の一つとして導入します。
  • フィードバックの提供: より環境に配慮したAIサービスの開発を促すため、プロバイダーへのフィードバックを積極的に行いましょう。

まとめ:持続可能なAI活用への道

ChatGPTのような生成AIは、業務効率化やクリエイティブ作業を支援する素晴らしいツールです。しかし、その便利さと引き換えに「見えない電力消費」「見えない環境負荷」が確実に存在していることを忘れてはなりません。

真にサステナブルな企業を目指すなら、AIの活用方法を今一度見直し、環境への影響を最小限に抑える工夫が必要です。便利さと環境配慮のバランスを取りながら、将来世代にも持続可能な社会を残していくために、今こそ行動を始めましょう。

よくある質問

Q: ChatGPTの使用によるCO₂排出量はどのくらいですか?

A: 一回のクエリあたり約0.3Whの電力を消費し、電力源によって異なりますが、概算で約0.12g〜0.15gのCO₂を排出すると推定されています。    タスク 推定消費電力(1回あたり) テキスト生成(短文) 0.1〜0.3 Wh 画像生成(512px) 1〜3 Wh 高解像度画像(4K) 10Wh以上もありうる 数秒の動画生成 20〜100Wh以上

Q: 小規模企業でもAIの環境負荷を考慮すべきですか?

A: 規模に関わらず、すべての企業がAI使用による環境影響を意識することが重要です。

Q: 将来的にAIの環境負荷は減少する見込みはありますか?

A: はい、技術の進歩によりAIモデルの効率は向上しており、GPT-4oのような新しいモデルはより少ないエネルギーで動作するように設計されています。また、データセンターの再生可能エネルギー化も進んでいます。


参考文献

  1. Epoch AI - How much energy does ChatGPT use?
  2. BestBrokers - ChatGPTの電力消費量の試算
  3. Financial Times - AI Energy Score project
  4. OpenAI公式ブログ - GPT-4とエネルギー効率
  5. IEA(国際エネルギー機関) – Data Centres and Data Transmission Networks
  6. Hugging Face Blog – Energy Use in Machine Learning

🚀AI×プログラミング:複数AIを管理して実装・テスト・設計までやる方法

イントロダクション

🔥 従来の常識を覆す開発アプローチ 🔥 こんにちは、エンジニアの皆さん!今日は育成AIでいきなりある程度のプログラムができるのに 「なぜ詳細設計から始めるの?」 という根本的な疑問から生まれた、革新的な開発手法をシェアします。

プログラム開発における育成AI活用に関する記事は増えていますが、多くは従来のウォーターフォール的な開発プロセスに沿って、各工程でAIのサポートを受けるというものです。

👴 従来の開発プロセス

人力だけで【詳細設計】→ 📝

人力だけで【プログラミング】→ 💻

人力だけで【単体テスト】→ 🧪

🤖 よくある育成AI活用パターン:

育成AI+人力で【詳細設計】→ 📝 + 🤖

育成AI+人力で【プログラミング】→ 💻 + 🤖

育成AI+人力で【単体テスト】→ 🧪 + 🤖

でも待ってください!私が実践している方法はこれらとは根本的に異なります。

💡で何をしたいのか

【詳細設計】・【プログラミング】・【単体テスト】をひとまとまりにしてAIに下書きさせる!

効果!下書きがあればゼロからドキュメント作るより全然早い!

正確!ドキュメント自体もAIでレビューしてもらう!

※詳細設計~単体テストだけで十分。いまのチャットAIの実力はそのくらいだと思っています

大きな流れ

第1段階: 【前準備】AIチーム編成 🤖👥

第2段階: 【下書き作らせる】メインAIとのやりとり 💬

第3段階: 【チェックさせ合う】多角的コードレビュー 🔍

第4段階: 【従来通り!大事!!】人力による仕上げ 🛠️

第5段階: 【AIによるレビュー】 🔄

第6段階: 【納品!おつー】 🚚

🛠️ 実践方法 🛠️

1️⃣ 第1段階: 【前準備】AIチーム編成 🤖👥

まず、メインとなるチャットAIを選びます。契約しているサービスがあればそれを使うのがベストです。

会話数が非常に多くなるため、利用制限のないサービスが理想的です。

2️⃣第2段階: 【下書きを作らせる】メインAIとのやりとり 💬

2.1 全体の指示(上司から部下への作業依頼スタイル)

👨‍💼「プログラム作るの手伝って」

👨‍💼「開発環境はC言語だよ」

👨‍💼「こういうことがしたいんだ!」(目的や概要を説明)

2.2 プログラミング(⚠️ 詳細設計を飛ばしていきなりコーディング!)

👨‍💼「ファイルを読み込んで表示したい。この場所にテキストファイルがあるはずだけど、ないかもしれないからエラー処理して、読み込んだ結果はコンソールに表示してね」

👨‍💼「じゃあソースコード出して!」

2.3 単体テスト(これも詳細設計なし!)

👨‍💼「すべての分岐を確認するテストプログラム作って」

環境依存のエラーは無視して、実際に修正可能なエラーだけ対処します。プログラミングと単体テストを繰り返して改善していきます。現場の開発っぽいでしょ?😉

3️⃣第3段階: 【チェックさせ合う】多角的コードレビュー 🔍

3.1 メインAIの成果を他のAIに共有 🔄

先ほどの全体指示と最終的なソースコードを別の育成AIに提示します。

3.2 コードレビュー依頼 🔍

👨‍💼「このプログラム、おかしいところないかな?修正して!」

3.3 多数決ではなく「最適解抽出」 🏆

主要な育成AI各々に投げて、それぞれの回答を比較し一番良さそうなソースコードやアイデアを選びます。

🧠 心理戦: AIによって得意分野が異なります。同じコードでも指摘するポイントが全く違うことがあるので、複数のAIに聞くことで盲点を減らせます!

3.4 【⚠️超重要⚠️】人間がコードの最終決定権を持つ

ここからは絶対に育成AIに直接ソースコードをいじらせない! 修正案が来たら自分で修正します。

3.5 複数AIによる単体テストの実施 🧪

主要な育成AI各々に単体テストをさせ、エラーがあれば修正案を提示してもらいます。 繰り返しますが、ソースコードの修正は必ず手作業で行うことが超重要です!

3.6 後付けの詳細設計(逆転の発想!)📝

👨‍💼「専門家のブログ風にこのソースコードは何をしているのかまとめて!」

各AIに依頼し、一番良い説明を選びます。これが「後付けの詳細設計」となります。実は先にコードを書いてから、それを元に設計書を作る方が具体的で良かったりします。

4️⃣ 第4段階: 【従来通り!大事!!】人力による仕上げ 🛠️

この時点で、なんかよくわからないけど動きそうな、コードとドキュメントができているはずです 😂

4.1 人力による詳細設計とプログラミングの洗練 ✨

ここまでの過程で得られた材料を元に、従来通り人力で詳細設計とプログラミングを行います。ただし、ゼロからではなく既存のものを改良する形なので、大幅な時間短縮が可能です。

🎯 目標: AIが80%完成させたものを、人間の知恵で100%に仕上げる

・ 詳細設計を人力でブラッシュアップ

・プログラミングを人力でブラッシュアップ

・テスト仕様書を人力で作成

単体テストを人力で実行

・実際にテストして確認

5️⃣第5段階: 【AIによるレビュー】 🔄

最終レビュー会議(AIメンバーを招集) 🔄

完成した成果物を主要な育成AI各々に確認してもらい、おかしな点がないかチェックします。 自分で「これは仕様だ!」と認識している部分はスルーし、それ以外は再検討します。

6️⃣第6段階: 【納品!おつー】 🚚

これで開発完了、納品に移ります。お疲れ様でした!

何がいいのか!

💯 この「コードファースト×AIマネジメント」アプローチのメリット

⚙️ 従来の順序にとらわれない柔軟性:詳細設計→プログラミング→単体テストという固定観念から脱却し、実践的な開発に近づける

🧩 複数のAIの知見を組み合わせる相乗効果:一つのAIの弱点を他のAIでカバーし、より堅牢なコードを実現

👑 人間が制御する主体性:最終的な判断と修正は人間が行い、AIはあくまでアイデアの源泉として活用

⏱️ 爆速な時間活用:ある程度形になったものを修正する方が、ゼロから作るより圧倒的に効率的

🔧 現場感覚のアプローチ:理想論ではなく、実際の開発現場で行われているような試行錯誤型の開発に近い

🧠 思考の整理:コードを先に書くことで問題点が明確になり、後から設計書を書く方が具体的になる場合も

📈 成果物の質向上:複数のAIによる多角的なレビューで、見落としを防止

🎯 こんな人におすすめ

✅ 締め切りに追われているプロジェクトリーダー

✅ 詳細設計に時間をかけすぎて実装が遅れがちな開発者

✅ AIの力を最大限活用したい効率重視のエンジニア

✅ 「動くものから改良する」アジャイル的思考の持ち主

✅ 複数のAIサービスに課金している人(投資を回収したい人)

🌟 核心: AIはツールではなく「チームメンバー」として扱え!

皆さんも、ぜひこの「できの悪いチャットAI 4人組をマネージメント」するアプローチを試してみてください。新たな効率化と発見があるかもしれません。

あなたのAIマネジメント体験、コメント欄でぜひシェアしてください!👇

🌈 AIチーム編成のベストプラクティス:おすすめAIランキング 🚀

「できの悪いチャットAI 4人組」を効果的にマネージするには? 🤔

各AIの特性を理解し、適切に役割分担することが成功への鍵です!以下に、実践経験に基づくAIランキングと活用法をご紹介します。

🏆 AI能力ランキング

🥇 最優秀マネージャー候補:Claude

強み:

📝 長文の理解力

🧠 文脈把握能力

💻 コードの論理性チェック

特記事項:

個人的に一番キレイなソースコードや文章を出してくれる(でもミスはある)

🥈 実装スペシャリスト:ChatGPT

強み:

📚 API仕様の把握

🌐 多様な言語への対応力

🧰 特定フレームワークの活用

🐞 細かいバグ修正

特記事項: 意外な指摘をしてくれる。便利だけどすぐに前に言ったこと忘れる

🥉 サポートメンバー:その他のAIアシスタント

強み:

🔍 異なる視点の提供

🧪 特定分野の専門知識

🕵️ 盲点のチェック

🔄 多角的な意見収集

特記事項:

まぁ、このあたりは振り回されない程度に利用がおすすめ。

🚀 コードファースト×AIマネジメント開発フロー

プロセスのチェックリスト

■■■ 第1段階:AIチーム編成■■■

□ AIを選定(最低でもメインAIとサブ1つ、可能ならサブ3種類ぐらい。)

□ 会話制限・利用条件を確認

■■■ 第2段階:下書き生成(メインAIと対話)■■■

□ 全体指示を出す(目的・概要・環境など)

□ 処理内容を細かく伝える(例:ファイル読み込みをしたいなど)

ソースコードを出力させる

□ 分岐網羅のテストコードを作らせる

□ プログラムとテストを繰り返して修正

■■■ 第3段階:コードレビュー(他AIに依頼)■■■

□ 成果物(プログラム)を他AIに共有

□ コードレビュー依頼

ソースコードを1つ決定する!これ以降はAIにソースコードを直接編集させない。

□ 各AIで単体テスト実行&バグ報告を受ける

□ 後付けで設計説明を依頼・比較・選定

■■■ 第4段階:人力で仕上げ■■■

□ 詳細設計を人力でブラッシュアップ

□プログラミングを人力でブラッシュアップ

□ テスト仕様書を人力で作成

単体テストを人力で実行

□ 実際にテストして確認

■■■ 第5段階:AIレビュー■■■

□ 各AIに最終成果物を確認させる

□ 指摘事項を再検討(仕様外かどうかを確認)

■■■ 第6段階:納品■■■

□ 成果物一式をまとめる(コード・設計書・テスト結果)

□ 納品

□ 完了&お疲れ様!

このブログは実際の開発経験をもとに作成しています。環境や要件によって最適なアプローチは異なりますので、自分のプロジェクトに合わせてカスタマイズしてください。

いまのチャットAIの実力では、関数の利用が限界だと思っています。それ以上は手戻りが多すぎて逆に効率が落ちます。

VBA アクティブシートの指定された2つの列を比較する(デバッグしきれてませんが動きますw)

Option Explicit


'/**
' * メイン実行プロシージャ
' * アクティブシートの指定された2つの列を比較する
' *  URL: https://pgbigoroku.hatenablog.com/entry/2025/05/16/004236
' */
Public Sub 実行_2列を比較して差分を新ブックに出力()
    ' ユーザー入力(列番号)
    Dim lngCol旧 As Long
    Dim lngCol新 As Long
    Dim lngStartRow As Long
    Dim blnHasHeader As Boolean
    
    ' ユーザー入力(列番号)
    lngCol旧 = InputBox("比較元の列番号を入力してください(A列=1, B列=2, ...):", "列比較", 1)
    If lngCol旧 = 0 Then Exit Sub
    
    lngCol新 = InputBox("比較先の列番号を入力してください(A列=1, B列=2, ...):", "列比較", 2)
    If lngCol新 = 0 Then Exit Sub
    
    ' 開始行
    lngStartRow = InputBox("比較を開始する行番号を入力してください:", "列比較", 1)
    If lngStartRow = 0 Then Exit Sub
    
    ' ヘッダーあり/なし
    blnHasHeader = (MsgBox("1行目をヘッダー行として扱いますか?", vbYesNo) = vbYes)
    
    ' 処理実行
    プロシージャ列比較と差分出力 ActiveSheet, lngCol旧, lngCol新, lngStartRow, blnHasHeader
End Sub



'/**
' * 2つの列データを比較し、差分を新しいブックに出力する関数
' *
' * @param pws対象シート      Worksheet : 比較対象の列が存在するシート
' * @param plng旧列番号       Long      : 比較元の列番号 (例: A列なら1)
' * @param plng新列番号       Long      : 比較先の列番号 (例: B列なら2)
' * @param plng開始行         Long      : 比較を開始する行番号 (デフォルト: 1)
' * @param pblnヘッダー行あり Boolean   : 1行目をヘッダーとして扱うか (デフォルト: True)
' *
' * 出力内容:新しいブックにA列(旧データ)、B列(新データ)、C列(差分コメント)を出力
' * 色分け:緑(追加)、赤(削除)、オレンジ(変更)
' *  URL: https://pgbigoroku.hatenablog.com/entry/2025/05/16/004236
' */
Public Sub プロシージャ列比較と差分出力( _
    ByVal pws対象シート As Worksheet, _
    ByVal plng旧列番号 As Long, _
    ByVal plng新列番号 As Long, _
    Optional ByVal plng開始行 As Long = 1, _
    Optional ByVal pblnヘッダー行あり As Boolean = True _
)
    ' 変数定義
    Dim wbk出力ブック As Workbook
    Dim ws出力シート As Worksheet
    Dim lngMaxRow旧 As Long
    Dim lngMaxRow新 As Long
    Dim lngStartRow As Long
    Dim lngLoop As Long
    Dim str旧 As String, str新 As String
    Dim lngOutRow As Long
    Dim str差分 As String
    
    ' セルデータ範囲を判断
    lngMaxRow旧 = pws対象シート.Cells(pws対象シート.Rows.Count, plng旧列番号).End(xlUp).Row
    lngMaxRow新 = pws対象シート.Cells(pws対象シート.Rows.Count, plng新列番号).End(xlUp).Row
    
    If pblnヘッダー行あり Then
        lngStartRow = plng開始行 + 1  ' ヘッダー行の次から開始
    Else
        lngStartRow = plng開始行  ' 指定行から直接開始
    End If
    
    ' 旧データと新データを配列に格納
    Dim arr旧() As Variant
    Dim arr新() As Variant
    ReDim arr旧(1 To lngMaxRow旧 - lngStartRow + 1)
    ReDim arr新(1 To lngMaxRow新 - lngStartRow + 1)
    
    For lngLoop = lngStartRow To lngMaxRow旧
        arr旧(lngLoop - lngStartRow + 1) = pws対象シート.Cells(lngLoop, plng旧列番号).Value
    Next lngLoop
    
    For lngLoop = lngStartRow To lngMaxRow新
        arr新(lngLoop - lngStartRow + 1) = pws対象シート.Cells(lngLoop, plng新列番号).Value
    Next lngLoop
    
    ' 出力用新規ブックを作成
    Set wbk出力ブック = Workbooks.Add
    Set ws出力シート = wbk出力ブック.Sheets(1)
    ws出力シート.Name = "列比較結果"
    
    ' ヘッダー設定
    If pblnヘッダー行あり Then
        ' ヘッダー行をコピー
        ws出力シート.Cells(1, 1).Value = pws対象シート.Cells(plng開始行, plng旧列番号).Value
        ws出力シート.Cells(1, 2).Value = pws対象シート.Cells(plng開始行, plng新列番号).Value
        ws出力シート.Cells(1, 3).Value = "差分コメント"
    Else
        ' ヘッダー行を設定
        ws出力シート.Cells(1, 1).Value = "旧データ"
        ws出力シート.Cells(1, 2).Value = "新データ"
        ws出力シート.Cells(1, 3).Value = "差分コメント"
    End If
    
    ' ヘッダー行の書式設定
    With ws出力シート.Range("A1:C1")
        .Font.Bold = True
        .Interior.Color = RGB(220, 220, 220)
    End With
    
    ' LCSアルゴリズムを使用した行単位の差分分析
    Dim LCS結果 As Collection
    Set LCS結果 = LCS行単位で最適化した差分取得(arr旧, arr新)
    
    ' 出力開始行
    lngOutRow = 2
    
    ' LCS結果を基に差分データを出力
    Dim str操作 As String
    Dim lng旧idx As Long
    Dim lng新idx As Long
    Dim varLCSItem As Variant
    
    For lngLoop = 1 To LCS結果.Count
        varLCSItem = LCS結果(lngLoop)
        str操作 = varLCSItem(0)
        lng旧idx = varLCSItem(1)
        lng新idx = varLCSItem(2)
        
        Select Case str操作
            Case "共通"
                ' 変更なしの行
                ws出力シート.Cells(lngOutRow, 1).Value = arr旧(lng旧idx)
                ws出力シート.Cells(lngOutRow, 2).Value = arr新(lng新idx)
                ws出力シート.Cells(lngOutRow, 3).Value = ""
                
            Case "追加"
                ' 追加行の処理 - A列は空白にする
                ws出力シート.Cells(lngOutRow, 1).Value = ""
                ws出力シート.Cells(lngOutRow, 2).Value = arr新(lng新idx)
                ws出力シート.Cells(lngOutRow, 3).Value = "【追加】"
                ws出力シート.Cells(lngOutRow, 2).Interior.Color = RGB(200, 255, 200) ' 緑色
            
            Case "削除"
                ' 削除行の処理 - B列は空白にする
                ws出力シート.Cells(lngOutRow, 1).Value = arr旧(lng旧idx)
                ws出力シート.Cells(lngOutRow, 2).Value = ""
                ws出力シート.Cells(lngOutRow, 3).Value = "【削除】"
                ws出力シート.Cells(lngOutRow, 1).Interior.Color = RGB(255, 200, 200) ' 赤色
            
            Case "変更"
                ' 変更行の処理
                ws出力シート.Cells(lngOutRow, 1).Value = arr旧(lng旧idx)
                ws出力シート.Cells(lngOutRow, 2).Value = arr新(lng新idx)
                
                ' 文字レベルの差分を取得
                str差分 = fnc文字を2つ比較して差分(CStr(arr旧(lng旧idx)), CStr(arr新(lng新idx)))
                If str差分 = "" Then
                    ws出力シート.Cells(lngOutRow, 3).Value = "【変更】"
                Else
                    ws出力シート.Cells(lngOutRow, 3).Value = "【変更】" & str差分
                End If
                
                ' 変更箇所のハイライト
                ws出力シート.Cells(lngOutRow, 1).Interior.Color = RGB(255, 230, 200) ' オレンジ色
                ws出力シート.Cells(lngOutRow, 2).Interior.Color = RGB(255, 230, 200) ' オレンジ色
        End Select
        
        lngOutRow = lngOutRow + 1
    Next lngLoop
    
    ' 列幅の調整
    ws出力シート.Columns("A:C").AutoFit
    
    ' 結果メッセージ
    MsgBox "列比較が完了しました。" & vbCrLf & _
           "差分は新しいブックに出力されています。", vbInformation
End Sub

'/**
' * LCSアルゴリズムを使用して、2つの配列の差分を最適化して取得する強化版関数
' * 行単位で最適な差分を検出し、追加/削除/変更/共通の操作と該当インデックスを返す
' *
' * @param arr旧 配列 : 元データの配列
' * @param arr新 配列 : 新データの配列
' * @return Collection : 操作とインデックスのコレクション (操作, 旧idx, 新idx)
' *  URL: https://pgbigoroku.hatenablog.com/entry/2025/05/16/004236
' */
Private Function LCS行単位で最適化した差分取得(ByVal arr旧 As Variant, ByVal arr新 As Variant) As Collection
    Dim i As Long, j As Long, k As Long
    Dim lngLen旧 As Long: lngLen旧 = UBound(arr旧)
    Dim lngLen新 As Long: lngLen新 = UBound(arr新)
    
    ' LCS行列を生成
    Dim LCS() As Long
    ReDim LCS(0 To lngLen旧, 0 To lngLen新)
    
    ' LCS行列を計算
    For i = 1 To lngLen旧
        For j = 1 To lngLen新
            If CStr(arr旧(i)) = CStr(arr新(j)) Then
                LCS(i, j) = LCS(i - 1, j - 1) + 1
            Else
                LCS(i, j) = Application.WorksheetFunction.Max(LCS(i - 1, j), LCS(i, j - 1))
            End If
        Next j
    Next i
    
    ' バックトレースして差分操作を取得
    Dim 結果 As New Collection
    Dim スタック As New Collection
    
    i = lngLen旧
    j = lngLen新
    
    While i > 0 Or j > 0
        If i > 0 And j > 0 And CStr(arr旧(i)) = CStr(arr新(j)) Then
            ' 共通要素を検出
            スタック.Add Array("共通", i, j)
            i = i - 1
            j = j - 1
        ElseIf j > 0 And (i = 0 Or LCS(i, j - 1) >= LCS(i - 1, j)) Then
            ' 新規追加を検出
            スタック.Add Array("追加", 0, j)
            j = j - 1
        ElseIf i > 0 And (j = 0 Or LCS(i, j - 1) < LCS(i - 1, j)) Then
            ' 削除を検出
            スタック.Add Array("削除", i, 0)
            i = i - 1
        End If
    Wend
    
    ' スタックを逆順に結果に追加
    For i = スタック.Count To 1 Step -1
        結果.Add スタック(i)
    Next i
    
    ' 変更操作の最適化(隣接する削除+追加を変更に変換)
    Dim 最適化結果 As New Collection
    i = 1
    
    While i <= 結果.Count
        If i < 結果.Count Then
            Dim 現在項目 As Variant: 現在項目 = 結果(i)
            Dim 次項目 As Variant: 次項目 = 結果(i + 1)
            
            ' 削除の次に追加がある場合は変更として統合
            If 現在項目(0) = "削除" And 次項目(0) = "追加" Then
                最適化結果.Add Array("変更", 現在項目(1), 次項目(2))
                i = i + 2
            Else
                最適化結果.Add 現在項目
                i = i + 1
            End If
        Else
            最適化結果.Add 結果(i)
            i = i + 1
        End If
    Wend
    
    Set LCS行単位で最適化した差分取得 = 最適化結果
End Function

'//**
' * 変更前・変更後の2つの文字列を比較し、
' * 差分(削除・追加・変更)を意味的ブロック単位で出力する関数
' *
' * 主な処理ステップ:
' *   1. 最長共通部分列(LCS)テーブルを作成
' *   2. 差分トレース(追加/削除/共通)を取得
' *   3. 差分をブロック単位(まとめ)で整形して出力
' *
' * 出力形式:
' *   "[旧文字列→新文字列]" のようなブロックを複数行に渡って返す
' *   使用する記号はOptional引数でカスタマイズ可能
' *
' * @param pstr変更前      String  : 比較元の文字列(Before)
' * @param pstr変更後      String  : 比較先の文字列(After)
' * @param strEqual        Optional String : 共通文字の識別記号(既定値: "=")
' * @param strAdd          Optional String : 追加操作の識別記号(既定値: "+")
' * @param strDelete       Optional String : 削除操作の識別記号(既定値: "-")
' * @param strBlockStart   Optional String : 差分ブロックの開始記号(既定値: "[")
' * @param strArrow        Optional String : 差分ブロックの区切り記号(既定値: "→")
' * @param strBlockEnd     Optional String : 差分ブロックの終了記号(既定値: "]")
' *
' * @return String : テキスト差分抽出("[a→b]"形式)の文字列(複数行)
' */
Public Function fnc文字を2つ比較して差分( _
ByVal pstr変更前 As String, _
ByVal pstr変更後 As String, _
Optional ByVal strEqual As String = "=", _
Optional ByVal strAdd As String = "+", _
Optional ByVal strDelete As String = "-", _
Optional ByVal strBlockStart As String = "[", _
Optional ByVal strArrow As String = "→", _
Optional ByVal strBlockEnd As String = "]" _
) As String

    ' Nullチェック
    If pstr変更前 = "" And pstr変更後 = "" Then
        fnc文字を2つ比較して差分 = ""
        Exit Function
    End If
    
    ' Nullチェック - どちらかが空の場合
    If pstr変更前 = "" Then
        fnc文字を2つ比較して差分 = strBlockStart & "1文字目: " & strBlockEnd & vbCrLf & _
                              strBlockStart & "→" & pstr変更後 & strBlockEnd
        Exit Function
    End If
    
    If pstr変更後 = "" Then
        fnc文字を2つ比較して差分 = strBlockStart & "1文字目: " & pstr変更前 & "→" & strBlockEnd
        Exit Function
    End If

    Dim alngLCS() As Long
    alngLCS = nfnc文字を2つ比較して差分_fnc作成LCS配列(pstr変更前, pstr変更後)

    Dim col差分操作列 As Collection
    Set col差分操作列 = nfnc文字を2つ比較して差分_fnc差分トレース( _
        pstr変更前, pstr変更後, alngLCS, _
        strEqual, strAdd, strDelete _
    )

    Dim str出力差分 As String
    str出力差分 = fnc文字を2つ比較して差分_fnc差分をブロック化( _
        col差分操作列, _
        strEqual, strDelete, strAdd, _
        strBlockStart, strArrow, strBlockEnd _
    )

    fnc文字を2つ比較して差分 = str出力差分

End Function

'//**
' * 2つの文字列から最長共通部分列(LCS)の動的計画法(DP)テーブルを生成する
' *
' * LCSとは:
' *    並び順を変えずに取り出せる共通部分列の中で最長のものを言う。
' *    例: "ABCDEF" と "ACEF" → LCS = "ACEF"
' *
' * DPテーブルには各部分列の最大共通長が格納される。
' *
' * @param str対象1 String : 1つ目の文字列(変更前)
' * @param str対象2 String : 2つ目の文字列(変更後)
' * @return Variant(2次元Long配列) : LCS用DPテーブル
' */
Private Function nfnc文字を2つ比較して差分_fnc作成LCS配列( _
ByVal str対象1 As String, _
ByVal str対象2 As String _
) As Variant

    Dim lngLen1 As Long: lngLen1 = Len(str対象1)        ' 文字列1の長さ
    Dim lngLen2 As Long: lngLen2 = Len(str対象2)        ' 文字列2の長さ

    Dim alngLCS() As Long                               ' LCSテーブル本体(2次元)
    ReDim alngLCS(0 To lngLen1, 0 To lngLen2)           ' (0,0) から使う

    Dim lngRow As Long, lngCol As Long
    For lngRow = 1 To lngLen1
        For lngCol = 1 To lngLen2
            ' 現在の文字が一致している場合 → 左上のマス +1
            If Mid(str対象1, lngRow, 1) = Mid(str対象2, lngCol, 1) Then
                alngLCS(lngRow, lngCol) = alngLCS(lngRow - 1, lngCol - 1) + 1

            ' 不一致 → 左 or 上 の最大値を使う
            Else
                alngLCS(lngRow, lngCol) = Application.WorksheetFunction.Max( _
                                            alngLCS(lngRow - 1, lngCol), _
                                            alngLCS(lngRow, lngCol - 1))
            End If
        Next lngCol
    Next lngRow

    nfnc文字を2つ比較して差分_fnc作成LCS配列 = alngLCS

End Function

'//**
' * 2つの文字列とLCS配列をもとに、変更前→変更後の差分操作列を生成する。
' *
' * 操作は以下のように分類され、記号は任意に変更可能:
' *   strEqual : 共通文字(変更なし)
' *   strAdd   : 変更後にのみ存在(追加)
' *   strDelete: 変更前にのみ存在(削除)
' *
' * 戻り値のCollectionは末尾から先頭へたどった結果なので、
' * 呼び出し元で正順に処理したい場合は逆順処理が必要。
' *
' * @param str変更前    String  : 変更前の文字列
' * @param str変更後    String  : 変更後の文字列
' * @param avarLCS配列  Variant : LCS動的配列(2次元)
' * @param strEqual     Optional String : 共通文字の識別記号(既定値: "=")
' * @param strAdd       Optional String : 追加操作の識別記号(既定値: "+")
' * @param strDelete    Optional String : 削除操作の識別記号(既定値: "-")
' *
' * @return Collection 差分操作(記号と対象文字の配列)を格納したCollection
' */
Private Function nfnc文字を2つ比較して差分_fnc差分トレース( _
ByVal str変更前 As String, _
ByVal str変更後 As String, _
ByVal avarLCS配列 As Variant, _
Optional ByVal strEqual As String = "=", _
Optional ByVal strAdd As String = "+", _
Optional ByVal strDelete As String = "-" _
) As Collection

    Dim lngIdx変更前 As Long: lngIdx変更前 = Len(str変更前)
    Dim lngIdx変更後 As Long: lngIdx変更後 = Len(str変更後)

    Dim col差分操作列 As New Collection
    Dim str前文字 As String, str後文字 As String

    Do While lngIdx変更前 > 0 Or lngIdx変更後 > 0

        If lngIdx変更前 > 0 And lngIdx変更後 > 0 Then
            str前文字 = Mid(str変更前, lngIdx変更前, 1)
            str後文字 = Mid(str変更後, lngIdx変更後, 1)

            If str前文字 = str後文字 Then
                col差分操作列.Add Array(strEqual, str前文字)
                lngIdx変更前 = lngIdx変更前 - 1
                lngIdx変更後 = lngIdx変更後 - 1

            ElseIf avarLCS配列(lngIdx変更前, lngIdx変更後 - 1) >= avarLCS配列(lngIdx変更前 - 1, lngIdx変更後) Then
                col差分操作列.Add Array(strAdd, str後文字)
                lngIdx変更後 = lngIdx変更後 - 1

            Else
                col差分操作列.Add Array(strDelete, str前文字)
                lngIdx変更前 = lngIdx変更前 - 1
            End If

        ElseIf lngIdx変更後 > 0 Then
            col差分操作列.Add Array(strAdd, Mid(str変更後, lngIdx変更後, 1))
            lngIdx変更後 = lngIdx変更後 - 1

        ElseIf lngIdx変更前 > 0 Then
            col差分操作列.Add Array(strDelete, Mid(str変更前, lngIdx変更前, 1))
            lngIdx変更前 = lngIdx変更前 - 1
        End If

    Loop

    Set nfnc文字を2つ比較して差分_fnc差分トレース = col差分操作列

End Function

'//**
' * 差分操作列からわかりやすい差分ブロックを生成する
' *
' * @param pcolDiffs Collection : 差分操作列
' * @param strEqual     Optional String : 共通文字の識別記号(既定値: "=")
' * @param strDelete    Optional String : 削除操作の識別記号(既定値: "-")
' * @param strAdd       Optional String : 追加操作の識別記号(既定値: "+")
' * @param strBlockStart Optional String : ブロック開始記号(既定値: "[")
' * @param strArrow     Optional String : 変更前後の区切り記号(既定値: "→")
' * @param strBlockEnd  Optional String : ブロック終了記号(既定値: "]")
' *
' * @return String : 整形された差分テキスト
' */
Private Function fnc文字を2つ比較して差分_fnc差分をブロック化( _
ByVal pcolDiffs As Collection, _
Optional ByVal strEqual As String = "=", _
Optional ByVal strDelete As String = "-", _
Optional ByVal strAdd As String = "+", _
Optional ByVal strBlockStart As String = "[", _
Optional ByVal strArrow As String = "→", _
Optional ByVal strBlockEnd As String = "]") As String

    Dim strResult As String
    Dim lngIndex As Long
    Dim strBuf追加 As String
    Dim strBuf削除 As String
    Dim varDiffItem As Variant
    Dim lng位置変更前 As Long: lng位置変更前 = 0 ' 変更前文字列のインデックス追跡用
    Dim lng現在位置 As Long: lng現在位置 = 1     ' 文字列上の現在位置カウント(1から開始)
    Dim lng変更開始位置 As Long                  ' 差分ブロックの先頭位置を記録

    ' 差分を逆順で処理
    For lngIndex = pcolDiffs.Count To 1 Step -1
        varDiffItem = pcolDiffs(lngIndex)

        Select Case varDiffItem(0)

            Case strEqual
                If strBuf追加 <> "" Or strBuf削除 <> "" Then
                    strResult = strBlockStart & lng変更開始位置 & "文字目: " & strBuf削除 & strArrow & strBuf追加 & strBlockEnd & vbCrLf & strResult
                    strBuf追加 = ""
                    strBuf削除 = ""
                End If
                lng現在位置 = lng現在位置 + 1

            Case strAdd
                If strBuf追加 = "" And strBuf削除 = "" Then
                    lng変更開始位置 = lng現在位置
                End If
                strBuf追加 = strBuf追加 & varDiffItem(1)

            Case strDelete
                If strBuf追加 = "" And strBuf削除 = "" Then
                    lng変更開始位置 = lng現在位置
                End If
                strBuf削除 = strBuf削除 & varDiffItem(1)
                lng現在位置 = lng現在位置 + 1

        End Select
    Next lngIndex

    ' 最後に残った差分ブロックの出力
    If strBuf追加 <> "" Or strBuf削除 <> "" Then
        strResult = strBlockStart & lng変更開始位置 & "文字目: " & strBuf削除 & strArrow & strBuf追加 & strBlockEnd & vbCrLf & strResult
    End If

    fnc文字を2つ比較して差分_fnc差分をブロック化 = Trim(strResult)

End Function

EXCEL VBA 文字を2つ比較して差分(削除・追加・変更)を出力する関数

EXCEL VBA 文字を2つ比較して差分(削除・追加・変更)を意味的ブロック単位で出力する関数

文字列差分抽出VBA:全体構成と処理ステップ

やりたいこと

変更前と変更後の文字列から「何が削除され、何が追加されたか」を
意味のあるかたまり(ブロック)で抽出する。
出力は "[削除→追加]" の形。

例:
入力:
- 変更前: abcdef
- 変更後: abxyef
出力:
- [cd→xy]

処理ステップ(3ステップ)

[ステップ1] LCS(最長共通部分列)を求める
→ 「どこが共通か」を判定するための基礎

[ステップ2] 差分をトレース(逆順に走査)
→ LCSをもとに「追加」「削除」「一致」を1文字単位で判定
→ 結果は Collection で保持(例: { "-", "c" }, { "+", "x" })

[ステップ3] 差分をブロックに整形
→ 連続する削除・追加をまとめて "[削除→追加]" に変換
→ 出力は改行付きのテキスト形式

関数構成

関数名 役割
`fnc文字を2つ比較して差分` メイン処理。全体を統括する
`nfnc文字を2つ比較して差分_fnc作成LCS配列` LCS(共通部分)のDP配列を作成
`nfnc文字を2つ比較して差分_fnc差分トレース` 文字ごとの差分を判定
`fnc文字を2つ比較して差分_fnc差分をブロック化` 差分をまとめて出力文字列に変換

出力フォーマット(デフォルト)

  • "[abc→xyz]":abcが削除され、xyzが追加された
  • "[→xyz]":追加だけ
  • "[abc→]":削除だけ

カスタマイズ可能な記号(オプション引数)

  • 共通記号:strEqual(デフォルト "=")
  • 追加記号:strAdd(デフォルト "+")
  • 削除記号:strDelete(デフォルト "-")
  • ブロック記号:strBlockStart, strArrow, strBlockEnd(デフォルト "[", "→", "]")

補足

  • 差分は「意味的に連続したブロック」にまとめて出力されるため、

見た目も分かりやすく、差分管理やログ出力にも向いている。

サンプルコード

Sub サンプルコード()
    MsgBox fnc文字を2つ比較して差分("aga", "acca")       ' → [g→cc]
    MsgBox fnc文字を2つ比較して差分("", "acccabb")        ' → [→acccabb]
    MsgBox fnc文字を2つ比較して差分("hello", "hero")      ' → [ll→r]
    MsgBox fnc文字を2つ比較して差分("abc", "xyz")         ' → [abc→xyz]
End Sub


ソースコード

Option Explicit

'/**
' * 変更前・変更後の2つの文字列を比較し、
' * 差分(削除・追加・変更)を意味的ブロック単位で出力する関数
' *
' * 主な処理ステップ:
' *   1. 最長共通部分列(LCS)テーブルを作成
' *   2. 差分トレース(追加/削除/共通)を取得
' *   3. 差分をブロック単位(まとめ)で整形して出力
' *
' * 出力形式:
' *   "[旧文字列→新文字列]" のようなブロックを複数行に渡って返す
' *   使用する記号はOptional引数でカスタマイズ可能
' *
' * @param pstr変更前      String  : 比較元の文字列(Before)
' * @param pstr変更後      String  : 比較先の文字列(After)
' * @param strEqual        Optional String : 共通文字の識別記号(既定値: "=")
' * @param strAdd          Optional String : 追加操作の識別記号(既定値: "+")
' * @param strDelete       Optional String : 削除操作の識別記号(既定値: "-")
' * @param strBlockStart   Optional String : 差分ブロックの開始記号(既定値: "[")
' * @param strArrow        Optional String : 差分ブロックの区切り記号(既定値: "→")
' * @param strBlockEnd     Optional String : 差分ブロックの終了記号(既定値: "]")
' *
' * @return String : テキスト差分抽出("[a→b]"形式)の文字列(複数行)
' *
' * ソースコードURL https://pgbigoroku.hatenablog.com/entry/2025/05/14/211840
' * Version 2025.5.14
' */
Public Function fnc文字を2つ比較して差分( _
    ByVal pstr変更前 As String, _
    ByVal pstr変更後 As String, _
    Optional ByVal strEqual As String = "=", _
    Optional ByVal strAdd As String = "+", _
    Optional ByVal strDelete As String = "-", _
    Optional ByVal strBlockStart As String = "[", _
    Optional ByVal strArrow As String = "→", _
    Optional ByVal strBlockEnd As String = "]" _
) As String

    Dim alngLCS() As Long
    alngLCS = nfnc文字を2つ比較して差分_fnc作成LCS配列(pstr変更前, pstr変更後)

    Dim col差分操作列 As Collection
    Set col差分操作列 = nfnc文字を2つ比較して差分_fnc差分トレース( _
        pstr変更前, pstr変更後, alngLCS, _
        strEqual, strAdd, strDelete _
    )

    Dim str出力差分 As String
    str出力差分 = fnc文字を2つ比較して差分_fnc差分をブロック化( _
        col差分操作列, _
        strEqual, strDelete, strAdd, _
        strBlockStart, strArrow, strBlockEnd _
    )

    fnc文字を2つ比較して差分 = str出力差分

End Function




'/**
' * 2つの文字列から最長共通部分列(LCS)の動的計画法(DP)テーブルを生成する
' *
' * LCSとは:
' *    並び順を変えずに取り出せる共通部分列の中で最長のものを言う。
' *    例: "ABCDEF" と "ACEF" → LCS = "ACEF"
' *
' * DPテーブルには各部分列の最大共通長が格納される。
' *
' * @param str対象1 String : 1つ目の文字列(変更前)
' * @param str対象2 String : 2つ目の文字列(変更後)
' * @return Variant(2次元Long配列) : LCS用DPテーブル
' */
Private Function nfnc文字を2つ比較して差分_fnc作成LCS配列( _
    ByVal str対象1 As String, _
    ByVal str対象2 As String _
) As Variant

    Dim lngLen1 As Long: lngLen1 = Len(str対象1)        ' 文字列1の長さ
    Dim lngLen2 As Long: lngLen2 = Len(str対象2)        ' 文字列2の長さ

    Dim alngLCS() As Long                               ' LCSテーブル本体(2次元)
    ReDim alngLCS(0 To lngLen1, 0 To lngLen2)           ' (0,0) から使う

    Dim lngRow As Long, lngCol As Long
    For lngRow = 1 To lngLen1
        For lngCol = 1 To lngLen2
            ' 現在の文字が一致している場合 → 左上のマス +1
            If Mid(str対象1, lngRow, 1) = Mid(str対象2, lngCol, 1) Then
                alngLCS(lngRow, lngCol) = alngLCS(lngRow - 1, lngCol - 1) + 1

            ' 不一致 → 左 or 上 の最大値を使う
            Else
                alngLCS(lngRow, lngCol) = Application.WorksheetFunction.Max( _
                                            alngLCS(lngRow - 1, lngCol), _
                                            alngLCS(lngRow, lngCol - 1))
            End If
        Next lngCol
    Next lngRow

    nfnc文字を2つ比較して差分_fnc作成LCS配列 = alngLCS

End Function




'/**
' * 2つの文字列とLCS配列をもとに、変更前→変更後の差分操作列を生成する。
' *
' * 操作は以下のように分類され、記号は任意に変更可能:
' *   strEqual : 共通文字(変更なし)
' *   strAdd   : 変更後にのみ存在(追加)
' *   strDelete: 変更前にのみ存在(削除)
' *
' * 戻り値のCollectionは末尾から先頭へたどった結果なので、
' * 呼び出し元で正順に処理したい場合は逆順処理が必要。
' *
' * @param str変更前    String  : 変更前の文字列
' * @param str変更後    String  : 変更後の文字列
' * @param avarLCS配列  Variant : LCS動的配列(2次元)
' * @param strEqual     Optional String : 共通文字の識別記号(既定値: "=")
' * @param strAdd       Optional String : 追加操作の識別記号(既定値: "+")
' * @param strDelete    Optional String : 削除操作の識別記号(既定値: "-")
' *
' * @return Collection 差分操作(記号と対象文字の配列)を格納したCollection
' */
Private Function nfnc文字を2つ比較して差分_fnc差分トレース( _
    ByVal str変更前 As String, _
    ByVal str変更後 As String, _
    ByVal avarLCS配列 As Variant, _
    Optional ByVal strEqual As String = "=", _
    Optional ByVal strAdd As String = "+", _
    Optional ByVal strDelete As String = "-" _
) As Collection

    Dim lngIdx変更前 As Long: lngIdx変更前 = Len(str変更前)
    Dim lngIdx変更後 As Long: lngIdx変更後 = Len(str変更後)

    Dim col差分操作列 As New Collection
    Dim str前文字 As String, str後文字 As String

    Do While lngIdx変更前 > 0 Or lngIdx変更後 > 0

        If lngIdx変更前 > 0 And lngIdx変更後 > 0 Then
            str前文字 = Mid(str変更前, lngIdx変更前, 1)
            str後文字 = Mid(str変更後, lngIdx変更後, 1)

            If str前文字 = str後文字 Then
                col差分操作列.Add Array(strEqual, str前文字)
                lngIdx変更前 = lngIdx変更前 - 1
                lngIdx変更後 = lngIdx変更後 - 1

            ElseIf avarLCS配列(lngIdx変更前, lngIdx変更後 - 1) >= avarLCS配列(lngIdx変更前 - 1, lngIdx変更後) Then
                col差分操作列.Add Array(strAdd, str後文字)
                lngIdx変更後 = lngIdx変更後 - 1

            Else
                col差分操作列.Add Array(strDelete, str前文字)
                lngIdx変更前 = lngIdx変更前 - 1
            End If

        ElseIf lngIdx変更後 > 0 Then
            col差分操作列.Add Array(strAdd, Mid(str変更後, lngIdx変更後, 1))
            lngIdx変更後 = lngIdx変更後 - 1

        ElseIf lngIdx変更前 > 0 Then
            col差分操作列.Add Array(strDelete, Mid(str変更前, lngIdx変更前, 1))
            lngIdx変更前 = lngIdx変更前 - 1
        End If

    Loop

    Set nfnc文字を2つ比較して差分_fnc差分トレース = col差分操作列

End Function


'/**
' * 差分のコレクション(1文字ごとの操作)をまとめて、
' * 連続した削除・追加操作を1ブロックに圧縮し、カスタム可能な記号でフォーマットされた文字列として返す。
' *
' * 例: Collection = {"-", "b"}, {"+", "x"}, {"=", "c"}
' * → 出力(デフォルト記号使用時): "[b→x]"
' *
' * @param pcolDiffs       Collection 差分種別("+", "-", "=")と文字のペアを持つ配列のコレクション
' * @param strEqual        Optional String 同一文字の識別記号(既定値: "=")
' * @param strDelete       Optional String 削除操作の識別記号(既定値: "-")
' * @param strAdd          Optional String 追加操作の識別記号(既定値: "+")
' * @param strBlockStart   Optional String 差分ブロック開始の囲い記号(既定値: "[")
' * @param strArrow        Optional String 差分ブロック内の区切り記号(既定値: "→")
' * @param strBlockEnd     Optional String 差分ブロック終了の囲い記号(既定値: "]")
' *
' * @return String 整形された差分ブロック文字列(1ブロック1行、改行区切り)
' */
Private Function fnc文字を2つ比較して差分_fnc差分をブロック化( _
    ByVal pcolDiffs As Collection, _
    Optional ByVal strEqual As String = "=", _
    Optional ByVal strDelete As String = "-", _
    Optional ByVal strAdd As String = "+", _
    Optional ByVal strBlockStart As String = "[", _
    Optional ByVal strArrow As String = "→", _
    Optional ByVal strBlockEnd As String = "]") As String

    Dim strResult As String             ' 出力する差分結果(ブロック単位の文字列)
    Dim lngIndex As Long                ' Collection を逆順に走査するためのインデックス
    Dim strBuf追加 As String           ' 連続追加ブロックの一時バッファ
    Dim strBuf削除 As String           ' 連続削除ブロックの一時バッファ
    Dim varDiffItem As Variant          ' 差分1件(配列: 0=操作種別, 1=対象文字)

    ' 差分を逆順(末尾→先頭)で処理して、元の並び順を再構成する
    For lngIndex = pcolDiffs.Count To 1 Step -1
        varDiffItem = pcolDiffs(lngIndex)

        Select Case varDiffItem(0)

            Case strEqual
                If strBuf追加 <> "" Or strBuf削除 <> "" Then
                    strResult = strBlockStart & strBuf削除 & strArrow & strBuf追加 & strBlockEnd & vbCrLf & strResult
                    strBuf追加 = ""
                    strBuf削除 = ""
                End If

            Case strAdd
                strBuf追加 = strBuf追加 & varDiffItem(1)

            Case strDelete
                strBuf削除 = strBuf削除 & varDiffItem(1)

        End Select
    Next lngIndex

    ' 最後に残った差分ブロックがあれば出力
    If strBuf追加 <> "" Or strBuf削除 <> "" Then
        strResult = strBlockStart & strBuf削除 & strArrow & strBuf追加 & strBlockEnd & vbCrLf & strResult
    End If

    fnc文字を2つ比較して差分_fnc差分をブロック化 = Trim(strResult)

End Function

🖥️ 古いMacに新しい命を!クラウド時代のゼロコスト・バックアップ術 🔄

🤔 クラウドストレージ、本当に信用できる?

クラウドストレージって便利ですよね。でも、いつアカウントを誤爆されるか分からないし、某マイクロソフトの某ワンドライブの挙動は不審すぎて、ファイルが消えていても原因が分からないことも...😅

NASを買おうかな?」と思ったけど、コストがかかりすぎる...。

そこで閃いたのが、「あの古いMacを使えばいいんじゃない?」という発想です!💡 重要なデータがたまったときに、HDDに逃がしておくというシンプルな方法。あくまでもバックアップなので、万が一バックアップデータが死んでも「また各クラウドストレージから取ればいっか」という気軽さがポイントです。

さらに驚いたことに、iPhoneバックアップや、ローカルパソコンのバックアップまでできちゃいました!👏

🧰 古いMacでできること:眠れる可能性を解放!

1️⃣ Macは死なない、使い方次第で生きる

古くなったMac、押し入れに眠っていませんか? それ、実はNAS(ネットワークストレージ)やバックアップマシンとして再活用する最適な素材です!

市販のNASは便利ですが、常時稼働・初期コスト・メンテナンスといった壁があります。一方で「使いたいときだけ電源を入れて、必要なデータを手動でバックアップする」という割り切った使い方なら、古いMacで十分です。

この記事では、FreeFileSyncという無料ソフトを使って、古いMacを"オンデマンド型バックアップ機"にする方法を紹介します。iCloudWindowsのデータを簡単にまとめて保存できて、しかもコストはゼロ。シンプルだけど実用的。そんな構成をお届けします。

🛠️ 構成概要:Mac+FreeFileSync+外付けストレージ

この運用は、次の3要素で成立します:

🍎 古いMac

  • 10年以上前でもOK!
  • 外付けHDD/SSD(バックアップ先として使う)
  • 共有設定(Windowsからのバックアップ用)
  • iCloud連携済み(iCloud Driveのため)
  • FreeFileSync導入(iCloudのバックアップ!
  • iPhoneWi-Fiバックアップ設定(iPhoneのバックアップ!

🪟 Windows

  • 古いMacへネットワークドライブの割り当て
  • FreeFileSync導入で以下をバックアップ:
    • OneDriveのデータ
    • ローカルパソコンのデータ
    • その他クラウドストレージのデータ

🔄 バックアップ方法:FreeFileSyncで"更新"モードを活用する

FreeFileSyncにはいくつかの同期方法がありますが、今回使うのは「更新(Update)」モードです:

  • 🆕 元データが新しくなっていれば上書き
  • 🚫 元にないファイルは何もしない(削除されない)
  • 📚 バックアップ先にはどんどん最新版が積み重なる

つまり、「消えてもいい、でもできるだけ最新にしておきたい」という運用にぴったりです!

⚖️ メリットと限界

✅ メリット

  • 💰 無料で構築できる
  • ♻️ 既存のMacを再活用できる
  • 🔄 iCloudWindowsiPhoneのデータを一括管理
  • 🔌 常時稼働しないため、静音・省電力・寿命延長が可能

❌ 限界(割り切り)

  • 🗑️ 削除ファイルは検知されず、ゴミが溜まる
  • 🕰️ 過去バージョンの復元はできない(上書きのみ)
  • 💥 Macが物理的に壊れるとバックアップも止まる
  • 🤖 自動化は限定的。実行は手動前提

📝 まとめ:完璧じゃない。でもちょうどいい

この方法は、完璧なバックアップではありません。でも、「使いたいときに使える/コストをかけない/自分の手で管理できる」という意味では、非常に合理的で現実的な構成です。

壊れてもいい。消えてもいい。けど、一応残しておきたい—— そんな「ラフな信頼」が成り立つ場所には、この方法がぴったりハマります。

FreeFileSync+古Mac。あなたのデータ保管庫を、もう一度再起動してみませんか? 🚀


コメント欄でぜひあなたの古いMac活用法をシェアしてください!