Translate

2010年2月20日土曜日

vb.netの正規表現をメモ。
やりたいことはperlで言うとこの以下の内容。

use strict;
use warnings;
use utf8;
use Encode;
sub debug{ print encode("shiftjis", (join "", @_)) }; #winOSコマンドプロンプト用

$_ = "ab_CD_ef_GH";
while(m/[a-z]+/g){
debug($&, "\n");
}
debug("-----------\n");
while(m/[a-z]+/ig){
debug($&, "\n");
}



Imports System.Text.RegularExpressions
Module Module1

Sub Main()
Dim str As String = "ab_CD_ef_GH"
Dim reg As New Regex("[a-z]+")
Dim match As Match = reg.Match(str)

While match.Success
Console.WriteLine(match.Value)
match = match.NextMatch()
End While

Console.WriteLine("-----------")

reg = New Regex("[a-z]+", RegexOptions.IgnoreCase)
match = reg.Match(str)
While match.Success
Console.WriteLine(match.Value)
match = match.NextMatch()
End While
End Sub

End Module

2009年12月16日水曜日

ほんとにめものめものめものめものめも

ちょいとwin32APiに初めて手を出すにあたりいろいろめもってみる。
正直さっぱりわからんw

やりたいことは、他のあぷりを操作したいってことで
ウィンドウのハンドルを取得してメッセージを投げて
ほげほげするってあたり。
ひとまず、vb.netを使ってみるよ!


まずは、操作したいアプリのハンドルを取得するために...
FindWindow 関数
指定された文字列と一致するクラス名とウィンドウ名を持つトップレベルウィンドウ( 親を持たないウィンドウ)のハンドルを返します。この関数は、子ウィンドウは探しません。検索では、大文字小文字は区別されません。

子ウィンドウを探すには、FindWindowEx 関数を使ってください。FindWindowEx 関数による検索は、指定した子ウィンドウから開始されます。

HWND FindWindow(
LPCTSTR lpClassName, // クラス名
LPCTSTR lpWindowName // ウィンドウ名
);

ソース→http://msdn.microsoft.com/ja-jp/library/cc364634.aspx

この子を使う為に行うAPIの宣言は...
Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Integer

ソース→http://www.winapi-database.com/Window/Change/FindWindow.html


じゃぁ、クラス名は?というと下記ソフトらへんを使うとクラス名が判明するっと。
・Winspector Spy(参考記事)
・WinIDWinID

とか使って目的のウィンドウやオブジェクトにカーソルをあてるとすぐにクラス名がわかりますね。
あとは、ウィンドウの名前を指定してあげればおkと。

ウィンドウのハンドルがわかると今度はそこに所属してるオブジェクトのハンドルを取得して
データを送り込んだり読み込んだり、ボタンを押したりする為にウィンドウに所属している
子供のハンドルを取得するために下記関数を使うと。
FindWindowEx 関数
指定された文字列と一致するクラス名とウィンドウ名文字列を持つウィンドウのハンドルを返します。この関数は、子ウィンドウを検索します。この関数による検索は、指定された子ウィンドウの直後の子ウィンドウから開始されます。大文字小文字は区別されません。

HWND FindWindowEx(
HWND hwndParent, // 親ウィンドウのハンドル
HWND hwndChildAfter, // 子ウィンドウのハンドル
LPCTSTR lpszClass, // クラス名
LPCTSTR lpszWindow // ウィンドウ名
);

ソース→http://msdn.microsoft.com/ja-jp/library/cc410853.aspx


この子を使う為に行うAPIの宣言は...
Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _
(ByVal hwndParent As Integer, ByVal hwndChildAfter As Integer, _
ByVal lpszClass As String, ByVal lpszWindow As String) As Integer

ソース→http://www.winapi-database.com/Window/Change/FindWindowEx.html
第1引数は、Findwindowで取得したハンドル
第2引数は、同じクラス名のオブジェクトがあった場合に、最初に見つかった
子ハンドルを渡してあげると次の同じ名前の子ハンドルをしることができると。
第3引数は、知りたいオブジェクトのクラス名を指定。
上に書いたソフトを使えばわかると。
第4引数は、ウィンドウ名だったり(vbのフォームに配置するオブジェクトのプロパティでいうとこの)キャプション名。

で、しれると。
あとは、SendMessageだったり、SendMesageStrとかだったり
非同期送信したければPostMessageをつかったりすると。
例としてSendMessage。

SendMessage 関数
1 つまたは複数のウィンドウへ、指定されたメッセージを送信します。この関数は、指定されたウィンドウのウィンドウプロシージャを呼び出し、そのウィンドウプロシージャがメッセージを処理し終わった後で、制御を返します。

メッセージを送信して即座に制御を返すには、SendMessageCallback または SendNotifyMessage 関数を使ってください。メッセージを 1 つのスレッドのメッセージキューにポストして即座に制御を返すには、PostMessage または PostThreadMessage 関数を使ってください。

LRESULT SendMessage(
HWND hWnd, // 送信先ウィンドウのハンドル
UINT Msg, // メッセージ
WPARAM wParam, // メッセージの最初のパラメータ
LPARAM lParam // メッセージの 2 番目のパラメータ
);

ソース→http://msdn.microsoft.com/ja-jp/library/cc411022.aspx

第1引数は、FindWindowExで知った実際に操作したいウィンドウハンドルを指定
第2引数は、メッセージ。
ウィンドウメッセージとかで検索するとわさわさでてきたりする。
C系では、メッセージが定数として指定されているけどVB.net等では指定されてないので
自分で値を設定してから使うもんらしーよ。
例えば
Public Const WM_SETTEXT = &HC
Public Const WM_GETTEXT = &HD
Public Const WM_IME_CHAR = &H286
Public Const LB_GETTEXT = &H189
Public Const WM_GETTEXTLENGTH = &HE
Public Const LB_GETCOUNT = &H18B
Public Const BM_CLICK = &HF5
って感じにね。
メッセージは種類がやまほどあるんで、そのつど調べて設定して使うと。

第3引数と第4引数は、メッセージによって要求される引数が違うので必要に応じてわたしてあげると。


APIの宣言は、
Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hWnd As Integer, ByVal MSG As Integer, _
ByVal wParam As Integer, ByVal lParam As Integer) As Integer

ソース→http://www.winapi-database.com/Program/Message/SendMessage.html


ちなみに、SendMessageは、引数に数値をとるために文字列を使う場合はSendMessageStrを使うとよいらしー。
Declare Function SendMessageStr Lib "user32.dll" Alias "SendMessageA" _
(ByVal hWnd As Integer, ByVal MSG As Integer, _
ByVal wParam As Integer, ByVal lParam As System.Text.StringBuilder) As Integer



VB.netではlParamの引数にStringじゃなくてStringBUilderを使うらしい。

これをもとに大量加筆しました→自作あぷりからAPIで他のあぷりをいじるときのめも。

2009年10月31日土曜日

某問題を解いていてめもをしておく。

・10進数からn進数へ変換するには?
my $num = 100;
print sprintf("%b", $num), "\n"; #2進数へ
print sprintf("%o", $num), "\n"; #8進数へ
print sprintf("%x", $num), "\n"; #16進数へ

・順列/組合せを全通りも止めるには?
Math::Combinatoricsモジュール使えばおk。

2009年10月18日日曜日

ミリ秒以下の計測を行う

http://kzk9.net/column/time.htmlや
http://okwave.jp/qa4679753.html?ans_count_asc=20を参考に、
ミリ秒以下の計測を行う際のメモ。


#include 
#include

double gettimeofday_msec() {
struct timeval tv;
gettimeofday(&tv, NULL);
return (double)tv.tv_sec*1000.0 + (double)tv.tv_usec/1000.0;
}

int main(){
double t1,t2;

/*開始時間取得*/
t1 = gettimeofday_msec();

/*ここに計測対象を書く*/

/*終了時間取得*/
t2 = gettimeofday_msec();
/*差分から処理時間を求める。*/
printf("処理時間:%.1fms\n", t2 - t1);
}


ちなみに、構造体のtimevalは、
struct timeval {
time_t tv_sec; /* 秒 */
suseconds_t tv_usec; /* マイクロ秒 */
};

2009年9月28日月曜日

n人中m人が当選するくじ

n人の中から公平にm人を選ぶ、くじ引きプログラムを作ってください。

→問題



perlで書いてみた。

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Encode;
sub e{encode("utf8", shift)};
sub d{decode("utf8", shift)};

die e("使用方法: $0 <全体の人数> <当選する人数>\n") if(@ARGV != 2);
my ($n, $m) = (d($ARGV[0]), d($ARGV[1]));
die e("引数は、整数でお願いします") if($n !~ /^\d+$/ || $m !~ /^\d+$/);
die e("全体の人数より当選する人数の方が多くなっています") if($n < $m);


my @list;
push @list, [$_, rand] for (1..$n);
my @sort = map{$_->[0]}
sort{$a->[1] <=> $b->[1]} @list;
print "$sort[$_]\n" for (1..$m);


spliceを使うと
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Encode;
sub e{encode("utf8", shift)};
sub d{decode("utf8", shift)};

die e("使用方法: $0 <全体の人数> <当選する人数>\n") if(@ARGV != 2);
my ($n, $m) = (d($ARGV[0]), d($ARGV[1]));
die e("引数は、整数でお願いします") if($n !~ /^\d+$/ || $m !~ /^\d+$/);
die e("全体の人数より当選する人数の方が多くなっています") if($n < $m);

my @list = (1..$n);
my @lot;
for (reverse 1..$m){
my $rnd = int rand(scalar @list);
push @lot, splice @list, $rnd, 1;
}
print "@lot\n";




javascriptで書いてみた。
function lot(n, m){
if(isNaN(n) || isNaN(m)){
alert("入力値は、半角数字でお願いします");
return;
}else if(n < m){
alert("error:第一引数(参加者の数)より第二引数(当選数)を少なくして下さい")
return;
}
var num = [];
for(var i=0; i<n; i++){num[i] = [Math.random(), i]};
num = num.sort();
var str = [];
for(i=0; i<m; i++){str.push(num[i][1] + 1)};
alert(str.sort(num_sort));
}

function num_sort(a, b){
return a-b;
}



lot(10, 2);
のようにくじ応募者数と当選者数を指定すると
alertで当選者の番号をかえします。


どうようの考えでExcelVBAで書いてみると・・・
Sub lot(m As Integer, n As Integer)
Dim list As Object
Dim i As Integer
Dim str As String
Dim temp() As String

Randomize
Set list = CreateObject("System.Collections.ArrayList")
For i = 0 To m - 1
temp() = Split(list(i), "*")
If str = "" Then
str = temp(1)
Else
str = str & "," & temp(1)
End if
Next i
MsgBox str
End Sub


確か、VBA単体ではソートができなかったはずなんで
.NET Frameworkの方の機能が使えるらしーので
そちらを使ってソートしてみました。