Translate

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の方の機能が使えるらしーので
そちらを使ってソートしてみました。

2009年9月27日日曜日

指定されたフォルダ以下のゴミ削除

指定したフォルダ以下にある、ファイル名が"~"で終わるファイルを削除するプログラムを作ってください。 指定したフォルダの中にあるフォルダのさらに中にあるファイルも削除の対象です。

問題



perlで書いてみた。

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

die e("使用方法: $0 directory string") if(@ARGV != 2);

my $directory = $ARGV[0];
find(\&del, $directory);
exit;

sub del{
my $pattern = $ARGV[1];
unlink $_ if(-f $_ && /$pattern$/);
}



javascriptでは・・・基本的に無理ですね。
WSH使えばできないこともないですが...

2009年9月5日土曜日

Cを少しずつ学習してみるテスト。

ひとまず、こんにちはこんにちは!から。

#include 

int main(void){
printf("こんにちは、こんにちは!!¥n");
return 0;
}


1行目:printf関数を使うがために、 #includeで標準ライブラリ(stdio.h)を読込む。
3行目:mainの前のキーワードは、返り値の型をさしている。後述をするが、0を返すのでintを指定
    mainは、ここからコードが始まるので必ず必要。
    mainの後の括弧内は、引数を指定。今回はないのでvoid。
4行目:printfで標準へ出力。
5行目:return 0で正常に終了できたことを知らせる。 mainにだけ必要。
<参考>
【C言語講座】標準ライブラリ関数


型と最小範囲のメモ

最小範囲
char-127〜127
unsigned char0〜255
signed char-127〜127(=char)
int-32767〜32767
unsigned int0〜65535
signed int-32767〜32767(=int)
short int-32767〜32767(=int)
unsigned short int0〜65535
long int-2147483647〜2147483647
signed long int-2147483647〜2147483647(=long int)
unsigned long int0〜4294967295
float小数精度6桁
double小数精度10桁
long double小数精度10桁



ちょっとメモ。
・main関数が起点
・main関数の最後はreturn0をする
・scanfで受け取った値は、&をつけた変数に渡す(ポインターでよい?)
・条件式では、0以外の値が真、0が偽と評価される。
・if文で文が1つの時は、中括弧使わない。。
・標準入力で文字を受け渡す方法が今のところよくわからん(現在独習Cの3章付近)


第6章にきた。
ポインター。

ポインターかぁ。。

#include 

int main(void){
int *p, q;
q = 199;
q = &q;
printf("%d", *p);

return 0;
}


perlだとこんな感じか。
use strict;
use warnings;

my $q = 199;
my $p = ¥$q;
print ${$p}, "¥n";

&がリファレンスで*がデリファレンスという感じかと
思ったけどそういう使い方とはちょいと違うのね。

最初の型宣言で、int型のアドレスを受け取る入れ物を
用意するってのが int *p なのね。
で、アドレスを渡しておかないとこの子には格納することができないのね。

2009年8月23日日曜日

読書。

読書の夏ですね。
というわけで、『はじめてのAIプログラミング』を読んでるわけなんですが
n-gramによるテキスト処理の説明があったのでコードを書いてみた。

Ngram.pm
package Ngram;
use strict;
use warnings;
use utf8;
use base qw(Class::Accessor::Fast);
__PACKAGE__->mk_accessors(qw(n str));
our $VERSION = '0.01';
use Encode;
sub d{decode('utf8', shift)};
sub e{encode('utf8', shift)};

sub make{
my $self = shift;
my @error;
$self->{n} = $self->{n} || 3;
$self->{str} = $self->{str} || push @error, "文字列を与えてください。";
push @error, "数字を指定して下さい。" if($self->{n} !~ m/^\d+$/);
die join("\n", @error) if(@error);


$self->{str} =~ s/\n//g;
$self->{str} =~ s/\s//g;
my @list = split(//, $self->{str});

die e("文字数が足りません!\n".
$self->{n}. "文字以上でお願いします") if($self->{n} > @list);
my $keyword = '$list[$i]';
if($self->{n} > 1){
for (1..$self->{n}-1){$keyword .= '.$list[$i+'. $_. ']'};
}

for my $i (0..@list-$self->{n}){
$self->{analyze}{eval($keyword)}++;
}
}

sub say{
my $self = shift;
for my $key (sort { $self->{analyze}{$b} <=> $self->{analyze}{$a} } keys %{$self->{analyze}}){
print e($key), ":", $self->{analyze}{$key}, "\n";
}
}

1;



#!/usr/bin/perl;                                                                                                 
use strict;
use warnings;
use utf8;
use lib qw(./lib);
use Ngram;

my $ngram = Ngram->new({
n=>2,
str=>"abcbacbcbabcabcabbcabcbabcabacbabcbcabcabbcabcabacb"
});
$ngram->make;
$ngram->say;



n=1なら
b:21
c:15
a:15

n=2なら
ab:12
bc:12
ca:8
cb:7
ba:6
ac:3
bb:2

n=3なら
bca:8
abc:8
cab:8
cba:4
bcb:4
bab:3
acb:3
bac:3
abb:2
bbc:2
aba:2
cbc:2

まずはここまで。。

hashのソート。

めもめも。
ハッシュのkeyでソートする場合とvalueでソートする場合。

・keyでソートする場合
#/!us/bin/perl                                                                                                  
use strict;
use warnings;
use utf8;

#適当な値を用意しておく
my %hash = (
bri => 48, sdu => 57, mff => 96,
egt => 61, nem => 3, vik => 65,
mrq => 22, mph => 54, wbj => 44,
mgl => 27,
);

print "key sort\n";
for my $key (sort keys %hash){
print $key, ":", $hash{$key}, "\n";
}

実行結果
key sort
bri:48
egt:61
mff:96
mgl:27
mph:54
mrq:22
nem:3
sdu:57
vik:65
wbj:44

・valueでソートする場合
#/!us/bin/perl                                                                                                  
use strict;
use warnings;
use utf8;

#適当な値を用意しておく
my %hash = (
bri => 48, sdu => 57, mff => 96,
egt => 61, nem => 3, vik => 65,
mrq => 22, mph => 54, wbj => 44,
mgl => 27,
);
print "value sort\n";
for my $key (sort{$hash{$a} <=> $hash{$b}} keys %hash){
print $key, ":", $hash{$key}, "\n";
}

実行結果
value sort
nem:3
mrq:22
mgl:27
wbj:44
bri:48
mph:54
sdu:57
egt:61
vik:65
mff:96

2009年8月14日金曜日

こんにちはこんにちは

javaにちょっとだけ、入門してみる。

public class Hello {
public static void main(String[] args){
System.out.println("こんにちはこんにちは!!");
}
}


Hello.java で保存。
javac Hello.javaでコンパイル。
java Hello で実行っと。

文字化けするなら
jjavac -J-Dfile.encoding=UTF-8 Hello.java
java -Dfile.encoding=UTF-8 Hello
のようにするとよい。



1行目:public class Hello{
・Helloというクラスの宣言
・class名の前にpublicと書いた場合そのclass名+.javaになる
・上記のことより、publicと書かれたclass名は1つのファイルに一つのみ。
・class名の大文字小文字の区別はされるのでファイル名と統一すること。
おkおk。


2行目:public static void main(String[] args){
・mainメソッドが開始位置。
おkおk。


3行目:System.out.println("こんにちはこんにちは!!");
・printlnは最後に改行を挟む。
・標準出力をする。
おkおk。


なお、1行目・2行目に出てきたアクセス修飾子(ここではpublic)は、
private、指定なし、protected、publicの4つがあり

private指定なしprotectedpublic
同じクラス
同じパッケージ内のサブクラス×
同じパッケージ内の非サブクラス××
他のパッケージのサブクラス××
他のパッケージ内の非サブクラス×××

※サブクラスは継承先のクラス。

◇クラスの定義は
[アクセス修飾子] class [クラス名] extends [継承元クラス名]{
クラスの中身(メソッドがずらずらと並ぶ)
}


◇メソッドの定義は、
[アクセス修飾子] [戻り値の型] [メソッド名] ([引数の型1] [引数の名前1], …){
処理
return 戻り値
}

ちなみに、
おはよう。
こんにちわ。
こんばんわ。
の3行を表示させるなら

改行(¥n)をつかって。
public class Hello {
public static void main(String[] args){
System.out.println("おはよう。¥nこんにちわ。¥nこんばんわ。");
}
}

となるっと。

■型(よく使うもの)
long (数字L)
int
double
boolean
char(1文字、シングルクォーテーションで囲う)
String(ダブルクォーテーションで囲う。大文字であることに注意)

■配列
型[] 変数 = new 型[要素数]
型[] 変数 = new 型[]{値1, 値2, 値3}
型[] 変数 = {値1, 値2, 値3}

■多次元配列
型[][] 変数 = new 型[行数][列数]
型[][] 変数 = {{値1, 値2, 値3}, {値4, 値5, 値6}, {値7, 値8, 値9}};

■拡張for文
for(型 変数名 : 配列変数){}


■名前空間(package)
Classa.java

package hogehoge;
import barfoo.Class2;

public class Class1{
public static void main(String[] args){
Class2.funk2();
}
}

Class2.java
public class Class2{
public static void funk2(){

}
}

■標準入力からデータを受け取る
BufferedReader 変数名1 = new BufferedReader(new InputStreamReader(System.in));
String 変数名2 = 変数名1.readLine();

2009年8月12日水曜日

SQLのメモ

◇テーブルへデータを登録 その1
INSERT INTO [table_name] VALUES (val1, val2, …);
・最初の列から順に登録。値は省略できない。
・途中の列で登録したいデータがない時はNullを指定。


◇テーブルへデータを登録 その2
INSERT INTO [table_name] (col1, col2, …) VALUES ( val1, val2, …);
・必要な列と値だけ登録する。


◇テーブルへデータを登録 その3
INSERT INTO [table_name] SET col1 = valu1, col2 = valu2, …;


◇データを更新
UPDATE [table_name] SET col1=val1, col2=val2, … WHERE 条件;
・例えば、掲示板とかブログで条件にIDでひっかけて内容を更新とか。
・条件については、後述。


◇データを削除
DELETE FROM [table_name] WHERE 条件;
・条件については、後述。


◇検索
SELECT col1, col2, … FROM [table_name] 条件;
・重複排除(DISTINCT)
 SELECT DISTINCT col1, col2, … FROM [table_name] 条件;

・並び替え(ORDER BY)
 SELECT col1, col2, … FROM [table_name] ORDER BY [ソートの基準となる列] [ASC/DESC];
  ASC-昇順 / DESC-降順
  ・ORDER BY RAND()でランダムに並び替えを行う。


◇条件
WHERE 列名 演算子 値
・演算子
  a=b aとbが等しい
  a<>b aとbが等しくない
  a<b aがbより小さい
  a>b aがbより大きい
  a<=b aがb以下
  a>=b aがb以上

WHERE 列名 LIKE 条件;
・部分一致
  _ 任意の1文字
  % 任意の文字列(0文字を含む)
  
  (例)WHERE program LIKE 'java%';
   これでjavaもjavascriptもひっかかるわけですね。
   参考⇒文字列の比較 likeとワイルドカード

プレースホルダー確認めも。

◇doメソッドの場合
$dbh->do("SQL文", undef, 値);

◇prepareメソッドの場合
my $sth = $dbh->prepare("SQL文");
$sth->execute(値);

それぞれのSQL文で使用したプレースホルダに該当する数の
値をdoメソッドなら第3引数以降に。executeなら第1引数に。

という感じか?

SQLインジェクション

プレースホルダって、SQL文を何度も発行するのを省く為の物
って認識があったけど、クォート文字、バックスラッシュ、
nullバイトのような特殊文字のエスケープをしてくれるのね。
つまり、SQLインジェクション対策にもなっていると。
だから、どんなに簡単な命令でも使っておけってわけか。
なるへそ。

2009年8月11日火曜日

MySQLの設定ファイル検索順(5.0/5.1)のメモ

1./etc/my.cnf
  (/etc/mysql/my.cnf 5.1.15-beta以上で有効??)
2.$MYSQL_HOME環境変数に指定されたディレクトリ/my.cnf
3.--defaults-extra-fileオプションに指定されたファイル
4.$HOME/my.cnf
5.DEFAULT_SYSCONFDIR/my.cnf
(./configure --sysconfdir= 
で指定されたディレクトリ。5.0.21以上で有効らしい。)


その他のめも。
my.cnf の記述ルール。
マイナス(-)をアンダースコア(_)にしても認識可。
#・・・コメント行
;・・・コメント行
[group]・・・次のグループ宣言までこのグループのオプション扱い。
!include・・・追加で読込むファイルを指定
!includedir・・指定したディレクトリ以下のファイルを追加設定ファイルとして読込む

2009年7月6日月曜日

MySQLのメモ

ちょいちょいずつ整理しながら追加していく予定。
・ルートで起動(mac OS X)
/usr/local/mysql/bin/mysql -u root -p



◇作成/設定
・データベースの作成
CREATE DATABASE {データベース名};


・テーブルの作成
CREATE TABLE {テーブル名}(
 {名前} {型} {etc},
 {名前} {型} {etc},
 {名前} {型} {etc},
 {名前} {型} {etc}
);





◇確認
・バージョン
SELECT VERSION();


・データベース一覧取得
SHOW DATABASES;


・データベース内のテーブル一覧取得
SHOW OPEN TABLES FROM {データベース名};


・テーブル内、型一覧
SHOW FIELDS FROM {テーブル名};
or
DESC {テーブル名};


・テーブル内データ一覧取得
SELECT * FROM {テーブル名};


・テーブルのSTATUSを調べる
SHOW TABLE STATUS;



◇文字コードの確認
・デフォルト文字コード設定を確認
status


・データベースの文字コードを確認
SHOW CREATE DATABASE {データベース名};


・テーブルの文字コードを確認
SHOW CREATE TABLE {テーブル名};


◇削除
・テーブルの削除
DROP TABLE {テーブル名};


・データベースの削除
DROP DATABASE {データベース名};



◇他
・データベースの切替
USE {データベース名}


・コマンドを抜ける
exit or quit

2009年7月1日水曜日

SPIDERING HACKS(#18)

#18は、スクリプトにプログレスバーを追加してみよう♪
ってお話ね。
原理は、LWP::UserAgentのオブジェクトを作ったのちに
getやらpostする時に、:content_cbヘッダに関数を指定することで
ある一定サイズのダウンロードが行われるたびに上記:content_cbに
指定した関数が呼び出されるを利用して、ダウンロードの進捗を表す
プログレスバーを作ろうってこった。

ちなみに、一定サイズのダウンロードごとに関数が呼び出されるわけだが
:content_cbヘッダと共に:read_size_hintというヘッダに、どのくらいの
ダウンロードサイズごとに関数を呼び出すか参考までに指定することが
できるそうな。
(指定したから、必ずそのサイズごとに呼ばれるわけではないらしい)


もっとも原始的な物はこんな感じになる。
#!/usr/bin/perl#!
use strict;
use warnings;
use LWP;
$|++;

die "[error]URLを指定して下さい。\n" unless @ARGV;
my $final_data; #受信データを格納する変数
for my $url (@ARGV){
$final_data = '';
print "URL", substr($url, 0, 40), "のダウンロード中...";
my $ua = LWP::UserAgent->new();
my $res = $ua->get($url, ':content_cb'=>\&callback);
print "\n";
}

sub callback{
my ($data, $response, $protocol) = @_;
$final_data .= $data;
print ".";
}


ポイントは、
5行目で特殊変数$|に0以外の数値を指定してバッファリングしないようにしている点
13行目で:content_cbをセットしている点かな。

他の物については、後でおいおい追加してメモ書きしておくかな。。

2009年6月29日月曜日

SPIDERING HACKS(#14)

#14は、相対URLを絶対URLに直しちゃうってお話ですね。
どうやら、URIモジュールのnew_absってメソッドに
相対URLとBaseURLを渡すと絶対URLを返してくれますよん。
ってことなんだって。

じゃ、BaseURLをどうしてゲットすりゃいいのかって話になると
LWP::UserAgentオブジェクトでgetとかpostした後でbaseメソッドで
取り出せるんですね。

ここいらの話を使ってコードを書いてみるとこんな感じ。
#!/usr/bin/perl#!/usr/bin/perl                                                                                     
use strict;
use warnings;
use URI;
use LWP;

#適当に階層の深そうなアドレスを用意してみる。
my $uri = URI->new('http://search.cpan.org/~gaas/URI-1.38/URI.pm');
my $UA = LWP::UserAgent->new();
my $response = $UA->get($uri);

#下記相対URLを絶対URLに直してみる。
my @list = qw(./1.html ./../2.html ./../../3.html ./hoge/0.html);

for my $list (@list){
print URI->new_abs($list, $response->base), "\n";
}


実行してみるとこうなる。
http://search.cpan.org/~gaas/URI-1.38/1.html
http://search.cpan.org/~gaas/2.html
http://search.cpan.org/3.html
http://search.cpan.org/~gaas/URI-1.38/hoge/0.html


なるほろね。
おまけ。
URIモジュールといえば、アドレスを分解するのに
非常に便利いいのでここにのっけておく。。
#!/usr/bin/perl#!/usr/bin/perl                                                                                     
use strict;
use warnings;
use URI;

my $u = URI->new('http://www.cpan.org/authors/00whois.html#hogehoge');

print "scheme:", $u->scheme, "\n";
print "opaque:", $u->opaque, "\n";
print "path:", $u->path, "\n";
print "frag:", $u->fragment, "\n";
print "host:", $u->host, "\n";


実行結果は
scheme:http
opaque://www.cpan.org/authors/00whois.html
path:/authors/00whois.html
frag:hogehoge
host:www.cpan.org

2009年6月28日日曜日

SPIDERING HACKS(#12)

formのメソッドタイプがGetの場合はURIモジュールのquery_formメソッドを
使うと便利よいよって話なので、それを使ってなにか書いてみる。

例)知恵袋にクエリーを送ってヒットした件数を抜き出す。
文字コード:utf8
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use URI;
use LWP;
use Encode qw(decode_utf8 encode_utf8);

my $search_word = decode_utf8(shift);
my $browser = LWP::UserAgent->new();
my $uri = URI->new('http://search.chiebukuro.yahoo.co.jp/search/search.php');
$uri->query_form(
flg => 3,
fr => 'chie-search-t',
p => encode_utf8($search_word),
);

my $res = $browser->get($uri);
if(decode_utf8($res->content) =~ m/([\d,]+件)/){
print encode_utf8($1), "\n";
}else{
print encode_utf8('Yahoo!知恵袋で、条件に一致する質問はみつかりませんでした。'), "\n";
}


utf8フラグ付きの鉄則は、スクリプトが受け取る時にdecode(もらうデータの文字コード, '文字列');
自分の書いたスクリプトを離れる時(printする場合や、モジュールに渡す場合などなど)に
encode('渡す先の文字コード', '文字列')
とすればよいっと。
あらかじめutf8に変換するってのがわかっている時は
use Encode qw(decode_utf8 encode_utf8);
のようにutf8用の関数を呼び出すとちょいとコードを書くのが楽になったりするわけね。

というわけで中身のメモ。
1行目 シェバン。(perlのありかを指定)
2行目〜7行目 モジュールの呼び出し
9行目 データの受け取りなのでさっそくdecode_utf8してフラグをつける。
   ※スクリプト実行時の引数がutf8で渡されることを前提としている。
10行目 LWP::UserAgentオブジェクトの生成。
11行目 知恵袋のsearchアドレス
12行目 パラメの組み立て作業。
URIオブジェクトのquery_formメソッドにハッシュで渡せばOK
URIへのエンコードも行ってくれる。
15行目 URIオブジェクトに渡すんでフラグを取る。
知恵袋がUTF8なんでutf8でエンコードする。
18行目 getしてデータを受け取る。contentプロパティにリクエストが格納される。
19行目以下。
データを受け取ったんでdecodeしてフラグをつける。
ヒット件数の部位を正規表現でヒットしたらその件数をprintするか
しなければ、ヒットしなかった趣旨を表示して終了。

formのメソッドがpostの時は下記の感じになる。。
文字コード:utf8
#!/us/bin/perl                                                                                     
use strict;
use warnings;
use utf8;
use LWP;
use Encode qw(decode_utf8 encode_utf8);

my $pref = decode_utf8(shift);
my $address = decode_utf8(shift);
my %pref = (
'北海道'=>1, '青森県'=>2, '岩手県'=>3, '宮城県'=>4, '秋田県'=>5,
'山形県'=>6, '福島県'=>7, '茨城県'=>8, '栃木県'=>9, '群馬県'=>10,
'埼玉県'=>11, '千葉県'=>12, '東京都'=>13, '神奈川県'=>14,'新潟県'=>15,
'富山県'=>16, '石川県'=>17, '福井県'=>18, '山梨県'=>19, '長野県'=>20,
'岐阜県'=>21, '静岡県'=>22, '愛知県'=>23, '三重県'=>24, '滋賀県'=>25,
'京都府'=>26, '大阪府'=>27, '兵庫県'=>28, '奈良県'=>29, '和歌山県'=>30,
'鳥取県'=>31, '島根県'=>32, '岡山県'=>33, '広島県'=>34, '山口県'=>35,
'徳島県'=>36, '香川県'=>37, '愛媛県'=>38, '高知県'=>39, '福岡県'=>40,
'佐賀県'=>41, '長崎県'=>42, '熊本県'=>43, '大分県'=>44, '宮崎県'=>45,
'鹿児島県'=>46, '沖縄県'=>47,
);

my @error;
push @error, encode_utf8("その都道府県は存在しません!\n") if(!exists $pref{$pref});
push @error, encode_utf8("引数が足りません。都道府県と市区町村名を渡して下さい\n")
if(!defined $address);
die print @error, "\n" if(@error);

my $browser = LWP::UserAgent->new();
my $uri = 'http://www.post.japanpost.jp/cgi-zip/zipcode.php';
my $response = $browser->post( $uri,
[
pref => $pref{$pref},
addr => encode_utf8($address),
]
);
die "{$uri}エラー:", $response->status_line unless $response->is_success;
print $response->content, "\n";

スクリプト実行時に都道府県名と市区町村・町名を引数に渡せばOK

この項目での肝はgetの時が
LWP::UserAgentを作ったのち
getメソッドなら
$obj->get('URI', %header); #パラメータはURIモジュール等で先に組み立てておく。
postメソッドなら
$obj->post('URI', [key1=>value1, key2=>value2,...], %header);
で取得が可能というお話ですね。

SPIDERING HACKS(#10)

この項目では、LWP::Simpleでは要求したアドレスからただデータを受け取るだけ
なのに対し、クッキーや認証、要求が成立したのか、駄目だったのかを知るには
LWP::UserAgentでよりブラウザ的な振る舞いをさせるための設定を施し、結果を
HTTP::Response周りの関数で調べましょうね。
ってお話ですね。

ここでは、HTTP::Responseオブジェクトのis_successメソッドで
リクエストの可否を調べれることやリクエストが失敗した場合
status_lineメソッドに情報を取り出せること。
MIMEコンテンツ情報は、content_typeメソッドで調べられますよん
って話ですね。

詳細は、
LWP::UserAgent
とか
HTTP::Response
で、調べると良さそうですね。

2009年6月21日日曜日

SPIDERING HACKS(#9)

SPIDERING HACKSのめも。
やっぱり、この手の物は自分のコーディングの
仕方で書いてみるにこしたこたーないしね。

#9 LWP::Simpleを用いた簡単なデータ取得。
自分なりに書いてみた。

文字コードはutf8で書いてます。
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use LWP::Simple;
use Encode;

my $id = shift || '074'; #デフォルトはNz
die "数字を入力して下さい" if ($id !~ m/\d+/);

#外務省海外安全ホームページ
my $url = "http://www.anzen.mofa.go.jp/info/info4.asp?id=$id";
my $content = decode('shiftjis', get($url));
die "{$url}を読込めませんでした。" unless defined $content;

#$contentの中身を解析。
$content =~ s/<!--(.*?)-->//gs;
$content =~ / SELECTED>▼([^<]+)</;
print encode("utf8", "$1\n");
if($content =~ /現在、危険情報は/){
print encode("utf8", "現在、危険情報は出ていません。\n");
}else{
print encode('utf8', "詳細をhttp://www.anzen.mofa.go.jp/で確認して下さい!\n");
}


4行目でuse utf8;をしてマルチバイト文字列はフラグ扱いしています。

8行目メモ。
フラグ付きのコードを書く時って、通常外からデータが来たら
フラグをつけて、出ていく直前にフラグを取るのが鉄則だったり
するけども、8行目のIDについては数字(非マルチバイト)を扱うので
フラグをつけようとしてません。。

13行目メモ。
海外安全ホームページの文字コードはshiftjisなのでフラグ付きにする際に
decode('shiftjis', get($url))で“shiftjisですよ”と教えてあげる。

14行目メモ。
die "{$url}を読込めませんでした。" unless defined $content;

{$url}←これ。
フラグ付きコード特有のあれです。
フラグ付きにすると、マルチバイト文字列をも変数にすることができます。
my $日本語 = "あいうえお";
すら扱うことができます。
つまり、"$urlを読込めませんでした。"ってすると$urlからでした。までが
変数扱いを受けてGlobalだyo!っておこられます。
なので、中括弧でかこって、{$url}とすることで変数がどこまでか明確化するか
$url を読・・・のように半角スペースを入れて変数を区切る必要がありますね。

19,21,23行目
フラグ付きの鉄則として外に出す前にエンコードってことで
エンコードしてます。本コードがutf8で書いているので
エンコードする際には、utf8にしてね。としています。

以上!

2009年6月7日日曜日

CGI::Session

ちょいとメモ。
あちこち眺めつつ、サンプルをまねて.plで実行したら
セッション情報の書き込まれたファイルが生成されるのに
対し、.cgiでローカル環境で動かしてみたらファイルが
生成されないのは、なんで??
レンタル鯖にアップしてみたら普通に生成されてるし。。
うーん。

こういうもんなの??

2009年6月3日水曜日

diredモードのメモ

・diredモード
  → C-x + D

・directoryの作成
  → + (ディレクトリ名)

・directory/fileの削除(Delete)
  → 削除したい(directory|file)にカーソルを合わせ(大文字)D

・ファイル名を変更する(Rename)
  →(大文字) R

・表示内容を更新する
  → (小文字) g

2009年5月6日水曜日

Class::Accessor::Fastモジュール

Class::Accessor::Fastは、オブジェクト指向な書き方における
bless部分やgetter/setter部分を何度も書いてげんなりするのを
代わりに受け持ってくれるモジュール。

#./lib/Hogehoge.pm
package Hogehoge;
use strict;
use warnings;

sub new{
my $class = shift;
my $ref_arg = shift;
my $self = bless {
foo => $ref_arg->{foo},
baa => $ref_arg->{baa},
}, $class;
return $self;
}

sub accessor{
my $self = shift;
my $name = shift;
if(!@_){
return $self->{$name};
}else{
$self->{$name} = shift;
}
}

sub foo{
my $self = shift;
$self->accessor("foo", @_);
}

sub baa{
my $self = shift;
$self->accessor("baa", @_);
}


#./test.pl
use strict;
use warnings;
use lib qw(./lib);
use Hogehoge;

my $obj = Hogehoge->new({foo=>"abc", baa=>456}); #オブジェクト生成と初期化
print $obj->foo, "\n"; #getter:「abc」と表示
print $obj->baa, "\n"; #getter:「456」と表示

$obj->foo(11111); #setter:「11111」とセット
print $obj->foo, "\n"; #getter:「11111」と表示


毎回、内容の、変わらないbless部分とgetter/setter部分を書くのは
めんどくさ。
そんなわけで、Class::Accessor::Fastモジュールの登場。
上記と同じことは下記でOK
#./lib/Hoge.pm
package Hoge;
use strict;
use warnings;
use base qw(Class::Accessor::Fast);
__PACKAGE__->mk_accessors( qw(baa foo) );
1;


超すっきりですね。
オブジェクトを生成したりセットしたり書き換えたりってのは何も変わらないです。
便利便利ですね。
最初の書き方だと変数が増えるたびに
sub foo{
my $self = shift;
$self->accessor("foo", @_);
}

のようにaccessorメソッドにアクセスするためのメソッドが必要でしたが
今度は、
__PACKAGE__->mk_accessors( qw(baa foo) );

mk_accessorsに増やす変数名を追加するだけですね。

2009年2月12日木曜日

[mkdir]ディレクトリを作成する
$ mkdir hoge //hogeディレクトリを作成
$ mkdir -p ~/bar/foo/hoge //指定したディレクトリの親ディレクトリで存在しないものがあれば作成する

オプション
・-m:ディレクトリの作成と共にアクセス権を設定する
・-p:指定したディレクトリのうち親がなければ作成する


[ls]ディレクトリ内のファイルを取得
オプション
・-a:隠しファイル(先頭がドットのファイル)も表示する
・-l:詳細表示する



[ps]実行中のプロセスを表示

オプション
・a:自分以外のユーザーのプロセスも表示
・u:ユーザー名と開始時刻を表示
・x:ユーザーの権限で実行しているプロセスを全て表示


[pwd]カレントディレクトリを表示する。


[rm]ファイル/ディレクリを削除
$ rm hoge.txt //hoge.txtを削除
$ rm *.log //.logとつくファイルを削除
$ rm -r hoge //hogeディレクトリを削除(消す際に警告あり)

オプション
・-d:ディレクトリごと削除。rootのみ
・-f:警告を表示しない
・-i:ファイルを削除するか確認
・-r:指定ディレクトリ以下を削除
・-v:削除前にファイル名を表示


[which]コマンドのあるディレクトリを返す


・Shellを調べる
echo $SHELL

2009年1月25日日曜日

winでのバージョン管理メモ

git gitと騒ぐ昨今ですが、何かの拍子に買った
win用Subversionの本があったのを思い出したので
一通り試してみるてすと。


1.ダウンロード(本体と日本語パック)
http://tortoisesvn.tigris.org/ のdownloadより本体をダウンロード

現在は->The current version is 1.5.7.
TortoiseSVN-1.5.7.15182-win32-svn-1.5.5.msi をゲット。

続けて同ページ下部より
日本語パッケージをダウンロード。
該当する国よりダウンロード。

2.インストール
本体をインストールすると再起動を要求されるので再起動。
で、日本語パックもインストール。

3.日本語メニューに変更
右クリック->TortoiseSVN->Settingsをクリック
Language:を日本語に変更して適用->OK

4.リポジトリの作成
リポジトリ(=保管庫)を作成する。
要は、データを保存するためのフォルダを作成する。
フォルダを作成したらそのフォルダに移動して
右クリック->TortoiseSVN->ここにリポジトリを作成する をクリック
いくつかファイルが生成されるっと。

5.さっそくインポート
データを保存してみます。
作業をしているフォルダを選択して、
右クリック->TortoiseSVN->インポート をクリック
どこのリポジトリにインポートするか聞かれるので
さきほど作成したフォルダを指定してあげる。
でOKをクリック
これでインストール完了。


6.さっそく取り出し作業する。
作業するためにデータをとってきます。
そのためにやることはチェックアウト。
これから作業に使うフォルダを選択
右クリック->SVNチェックアウト をクリック
チェックアウトという画面が出てくるのでリポジトリのある場所を指定してあげる。
これでデータをリポジトリから取り出しっと。

7.何かしらの変更。
7.1ファイルの修正。
適当に変更するとフォルダに緑色のチェックマークがついていたのから
赤色でビックリマークに変更される。
変更が完了したら、
右クリック->SVNコミット をクリック。
内容を確認してOKをクリック。
これでリビジョンが一つあがりるっと。

7.2ファイルの追加。
何かしらのファイルを作成。
この時点では、ファイルに青色ではてなマークがつく。
この状態で、コミットしてもデータが保管されないのでまずは
追加コマンドでSVNにこのファイルも保管してねっ!
って知らせてあげる。

新規ファイルを選択
右クリック->TortoiseSVN->追加
OKをクリック

この時点で青色ではてなマークだったのが青色でプラスマークにかわる。
さっそくコミット。
右クリック->SVNコミット
これで、また、すべて緑色のチェックマークに戻るっと。

7.3ファイルの削除
いらないファイルを選択
右クリック->TortoiseSVN->削除 をクリック
これでファイルが作業フォルダ内では削除されます。
今度は保管庫にそれをつたえてあげる必要があります(要は、コミットする)
一見、何もないから変更しされているのかどうかわかりにくいのですが
右クリック->TortoiseSVN->変更をチェック をクリックすると
ファイルが削除される趣旨が記載されています。

で、
右クリック->SVNコミット をクリック。

ひとまずここまで。

2009年1月24日土曜日

Module::Starter::PBPを入れてみた。

Perlモジュールの作成に使われるModule::Starter::PBPというのを入れる。
で、次にまずはセットアップ。

$ perl -MModule::Starter::PBP=setup

これでホームディレクトリに.module-starterというディレクトリが作られ
次に下記のように名前とメアドが聞かれるので入力する
Please enter your full name:
Please enter an email address:

後で変更したい時は、
~/.module-starter/config を編集すればおk


後は、作業したいディレクトリに移動したのち
$ module-starter --module="モジュール名"

これで、作業ディレクトリにモジュール名のディレクトリが生成されるので
中に移動して
$ perl Build.PL
$ perl Build
$ perl Build test

を叩くとtディレクトリ配下にあるテストを実行するっと。
この時いくつかモジュールがたらんぞーってエラーを
吐く場合があるので必要に応じて追加してあげるっと。

ちなみに、Test::Perl::Criticがたりんってしかられた。。
なので追加。

後は、テストを書いてそれを通過するモジュールを作成しての繰り返していけばよいらしい。

再起動

2009年1月15日木曜日

馴染まず。。。

なんとなくこの書き方がなじまない。。(not なじめない)

変数 = (条件) ? 式1 : 式2

3項演算子の結果を変数に代入する書き方。
読んだら、すんなり理解できるけども、
こんなシチュエーションに出くわしても
思い出せない 笑