投稿

9月, 2020の投稿を表示しています

テキストの差分

  目的および概要 似たような2つのテキストの違いを調べたい場面が、たまにあります。 テキストを出力するプログラムの修正で意図した結果になっているか確認する場合や、プログラムの変更箇所を調べる場合などです。 いろいろな比較ツールがあり、これを使えば、違いをわかりやすく見る事ができます。 ここでは、敢えてVBAで比較する方法を検討します。 一致する箇所を探す 目的は2つのテキストの違う箇所の探す事ですが、その為には一致する箇所を探します。元のデータから一致箇所を取り除けば、残ったデータが不一致箇所となります。 2つのファイルは殆ど一緒の前提(その為、プログラムで不一致箇所を調べたいので)です。テキストの先頭から読み込み、行単位で比較して一致する箇所を取り除きます。 不一致の場合は、次に一致する行をなるべく近い位置で探します。いろいろな方法が考えられますが、スキップする行数の合計を1から順に増やしながら探し、最初に見つかった行同士を次の一致箇所とする方法が簡単です。 見つかった一致箇所までは不一致箇所として残します。一致箇所から処理を繰り返し一致する箇所を取り除きます。 これで、不一致箇所が残ります。 行単位の比較 行単位での比較は、strcompを使うのが簡単です。 不一致箇所を見つけたときに次の一致箇所を探すのですが、このとき、同じ行を何度も読み込む事になります。もし、strcomp が遅いと思われるなら、文字数を配列に保存しておき最初に評価する事で不要なstrcompを回避できます。 また、曖昧な評価をしたい場合は、予めテキストを変換するか、strcompとは別に比較のロジックを準備します。 前者の例では、スペース文字とタブ文字を同一にする場合は、予めタブ文字をスペース文字に置換します。また、スペース文字の数を無視する場合は、複数のスペース文字を1文字のスペース文字に予め置換します。 文字単位の比較 行の中のどの文字が違うかを知りたい場合は、行単位ではなく、文字単位で処理します。 文字単位の場合でも、基本的な考え方は一緒で、一致箇所を取り除いた残りを不一致とします。但し、行という纏った単位がないため、一致箇所を探す場合はデータの近さより、一致箇所の長さに注目した方が良い結果となると思います。 具体的には、まず、データ全体を、不明箇所として考えます。 不明箇...

VBAでハッシュの計算

 概要 advapi32.dllを呼び出すことで、ハッシュ値を取得できるとの情報を見かけたため、試してみました。 備忘録として、コードを貼り付けておきます。 Option Compare Database Option Explicit #If VBA7 Then Private Declare PtrSafe Function CryptAcquireContext Lib "advapi32.dll" Alias "CryptAcquireContextA" _                             (ByRef phProv As LongPtr, ByVal pszContainer As String, ByVal pszProvider As String, _                              ByVal dwProvType As Long, ByVal dwFlags As Long) As Long Private Declare PtrSafe Function CryptReleaseContext Lib "advapi32.dll" _                             (ByVal hProv As LongPtr, ByVal dwFlags As Long) As Long Private Declare PtrSafe Function CryptCreateHash Lib "advapi32.dll" _                             (ByVal hProv As L...

PDFファイルのテキストを抽出する

ここでは、PDFファイルに含まれるテキスト情報をVBAから利用することを考えます。 PDFファイルを、ページの内容により分類し自動処理する場合、まずページ毎の内容を把握することが必要です。 多くのPDFファイルでは、テキスト情報を含んでいるため、これを読み取る方法を検討します。 PDFSharpを使った方法(失敗) 検索で見つけたページを参考に、PowerShellからPDFSharpを使ってテキストが抽出できるか試したところ、文字化けしたようなデータしか得られませんでした。 $root="C:\PDFTEST" [void][Reflection.Assembly]::LoadFile( $root + "\PdfSharp.dll"); $pdf = $root + '\TEST.pdf'; $rd = [PdfSharp.Pdf.IO.PdfReader]::Open($pdf, [PdfSharp.Pdf.IO.PdfDocumentOpenMode]::Import); $pgnum = $rd.PageCount; $txtname = [String]$root + "\out.txt" $fs = new-object System.IO.FileStream($txtname, [System.IO.FileMode]::Create) $sw = new-object System.IO.StreamWriter $fs function ReadContent( $cobj) {     $rettext = ""     $objcount =$cobj.Count     for($j=0; $j -lt $objcount; $j++){         $TypeName =$cobj[$j].GetType()         $obj = $cobj[$j]         if ($TypeName.Name -eq "COperator...

PDF印刷の印刷順序を検討する(4)

"PDFに出力・印刷される各種リストのページを使いやすく並べ替える”ことを引き続き検討しています。 PDFからページの抽出 1つのPDFから所定のページを抜き出し、1つのPDFに連結します。 これにより、ページの順序を変えたPDF2を作成します。 Public Function MergePdfPg3 _ (ByVal pi_sTMPPdfFile As String, _ ByVal pi_nADDPdfFileCnt As Long, _ ByRef pi_sADDPdfFile() As String, ByRef pi_nPgFrom() As Long, ByRef pi_nPgTo() As Long) As Long 'PDFSharpを使ってPDFファイルを連結(ページ指定あり) Dim com As String Dim i As Long Dim j As Long com = PSPath & "powershell -Command " com = com & "[System.Reflection.Assembly]::LoadFrom('" & CurrentBookPath & "PDFSharp.dll');" com = com & "$pdf = '" & pi_sTMPPdfFile & "';" com = com & "$doc = New-Object PdfSharp.Pdf.PdfDocument;" com = com & "function AddPDFFile( $fnm, $pgf, $pgt )" com = com & "{" com = com & "$rd = [PdfSharp.Pdf.IO.PdfReader]::Open($fnm, [PdfSha...

PDF印刷の印刷順序を検討する(3)

"PDFに出力・印刷される各種リストのページを使いやすく並べ替える”ことを引き続き検討しています。 PDFの連結 複数のPDFを1つのPDFに連結することで、ページの順序が乱れてしまうのを防ぐことができます。 連結にiTextSharpを使う例が多く見受けられますがライセンス面で避けるといった情報もあり、ここではPdfSharpの利用を検討します。 VBAからPowerShellを介して呼び出すことを検討します。 Public Function MergePdf3 _ (ByVal pi_sTMPPdfFile As String, ByVal pi_nADDPdfFileCnt As Long, ByRef pi_sADDPdfFile() As String) As Long 'PDFSharpを使ってPDFファイルを連結 Dim com As String Dim i As Long Dim j As Long com = PSPath & "powershell -Command " com = com & "[System.Reflection.Assembly]::LoadFrom('" & CurrentBookPath & "PDFSharp.dll');" com = com & "$pdf = '" & pi_sTMPPdfFile & "';" com = com & "$doc = New-Object PdfSharp.Pdf.PdfDocument;" com = com & "function AddPDFFile( $fnm )" com = com & "{" com = com & "$rd = [PdfSharp.Pdf.IO.PdfReader]::Open($fnm, [PdfSharp.Pdf.IO....

PDF印刷の印刷順序を検討する(2)

"PDFに出力・印刷される各種リストのページを使いやすく並べ替える”ことを引き続き検討しています。 対応方法の検討 次のような操作方法を検討します。   ・プリンタ(スプール)を停止、システム日時を保管します。   ・ 社内システムを操作して、リストを印刷します     →スプールを停止しているため、プリンタからは印刷されません。    ・プリンタ(スプール)に溜まったデータを削除して再開します。    システム日時を元に、停止中のPDFファイルを検知します。     ページを並べ替えたPDFを作成し、画面表示して終了します。 使用するPCの環境より、エクセルマクロ(VBA)を使うことにします。  プリンタの停止、キューの削除、再開  使用するプリンタは、「通常つかうプリンタ」です。 WMIを使用してのプリンタの停止、キューの削除・再開は、次のようになるかと思います。 Public Sub PauseDefaultPrinter()     Dim oPrinters As Object     Dim oPrinter As Object          Set oPrinters = GetObject("winmgmts:\\.\root\cimv2").ExecQuery("SELECT * FROM Win32_Printer where default=TRUE")     For Each oPrinter In oPrinters         oPrinter.Pause     Next End Sub Public Sub ResumeDefaultPrinter()     Dim oPrinters As Object     Dim oPrinter As Object          Set oPrinters = GetObject("winmgmts:\\.\root\cimv2").ExecQuery("SELECT * FROM Win3...

PDF印刷の印刷順番を検討する

社内システムから印刷される「〇〇送付リスト」や「〇〇ピッキングリスト」を確認しながら、作業をすることがあります。 普段は、1日分の作業のリスト、つまり複数のリストが一括で出力されています。リストは、内容や作業場所でページが分かれており、枚数は数十枚になります。 作業場所毎に参照するため、リストもその順番であれば良いのですが、実際には規則性なく出力されます。(何かしらの規則があるかも知れませんが、利用者からすると何の意味もありません。) 枚数が多いほど、並べ替えは面倒なもの。間違いの元にもなるため、コンピュータでの並べ替えを検討しました。 現状確認 社内システムから、何かしらのリストを出力してみます。 すると、ダイアログが表示され、印刷かプレビューを選択できるようになっており、AcrobatReaderが立ち上がり、PDFが開きます。 1つのPDFに複数ページが含まれるケースと、1・2ページ程度PDFが複数作成されるケースがありました。 1つのPDFに複数ページが含まれる場合の対策 PDF内のページを並び替えて、印刷し直すことを検討します。 ページのコードNO順に並べ替えたいので、各ページのコードNOを調べます。 使用している社内システムのPDFにはテキスト情報が含まれており、pythonのスクリプトpdf2txt.pyの出力をchr(9)で分割して、ページ毎のテキストにできそうでした。 複数のPDFの場合の対策 PDFのファイル名を見ると規則性が見て取れ、   印刷モジュール名.ユーザー.印刷日時.pdf と推測しました。 プレビュー中のファイルから、ファイルの保管場所を調べ、印刷したPDFが多く残っていることが確認できました。 印刷日時の順にファイルの中身を確認すると、出力順としては問題が無いことがわかりました。印刷のシステム、プリンタドライバ、スプーラで順番が入れ替わっているようです。尚、スプーラの設定を見直しても改善しませんでした。 複数のPDFを1つに連結し、印刷し直すことを検討します。 次に続きます。

[VBScript]WiFiアダプタの無効化と有効化をスクリプトで実行する

OSをWindows10に入れ替えてから、起動直後やスリープからの復帰時に「識別中・・・インターネットアクセスなし」と表示され、インターネットに接続できない現象に遭遇しています。 結構な頻度で発生し、Wifiのネットワークアダプタを一度無効にしてから有効にすると治ります。 面倒な操作ですが、その後は安定するため、Wifiアダプタの買い替えまでには踏み切れません。 別件の調べ物をしていたら、WMIで無効・有効を操作できそうだったので、VBScriptで試してみました。 本題 VBScriptからWifiのネットワークアダプタを再接続(無効化→有効化)する。 <使い方> ・適当なファイル名(~.vbs)に保存し、ダブルクリックで実行。 ・ネットワークアダプタの名称に合わせて、検索条件( %Wireless%の箇所)は適宜変更すること。 ・バッチファイルを作成し、起動後にスケジュール実行するようにしても良いかもしれません。無効・有効の設定には、管理者権限が必要なようです。 ポイント ・VBScriptからWMIを利用。Wifiアダプタの検索と設定が、比較的簡単。 ・アダプタの無効と有効の間に、何となくウェイトを入れています。根拠はありません。 Option Explicit Dim obj Set obj = Wscript.CreateObject("Shell.Application") if Wscript.Arguments.Count = 0 then ' 管理者権限でスクリプトを再実行する obj.ShellExecute "wscript.exe", WScript.ScriptFullName & " runas", "", "runas", 1 Wscript.Quit end if 'WMIにて使用する各種オブジェクトを定義・生成する。 Dim oClassSet Dim oClass Dim oLocator Dim oService 'ローカルコンピュータに接続する。 Set oLocator = WScript.CreateObject("WbemScripting.S...