エクセル内に定義された名前の重複を解決するマクロ
やりたいこと
以下ダイアログメッセージの連発を叩きのめす。
移動またはコピーしようとしている数式またはシートには、移動またはコピー先のワークシートに既にある名前 'foo' が含まれています。 この名前を使用しますか?
- コピーまたは移動先のシートに定義されている名前を使用する場合は、[はい]をクリックします。
- 数式またはワークシートで参照する範囲の名前を変更する場合は、[いいえ]をクリックし、[名前の重複] ダイアログボックスに新しい名前を入力します。
先にデメリット
すべて消えます。
この方法は定義された名前をすべて削除します。
そのため、セルに名前を付けているとすべて消えます。
対象としてはまっさらにする時の用途なのでご注意ください。
たまに復活します。
古い形式(.xls)など、削除したはずが謎のタイミングで復活する場合もあります。
そうなると諦めて新しいファイルに書式などを丁寧にコピーするしかないです多分。
やること
開発」タブを表示するようにする。
(ファイル→オプション→リボンのユーザー設定)
「開発」タブの「マクロの記録」をクリック、OKをで初期表示の名前で記録開始。
「開発」タブの「記録終了」をクリック
「開発」タブの「マクロ」をクリック
マクロの記録で付けた名前を選択して、「編集(E)」をクリック
以下のような状態になっていると思います。
Option Explicit Sub Macro1() ' ' Macro1 Macro ' ' End Sub
全部消して以下をコピペする
Option Explicit Sub Macro1() ' ' Macro1 Macro ' Dim n As Name Dim s As Worksheet ' ブックの範囲の名前を削除 For Each n In ThisWorkbook.Names n.Delete Next ' シートの範囲の名前を削除 For Each s In ThisWorkbook.Worksheets For Each n In s.Names n.Delete Next Next msgbox "あいつはもう消した!" ' End Sub
F5キーを押す
メッセージが出たら終わり。
以上!
2016年 C# 開発に使用しているNuGetまとめ
概要
早いもので今年ももうすぐ終わりということで(テンプレフレーズ)
C#でデスクトップアプリケーションを開発するのも慣れてきました(企業文化的な意味で)
ということで今年である程度まとまってきたC#でのデスクトップアプリケーション開発環境をメモ。
主にプロジェクトとNuGetで使用するライブラリです。
前提となる動作環境
- Windows7以降
- .Net 4.0以降
- デスクトップアプリからSQL Serverとのやりとり。
プロジェクト
- Livet (MVVM)
WPFで開発する時はまずLivetプロジェクトを使っています。
https://marketplace.visualstudio.com/items?itemName=vs-publisher-129899.Livet-WPF445MVVM
NuGet
Dapper
対DBのオブジェクトマッパー。プロパティ名に日本語使ってもOKなので便利。
CsvHelper
対CSVのオブジェクトマッパー。業務データがCSVの時にこれで読み込むととても楽。
MahApps.Metro
WPFのGUIをメトロスタイルにするやつ。自己満足でたまに導入します。
Json.NET
Jsonを読み込むライブラリ。
最近使い始めたけどちょっとした設定を外部ファイルにする時いいですね、json。
NLog
ロギングライブラリ。
出力先を社内共有サーバーにしてログを管理してます。
QuickConverter
ちょっとbool反転したい時とかに式を書いてバインディングできます。ここ一ヶ月の中で感動したライブラリ。
いちいち実装しなくても、痒いところに手が届く!
EPPuls
Excel 2010以降のファイルを高速に読み書き。
NetOffice
古いExcelを読むならこれ。
だいたいこれらを使っていればちょっとした社内ツールの開発に十分かなという感じです。
以上!
VBScriptでOutlookのメールファイル(msg)から貼付ファイルを取り出す。
概要
複数のメールにある貼付ファイルを一気に取得したい!
ただし、OutlookのVBAは勘弁な!ということで作りました。
このソースを ExtractAttachments.vbs
みたいに保存して、
msgファイルをドラッグアンドドロップするとmsgファイルのディレクトリにモリモリ添付ファイルを取り出してくれます。
なお、元ファイルの名前の末尾に貼付ファイル名を追加するため、名前が重複することはありません。
ソースコード
Dim args, arg ' 許可されている拡張子 Set AllowedExtensions = CreateObject("Scripting.Dictionary") AllowedExtensions.Add "msg" , 0 Set args = WScript.Arguments ' 引数のチェック。対象ファイル以外が混ざっている場合終了。 set fobj = CreateObject("Scripting.FileSystemObject") For Each arg In args ext = fobj.GetextensionName(arg) if not AllowedExtensions.Exists(ext) then msgbox "msgファイル以外が指定されました。終了します。" WScript.Quit end if Next Set appOL = CreateObject("Outlook.Application") For Each path In args Set msg = appOL.CreateItemFromTemplate(path) for each atc in msg.Attachments atc.SaveAsFile path & "." & atc.DisplayName next Next msgbox "抽出完了しました。"
感想
やはりOffice系をいじるのはVBScriptが一番かなあと思う事が多いです。
以上!
C# - Chromeでダウンロードしているファイルの状況を確認するクラス
Seleniumからファイルのダウンロードリンクをクリックさせてダウンロードしたファイルをどうにかするプログラムの副産物
概要
Chromeはダウンロード中のファイルを以下の名前でダウンロードしていきます。
<元のファイル名>.crdownload
よって、そのcrdownloadファイルをうまいこと監視すればチェックしたいファイルのダウンロード完了を検出できるのです!
とか思ってたんですけど FileSystemWatcher って言う便利なクラスがあったんですね・・・。
もったいないので一応メモ。
ソースコード
/// <summary> /// Chromeのダウンロードの状況クラス /// </summary> public class ChromeDownloadStatus { /// <summary>ダウンロードフォルダ</summary> public static readonly DirectoryInfo DownloadDirectory; /// <summary>ダウンロードフォルダの名前</summary> private static readonly string DownloadDirectoryName = "Downloads"; /// <summary>キャッシュファイルの拡張子</summary> private static readonly string DownloadCacheExtension = ".crdownload"; /// <summary> /// ダウンロード状態。 /// </summary> public enum DownloadStatus { /// <summary>何もしていない</summary> None, /// <summary>ダウンロード中</summary> Downloading, /// <summary>ダウンロード完了</summary> Downloaded } /// <summary> /// 初期化。 /// </summary> static ChromeDownloadStatus() { DownloadDirectory = new DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), DownloadDirectoryName)); } /// <summary> /// 対象のファイルのダウンロード状況を取得する。 /// </summary> /// <param name="fileName">対象のファイル名</param> /// <returns></returns> public DownloadStatus GetDownloadStatus(string fileName) { var cacheFile = new FileInfo(Path.Combine(DownloadDirectory.FullName, fileName + DownloadCacheExtension)); var file = new FileInfo(Path.Combine(DownloadDirectory.FullName, fileName)); // キャッシュがある場合はダウンロード中 if (cacheFile.Exists) { return DownloadStatus.Downloading; } // キャッシュがなくて、ファイルが存在する場合は完了 if (!cacheFile.Exists && file.Exists) { return DownloadStatus.Downloaded; } return DownloadStatus.None; } /// <summary> /// ダウンロード完了まで待つ。 /// タイムアウトの場合はNULLを返す。 /// </summary> /// <param name="fileName">ファイル名(ダウンロードフォルダに存在するもの。</param> /// <param name="loopWaitSpan">チェックごとのWait</param> /// <param name="timeout">タイムアウト時間。</param> /// <returns>ダウンロード完了したファイル情報</returns> public FileInfo WaitUntilDownloaded(string fileName, TimeSpan loopWaitSpan, TimeSpan timeout) { var start = DateTime.Now; // 指定のファイル名のダウンロード状況を取得する Func<DownloadStatus> getStatus = () => GetDownloadStatus(fileName); // タイムアウトかどうか取得する。 Func<bool> isTimeout = () => timeout < (DateTime.Now - start); var dlStatus = getStatus(); // 既にDL終了であればそのままファイルを返す if (dlStatus == DownloadStatus.Downloaded) { return DownloadDirectory.GetFiles(fileName).First(); } // ダウンロード開始直前の場合開始していない扱いになるため開始になるまで待つ if (dlStatus == DownloadStatus.None) { while (getStatus() == DownloadStatus.None) { Thread.Sleep(loopWaitSpan); if (isTimeout()) { return null; } } } // ダウンロード完了状態になるまで待つ while (getStatus() != DownloadStatus.Downloaded) { Thread.Sleep(loopWaitSpan); if (isTimeout()) { return null; } } // ここまで来たらDL完了のため、ファイルを取得する return DownloadDirectory.GetFiles(fileName).FirstOrDefault(); } }
Powershellで複数のCSVファイルを特定の列で1つのファイルにマージ
概要
以下2つのCSVを共通の列名"HeaderA"でまとめたCSVにしたい!
A.csv
HeaderA,HeaderB ValueA,ValueB
B.csv
HeaderA,HeaderC ValueA,ValueC
以下Powershellスクリプトで実現。
get-childItem "*.csv" | foreach { Import-Csv -Path $_ | Select HeaderA | Export-Csv -Append -NoTypeInformation -Path AB.csv }
備考/感想
- Selectに存在しないヘッダーを選んでも大丈夫(無いものは空文字になる)
- 結果ファイルの全部のデータがダブルクォーテーションで囲まれて出力される。注意。
- もちろんヘッダー指定は複数でもOK("Select HeaderA, HeaderB"という感じ)
社内ホームページにRiot.jsを導入してみた質の極めて低いメモ
前提
環境
- 社内のホームページはホームページビルダーなどで作った静的なページ。
- ホームページサーバーはWinServerでIISの標準的な機能でホストしている。
実装者
- web系開発経験なし。全然ノウハウなし。
- ウェブサービスのフロントエンドとバックエンドがどうデータをやり取りしているのかも分からないレベル。
契機
社内のホームページにある社内連絡のtable要素を非エンジニアがhtmlを直接編集しており、記述に難儀していた。 直接編集する作業をやめたい、という要望があった。
導入
全体像
- 社内連絡の内容を記載し、マクロによってjson出力するExcelマクロ有効ブックを作る…①
- 非エンジニアに①を使用させ、出力を行う…②
- ホームページで②を読み込ませ、それを元にRiot.jsで特定のタグをマウントする。
簡単ですね。実際はVBAが実装面倒すぎて辛かったんですけど。
実装
jsonファイル
トップの"renraku"から、"date","text","url"の3つのデータを配列で持たせています。
{ "renraku":[ { "date":"2016/11/30", "text":"おしらせ~", "url":"http://google.com" }, { "date":"2016/11/29", "text":"ファイルへのリンクお知らせ", "url":"files/お知らせ.xlsx" } ] }
社内連絡のページHTML
カスタムタグではなくID指定で試してみた。
<!doctype html> <html lang="ja"> <head> <title>社内連絡</title> </head> <body> <div id="riot-renraku-table"></div> <script type="text/javascript" src="js/jquery-1.8.3.min.js"></script> <script type="riot/tag" src="tag/renraku-table.tag"></script> <script type="text/javascript" src="js/riot_compiler.min.js"></script> <script type="text/javascript"> $.ajax({ url: 'json/renraku.json', dataType: 'json', async: true, cache: false, success: function(res) { riot.mount('#riot-renraku-table', 'renraku-table', res.renraku); } }); </script> </body> </html>
カスタムタグ
if文を使って、URLがあればa要素、なければdivという表示をしています。
<renraku-table> <table> <thead> <tr> <th>日付</th> <th>お知らせ</th> </tr> </thead> <tbody> <tr each={opts}> <td>{date}</td> <td> <a if={url!==""} href="{url}" target="_blank">{text}</a> <div if={url===""}>{text}</div> </td> </tr> </tbody> </table> </renraku-table>
感想
なんか書くのが面倒になってしまったので感想でまとめて終わらそうと思うんですけど、
「なんかよくわからないが動いた」の一言につきます。
とりあえず初心者の手習いだと思っていただければ。
VBScriptで古い形式のExcelを新しい形式に変換する。
いちいち開いて名前を付けて保存するの面倒だよね、という事からつくりました。
変換したいファイル達をドラッグ&ドロップするだけで同ディレクトリに保存されます。
コード
' 定数 Const XlFileFormat_xlOpenXMLWorkbook = 51 ' .xlsx : Excel ブック ' ドラッグドロップで渡されたファイルを文字列で取り込む。メッセージ用。 set args = WScript.Arguments fileList = "" for each arg in args fileList = fileList & vbNewLine & arg next ' 引数のチェック。対象ファイル以外が混ざっている場合終了。 set fobj = CreateObject("Scripting.FileSystemObject") for each arg in args ext = fobj.GetextensionName(arg) if ext <> "xls" then msgbox "xlsファイル以外が指定されました。終了します。" & vbNewLine & fileList WScript.Quit end if next ' 引数で貰った各Excelファイルを最新の形式で保存する。 set oXlsApp = CreateObject("Excel.Application") for each path in args oXlsApp.Application.Visible = true set book = oXlsApp.Application.Workbooks.Open(path) book.SaveAs Replace(path, ".xls", ".xlsx"), XlFileFormat_xlOpenXMLWorkbook book.Close next oXlsApp.Quit set oXlsApp = nothing msgbox "変換完了しました。"