カテゴリー: Development

Processing覚書 引数付き起動

Processing2.2.1で確認。

Processingで作成したexeを引数渡しで起動させる場合、というので調べてみたが、一番よさげなのは下記のURLの説明とサンプルだと思った。

uncertain world「Processingをコマンドラインから引数つきで実行する方法」

特に良いと感じたのは引数を「xxx=yyyy」という記載で渡すところ。

というのは、Processingで開発中のときにRUNするときと、Exportしてexe起動させるときでは、引数の数が違っている。
前者だと引数の最初に、「–sketch-path=XXXXX」が入っていて、後者だと入らない。
なので、引数の何番目を見て、ウンチャラカンチャラ・・・みたいなことはできない訳。

void setup() {
  for (String a : args) {
   String[] a2 = a.split("=");
   if (a2[0].trim().equals("para1")) {
    ・・・処理・・・  
   } else if (a2[0].trim().equals("para2")) {
    ・・・処理・・・  
   }
  }
}

と、こういう感じで、setupメソッド内に、引数取得処理を入れておく。

起動させるときは、

Prog.exe para1=1 para2=ABC

ってな感じでパラメータを渡してやればよい。

ExcelVBA覚書 Dictionaryループ

基本的にScripting.Dictionaryは、

Dim dic     As Object

Set dic = CreateObject("Scripting.Dictionary")
If Not dic.Exists(a) Then
  dic.Add a,b
End If

みたいに、Existsメソッドを利用することが多いのだが、
やはり1つずつ確認して処理を行うこともなくはない。

Dim i As Long
For i = 0 To dic.Count - 1 Step 1
    debug.print dic.Keys()(i) & "-" & dic.Item(i)
Next i

もしくは、

Dim v As Variant
For Each v In dic.Keys()
    debug.print CStr(v) & "-" & dic(v)
Next

で、いずれも、Keys()両括弧を付けるところがポイント。

色々サイトを見てみたのだが、この()が抜けていたり、ItemがItemsになっていたりして、混乱している記載が多く、ここまでたどり着くのに英語のサイトまで見に行ってしまった。

非常にやっかいだが、もともとこういう使い方するようなオブジェクトではないのだろうから、仕方ない。

ちなみに削除するときはRemoveを使う。(Deleteではない)

Dim v As Variant
For Each v In dic.Keys()
    dic.Remove v
Next

MySQL覚書 配列、縦→横、カンマ区切り

同じIDのTITLEデータをカンマ区切りでとってきたい!
とか思って漁っていたら、

MySQLでidだけをSELECTして、カンマ区切りにして出力する

という、ページが見つかった。
GROUP_CONCATという関数を使い、区切り文字をカンマに指定する方法である。

SELECT GROUP_CONCAT(title SEPARATOR ',') FROM t_sample WHERE id = 1;

PostgreSQLだと、ARRAY_TO_STRING

<参照>PostgreSQL覚書 配列

AccessVBA覚書 Excelファイルを取込む

ファイル渡すからプログラム組んでくれ、っていわれてプログラム作成している最中、
ファイルも寄越さないうちから、「進捗どうですか?」って聞かれて、ちょいムカっとしたのは今週の始め。
んで、ムカついたからもう少し待ってねメールのついでに、送ってきた中途半端な仕様書の「重箱の隅にもならない場所」(ちゃんと書いて!ってな場所)をつつくような質問を畳みかけてやった。(フン!)

まぁ、別に大して怒っている訳ではないのだが、
 「自分がやるべきこともしないで、なんなんだ?」とか、
 「いやいや○日かかるって言ってるでしょ!何日目だよ今日!」とか・・・
色々思うところはあった。
そうは言いつつ、自分もこうならないように気を付けようと、ちょいと思ったのだった。

で、慣れないDoCmdに苦戦しつつ、ExcelファイルをReadOnlyで開いて、データを読込み、終わったら閉じる処理を書いてみた。
DisplayAlertsをFalseにしているのは、Excelで発生したエラーやら確認メッセージを出させないためだけで、値をとってくるだけなら特に必要はないと思う。

Dim xls As Object
Dim wb  As Object

Set xls = CreateObject("Excel.Application")
xls.DisplayAlerts = False
Set wb = xls.Workbooks.Open(FileName:=[Excelパス], ReadOnly:=True)

 ・・・(読込処理)・・・

wb.Close SaveChanges:=False
Set wb = Nothing 
xls.DisplayAlerts = True
xls.Quit
Set xls = Nothing

面倒だなぁ・・・Excelでいいじゃん?
だって、xlUpとかxlToLeftとかのExcelVBA特有の定数も使えないし。
(参照設定で設定すれば、使えるようにはなるけどサ)

とは思ったのだが、まぁ、後々Accessの方がいいこともあるかもって思ったので、お客さんの言うとおりAccessにした。
だけど、やはり、今回は、Accessにデータを取込むわけでもなく、別DBに出力するロジックだったので、尚更、AccessでExcelを開くというのは、かなり馬鹿馬鹿しく感じた。
もちろん、できるならImportしたいところだが、できるほど単純なデータではなかったので、わざわざロジックを組む。

  ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・

で、今回は読み込んだデータをAccessテーブルには放り込まなかったのだが、Accessに取込むとなるとどうするのか・・・ということも考えてみた。

しっかし、AccessのTableってのは、INSERT文で出力しようが、AddNew・Updateで入れてみようが、まぁ、遅いのなんの・・・
さらに複数のSQL文を一括実行する方法なんて探してみたのだが、

Accessにはない!

ということなので、1つ思いついたのが、
 ・Excelデータを取込んで、テーブルImport用のCSVを作成。
 ・CSVをImportする。
という方法。
確かに、INSERTを発行するより速いのだが、かといって、すこぶる速いという訳でもなかった。件数が多ければ、明らかに速くなる気はする。

しかし、ここで問題発生。文字コードだ。

UTF-8文字が入力されたExcelデータであったため、ADO.Streamを利用して、BOM無しのUTF8でCSV出力。
かつ、インポートするときも

 DoCmd.TransferText acImportDelim, , temp_table , csv_path, True, , 65001   

というように、文字コード(65001がUTF-8を示す)を指定して取込む必要があった。

ということで、いろいろ試しにやったのだが、プログラム自体はすんなり作成できた。

ってか、まだファイル来ないし・・・

ExcelVBA覚書 VBAPのパスワード忘れた?

略すとPPAPみたいになってるけど、ExcelのVBAプロジェクトのパスワードがわからないとき(忘れたとき)は、それを外すやり方がある。

何だっけ・・・

と思って調べた。

ここでは詳細は書かないけど、検索ワード的には
 Excel, VBA, DPB=
といったところか。

DPB=のダブルクォーテーションで括られた中身が暗号化?されたPWで、それをうまいこと置換えるわけなんだけど、バイト数が合わないとVBA関連のファイルが潰れちゃうので注意しなくてはならない。
なので、バイト数のきっちり合った置換文字を作成するため、新規ExcelファイルにVBAパスを付けて保存した後バイナリファイルの中身を確認する。
(パスワードの桁数からDPBの中身の桁数が容易にわかるわけではないので、色々作って合致した!ってなパスワードが見つかってから置換えるわけ。ちょいと面倒なのだが、熱さ過ぎればチョメチョメチョメと。)

あらら、結構書いてしまったぞい。
忘れたときのためなので、悪用するべからず!

Java覚書 サーバ名からMACアドレスを取得

Windows上で動いている場合にしか利用できない方法だけど、メモ。

JavaでサーバのMACアドレスを簡単に取得する方法を漁ってみたのだが、結局は「ARPコマンドを実行する」ぐらいしかないようである。
なので、ちょっとガックシきてしまった。

1) target に サーバ名を設定。
2) Windowsコマンド arp に、targetサーバのIPアドレスを設定して実行。
3) コマンドプロンプトの出力からtargetサーバのIPアドレスのMACアドレスを取得

    String target = "ここにサーバ名を設定";
    String adr= "";
    try {
      // 1)
      InetAddress ip = InetAddress.getByName(target);
      // 2)
      ProcessBuilder pb = new ProcessBuilder("arp", "-a", ip.getHostAddress());
      pb.redirectErrorStream(true);
      Process proc = pb.start();
      proc.waitFor();
      // 3)
      InputStream is = proc.getInputStream();
      BufferedReader br = new BufferedReader(new InputStreamReader(is));
      try {
        for (;;) {
          String line= br.readLine();
          if (line == null) break;
          if (line.indexOf(ip.getHostAddress()) >= 0) {
            adr = buf.substring(23,45).trim();
          }
        }
      } finally {
        br.close();
      }
      if (res.length() > 0) {
        System.out.println("Server ["+ target+ "] , IP [" + ip.getHostAddress() + "] , MAC [" + adr + "]");
      }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
    }

参考URL
きしだのはてな「JavaでMACアドレスを取得する」
ひしだま’s 技術メモページ「Java > 外部プロセス起動」

SQLite覚書 副クエリを使ったUPDATE

世の中には、ありがた迷惑とか、小さな親切大きなお世話とか、そういうことがわからない人が一杯いるようだ。
そういう人は、「やるな!」「やらないでくれ!」っていっても、「やる」のだなぁ。
人のやること横取りするんじゃないよ!と、叫びたかった、今日の朝。

それはそうと、SQLiteでSELECT文を使ってUPDATEしたい!というのがあって、
そうすると、まぁ、

 UPDATE table1 SET
  col1 = (SELECT col1 FROM table2 WHERE .... )

みたいにすればできるぜ!みたいなことはいっぱい書いてあるんだけど・・・

 そうじゃないんです!
 JOINで連結させて、ホゲホゲホゲ・・・とやりたいんです!

という要求は満たされないわけ。

で、調べた。

SQLiteはWITH句が使えるらしい。
んで、WITH句をうまく活用して、UPDATEできるらしい。

他のDBのSQL文を

UPDATE table1 SET
    col1 = a.col1
  , col2 = a.col2
 FROM (SELECT .... FROM .... INNER JOIN ....) a
 WHERE table1.id = a.id

とすると、
WITH句を使ったSQL文は

WITH a AS (
  SELECT .... FROM .... INNER JOIN ....
)
UPDATE table1 SET
    col1 = (SELECT col1 FROM a WHERE table1.id = a.id)
  , col2 = (SELECT col2 FROM a WHERE table1.id = a.id)

みたいな感じ。

で、これを私が愛用する「A5:SQL Mk-2」(SQL開発ツール)で実行したのだが、うまくいかずに、「あれ?できないの?」とか思って悩んだのだが、ツール上ではうまくいかないだけで、SQLiteのコマンド実行では、ちゃんと動いた。

ホント、統一させてほしいんですけど。

Processing覚書 SQLite接続

Processing開発。
BezierSQLibライブラリを使ってSQLiteのDBにつないでいるのだが、1つ問題が。

というのも、エラーになったときExceptionが発生しない。
ライブラリ内部で例外処理までしてるのは兎も角、結果がエラーになってもエラーを判別できるフラグがない。
DBにLockがかかってる時にUPDATEしても、コンソールにエラーメッセージは出るが、それだけ・・・
Rollbackするタイミングがつかめない。
このままではマズイ。困った。

こうなったら、直接jdbcライブラリを利用しよう!となった。

プログラムソースのpdeファイルが入っているフォルダの下に「data」フォルダを作って、その中にDBファイルの「test.db」を入れる。
「data」フォルダと同じ並びに「code」フォルダを作って、その中にライブラリ「sqlite-jdbc-***.jar」ファイルを入れておく。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

// ------------------- ( 略 ) -------------------

void getData() {
  Connection con = null;
  Statement stmt = null;
  try {
    Class.forName("org.sqlite.JDBC");
    con = DriverManager.getConnection("jdbc:sqlite:"+ dataPath("test.db"));
    println("Opened database successfully");
    
    stmt = con.createStatement();
    stmt.executeUpdate("INSERT INTO m_users (user_cd ,user_name) VALUES ('1010101', 'Lily');");
    stmt.close();
    con.close();
  } catch ( Exception e ) {
    println( e.getClass().getName() + ":" + e.getMessage());
  }
}

Macでいけたから、あとはWindowsでも確認しよう。

SQLite覚書 速度の向上

データが1万→2万になったところで、急激にUPDATEの速度が遅くなってしまった。
SQLiteって速いって聞くんだけど・・・
ということで、チューニングについて調べてみた。
INSERTが遅いってのがあったけど、Transactionは入れてるし。
UPDATEが遅いっていわれても、そこを変えるのは・・・と思ったので、以下のサイトを参考に、コマンドプロンプト上でDBの設定をかえた。
パフォーマンスを追求するためのSQLite設定 | ITハンドブック
SQLite「PRAGMA statement」

sqlite> PRAGMA main.journal_mode = PERSIST;
sqlite> PRAGMA main.synchronous=0;

mainはスキーマ名。
で、どうなったかというと、設定を変更後、一回VACUUMをしてから確認したら、劇的に速度向上?

<追記>
あぁ・・・勘違いしてた。
どうやら、DBを開いているときだけ設定した状態が保持される様子。

SQLite が認識できる SQL

閉じちゃったら元のDefault設定に戻るようだ。
たしかに、開き直したら設定が消えちゃってたよ。

開いた直後だな。設定するのは。

<追記2 2016/09/14>
さて、さて、いろいろ試した結果。

結果的に設定を変えて高速化したか?といえば、さほどな気はした。
やはり、他のSQLと同様、INDEXをはるってのが1番で、あとはなるべく実行しない方法を探すのがよいようで。
次に、TRANSACTION。これはかなり大きかった。1,2万行を順にINSERTしていく手前でBEGIN→終了時COMMITとするだけだが、これも速度がだいぶん速くなったように感じた。
DELETE&INSERTよりREPLACEを使うのがいいと書いている人もいるが、
目からウロコだったのは、INSERT文のVALUES部にUNION ALLしたSELECT文を用いるやり方。

SQLiteで最も速く複数行INSERTする方法 | transhumanist note
要は、複数行の実行をお纏めしちゃうわけで、これはなかなか面白いやり方だと思った。

まぁ、あとできることはVACUUMしてゴミを減らすことかな・・・

ExcelVBA覚書 コマンド実行

Dir関数でファイルがないってときに、
 ただファイルがないのか、ネットワークにつながってないのかわかんないの?
 Ping飛ばしてネットワークにつながってるのか調べたらいいじゃない?
みたいな要件があって、まぁ、正直、「そこまでやるか?」って思ったけど、そういう環境で動いている人は、そういう発想になるんだろうなぁ・・・と思って、教えてもらったPing送信術をアレンジしてExcelに埋め込んでみた。

Public Function CheckNetwork(ip As String) As Boolean
    
  Dim wsh As Object
  Dim buf As String
    
  On Error GoTo ErrCheck

  Set wsh = CreateObject("WScript.Shell")
  wsh.Run "%ComSpec% /c ping -n 1 " & ip & " | clip ", 0, True
  buf = GetObject("\" _
               , "htmlfile").ParentWindow.ClipboardData.GetData("text")
  If InStr(buf, "ラウンド トリップの概算時間") > 0 Then
      CheckNetwork = True
  End If
  Exit Function
ErrCheck:
  err.clear
End Function

ちなみに、「%ComSpec%」は、「%SystemRoot%\system32\cmd.exe」のことらしい。
「 | clip」でクリップボードに入れて、それをbufに読み込むようにした。
また、Shellは、Execで動かす方法とRunで動かす方法があるが、Runのほうが、コマンドの窓が表示されないようにできるので、こちらを採用。
面倒な要件は、解決できると嬉しい。
解決しないと、逆恨みしそうだけど。

ExcelVBA覚書 シートロック、でもフィルターは使いたい

あるよねぇ~~~~
ってことで、

Sub ProtectSheet
    With ws
        If Not .ProtectContents Then         'ロックされていないときだけロック処理
            .Protect Password:="password"
                   , DrawingObjects:=True
                   , Contents:=True
                   , Scenarios:=True _
                   , AllowFiltering:=True     'ここでフィルターOKにする
        End If
    End With
End Sub

以下は試していないけれど、これでもOKらしい。

Sub ProtectSheet2
    With ws
        If Not .ProtectContents Then         'ロックされていないときだけロック処理
            .Protect Password:="password"
                   , DrawingObjects:=True
                   , Contents:=True
                   , Scenarios:=True _
                   , userInterfaceOnly:=True
        End If
        .EnableAutoFilter = True
    End With
End Sub

ExcelVBA覚書 Application.Goto

セル選択&移動させる方法はいろいろあるけど、一番手っ取り早いのはApplication.Gotoのようだ。

Sub ActivateRange(rng as Range)
    On Error Resume Next
    Application.Goto rng, True
    err.clear
End Sub

1つ目の引数は選択セル、2つ目の引数はスクロールして移動するかどうか、らしい。
選択だけだったら、rng.selectでもいいように思うけど。

これを使わずに選択させようとなると、

Sub ActivateRange(rng as Range)
    On Error Resume Next
    rng.parent.parent.Activate
    rng.parent.Activate
    rng.select
    err.clear
End Sub

みたいなかんじで、ブック→シート→セルをアクティブにしないといけないわけで、これは面倒。
(親がアクティブになっていないに、子をアクティブにはできないのだ)
楽にできる関数があるということで、メモ。

ExcelVBA覚書 このパスどこ?

このパスはローカルなのかネットワークサーバなのか・・・
とりあえず判定ロジックを作ってみた。

'ローカルならTrue、ネットワークならFalse
Public Function CheckLocal(filepath as String) As Boolean
    
    Dim cap As String
    Dim fso As Object
    Dim obj As Object
    
    '先頭が\なら確実にネットワーク
    cap = Left(filepath, 1)
    If cap = "\" Then
        Exit Function
    End If

    'ドライブ割当のローカル/サーバ確認
    Set fso = CreateObject("Scripting.FileSystemObject")
    For Each obj In fso.Drives
        If obj.DriveLetter = cap Then
            If obj.DriveType = 3 Then
            Else
                CheckLocal = True
            End If
            Exit Function
         End If
    Next
    'ここまで来たらどこかは不明
End Function

Java覚書 ExcelのSLOPE関数をJava化してみる

回帰直線の傾きを求めるExcelのSLOPE関数をJavaで作成してみる。

public class Main {
    public static void main(String[] args) throws Exception {
        // y値のみで、かつ、int型
        int y[] = new int[]{70,80,30,40,50,20};
        slope(y);
        // x,y値で、かつ、float型
        float[][] xy = { {2.5F,10.3F}
                        , {3.0F,24.3F}
                        , {3.2F,30.5F}
                        , {5.0F,42.5F}
                        , {6.1F,53.4F}
                        , {8.9F,48.8F}
                       };
        slope(xy);
    }
    
    // 回帰直線の傾きを算出(int型 y値のみ渡す)
    static float slope(int val[]) {
        float[][] f = new float[val.length][2];
        int i = 0;
        for(int v : val) {
            f[i][0] = (float)i;
            f[i][1] = (float)v;
            i++;
        }
        return slope(f);
    }
    
    // 回帰直線の傾きを算出(float型 x, y値を渡す)
    static float slope(float[][] val) {
    float sumX = 0;
    float sumY = 0;
    float sumXX = 0;
    float sumXY = 0;
    float n = val.length;
    for(int i = 0; i < val.length; i++){
       float x = (float)val[i][0];
       float y = (float)val[i][1];
       sumX += x;
       sumY += y;
       sumXX += x*x;
       sumXY += x*y;
     }
     System.out.println("a : " + (float) (n*sumXY-sumX*sumY)  / (float) (n*sumXX-sumX*sumX));
     System.out.println("b : " + (float) (sumXX*sumY - sumXY*sumX) / (float) (n*sumXX - sumX*sumX));
     return (float) (n*sumXY-sumX*sumY)  / (float) (n*sumXX-sumX*sumX);
    }
}

下手をしてしまったこの1週間

いやぁ、参った。
自分が基本的なことを怠った所為なのだけど。

DBとかのバックアップはとってたのに、WordPress関連ファイルのバックアップをしないまま、WordPressのバージョンアップをしてしまった。
というのも、ここ最近は、エラーもなくバージョンアップできていたからなのだけど。

で、バージョンアップに失敗し、メンテナンスモードから戻らず、挙げ句の果て、FFFTPでバージョンアップしたファイルをアップロードしようとして、サーバに容量が足りないんだぜ!エラー「552 STOR denied: quota exceeded」が発生し、どうにもならん状態で1週間がすぎた。

で、もうダメかなぁ・・・などとブルーになっていたら、wp-content/upgradeのなかに、古いバージョンのファイルがすべてバックアップされているのを発見。
で、そこからファイルを戻して復旧させることに成功した。

おそらくだけど、バックアップとって、バージョンアップさせたら容量が足りなくなったんだろうな。

ということで、アクセスできなかった方々、申し訳ございませんでした。

Excel VBA覚書 CSVファイル読込

久方ぶりの投稿。いろいろあったけど、それはまた別に書くとして、CSVファイルを読み込むときの高速なやり方を探してたらQueryTablesを使った方法というのがあったので、やってみた。

    Dim wb As Workbook
    Dim ws As Worksheet
    Set wb = Workbooks.Add
    Set ws = wb.Worksheets(1)
    With ws.QueryTables.Add(Connection:="text;mega.csv", Destination:=ws.Range("A1"))
        .Name = "megacsv"
        .TextFileCommaDelimiter = True
        .Refresh
    End With

すごかった。30万行一瞬。

Processing3 Javaで動かしてみる

Processingで作成したpdeファイルをJavaにしてみようと思ったが、うまくいかないので、基本的なところから少しずつ試していく。

Processing3を入れて、JRE1.8をいれて、Eclipse上でごねごね。
ネットで調べたとおり、setupのところにsizeメソッドを入れたら怒られて、しょうがないからsettingsメソッドをつくってそっちに入れたら、なんか足りん!と怒られて、こんな感じにしたら、とりあえず斜めに線は引けた。

package test;

import processing.core.PApplet;

public class Test extends PApplet {

	public void settings() {
		size(600, 600, JAVA2D);
	}
	public void setup() {
		background(200, 50, 60);
		smooth();
		strokeWeight(5);
	}

	public void draw() {
		line(0, 0, width, height);
	}

	public static void main(String _args[]) {
		PApplet.main(new String[] { test.Test.class.getName() });
	}
}

先は長そうだ。

SQLServer覚書 8桁数値を日付表示に

さて、最近くだらないことをまじめに書いているので、久しぶりに技術的なことを軽くメモ書きしておこう。

8桁数値を日付(yyyy/mm/dd)表示にする方法

SELECT CONVERT(varchar,CONVERT(datetime, CONVERT(varchar,20160223), 112),111)

1つ目(内側から)は文字列に変換、2つ目のCONVERTではDATETIME型に変換するので、出力としては「2016/02/23 0:00:00」というように日付と時間で出力される。
これを「yyyy/mm/dd」形式の文字列で出力させるために3つ目(一番外側)のCONVERTを用意。

これとは逆に日付を8桁数値に変える場合は、データを「yyyymmdd」の文字列で出力した後、INT(またはNUMERIC)型に変えてしまえばよい。

SELECT CONVERT(int,CONVERT(varchar, '2016-2-14', 112))

Excel印刷範囲指定+ウインドウ枠固定→チカチカ

印刷範囲指定をしてウィンドウ枠を固定すると、アクティブセルのある領域以外の図形がちらついて見える事象。
Excel2010でしか起きないらしい当該事象だが、さてどうしようかと考えると、結局は印刷範囲指定をやめる結論に至った。
解決作的には根治してもらわなければならないのだが、MSさんが重い腰をあげないので、
自分で腰を上げるとするなら、例えば、印刷ボタンを作って、ボタンを押したときだけ印刷範囲指定→印刷→印刷範囲クリアすればよいのかなぁと考えた。
でも、厳密に印刷設定を行う必要性がないのであれば、印刷の拡大率を設定しておくだけでも何とかなるような気もする。