2008年7月 1日

[ruby-list:45177] Re: MySQLに書き込む前にSJISのエスケープ文字を入れる処理ってどうされてますか?

かなり苦労しましたが何とかできました。(勉強になった。)

■まとめ。
MySQL/Rubyを使っている場合は
my = Mysql.init
my.options Mysql::SET_CHARSET_NAME, "cp932"
で解決。

Ruby/MySQLはoptionsが無いっぽいので、
・require "kconv"する。
・MySQLに書き込む前にUTF-8にする。 (str.toutf8)
・MySQLから読み込んだ後にSJISにする。(str.tosjis)


■ソース(ちょっと長くなりますが、後学の為)
## Main.rb ################################################
require "mysql" # MySQLクラス
require "lib/classup.rb" # 既存のクラスに関数を追加

## MySQLインスタンス作成 (setparmは追加した関数)
db=Mysql.init()
db.setparm("localhost","user","pass","mydb","UTF-8","SJIS")

## SQL実行 (runsqlは追加した関数)
sql="select DATA from tbl_test"
csl=db.runsql sql

## 結果を表示 (cslは通常のhashの配列になっている)
csl.each { |r| print "#{r['DATA']}" }
## Main.rb ここまで ######################################

## classup.rb ############################################
require "kconv"

## Hashをオーバーライド
## hashにmapすると、どうしても結果が配列になってしまうので
## 結果をhashで返してくれるように関数を追加。
class Hash
def maph(&b)
inject(clone) {|h, (k, v)| h.update(k => b[k, v]) }
end
end

## MySQLをオーバーライド
class Mysql
## 初期設定
def setparm(dbh,dbu,dbp,dbn,dbchar,txchar)
@_host,@_user,@_pass,@_dbname,@_dbchar,@_txchar=[dbh,dbu,dbp,dbn,dbchar,txchar]
end

## SQL実行
def runsql(sql)
#SQL文の文字コードを変更
sql=sql.toutf8 if @_dbchar == "UTF-8"
#SQL実行
self.connect(@_host,@_user,@_pass,@_dbname)
csl=self.query sql
self.close

#SQLの実行結果をハッシュ配列に変換(selectの場合のみ)
splt=sql.split(" ")
if splt[0].upcase == "SELECT" then
cursol=[]
csl.each_hash(with_table=false) do |cline|
hary=cline.maph{|x,y| y.tosjis}
cursol<<hary
end
csl=cursol
end

#配列/実行結果を戻す
return csl
end
end
## classup.rb ここまで ###################################

まとめここまで =====================

> これがオープンクラス。
> 既存のクラスにメソッドを追加するとき、既存のメソッドやインスタンス変数と
> かぶらないよう気をつければ、オープンクラスは味方になってくれます。
> 逆に、かぶってしまうと見付けづらいバグになります。

やっぱそうですよね。
「そういうリスクがあることを踏まえたうえで使いましょう」という
仕様ということで理解です。

> まあ、ほんとはブロック使うべきですがそれは次の段階ということで。
善処します...


> eachの代わりにmapを使えばいいという指摘は既出なのでおいといて、
> この場合わざわざインスタンス変数にする意味がないと思います。
> @sql、@cursor、@curはローカル変数で十分です。

ついにローカル変数とインスタンス変数の違いを覚える時が来たのですね...
「どちらも他のオブジェクト(インスタンス)からは見えないけど、
特にローカル変数はインスタンス内の他の関数からも見えない」
でしたっけ。
一通り修正しました。ついでに変数名も@_hostとかわかりやすく。

mapがうまく使えなかったのでHashに関数を追加して仮対策したのは
前述のとおりです。将来の自分が解決することに期待。

>> self.connect("#{@dbh}","#{@dbu}","#{@dbp}","#{@dbn}")
> ここも式展開を使うまでもなく、普通に変数で指定すればよい。

ここ以外にもこういう扱いをしている部分があったので
だいぶ掃除しました。
POSTで受け取った値の扱いがイマイチよくわからない(to_iとか
するとエラーになる)のですが、それはまた別途。

> というかdbが未定義だから、
> undefined local variable or method `db' for main:Object (NameError
一因でした。(ノ∀`)タハー

>> ・runsqlの中でrequire "kconv"をやっている。
>> initializeで出来ないかなぁ...MySQLのinitializeとぶつかりそうだなぁ
>
> lib/classup.rbの冒頭に置けばいいです。

これもそのうち整理しないと。
Mainのソース内でrequireしたライブラリ(モジュール?)は、Mainの中で使っている他のク
ラスに影響するかとか。


> # adgjmptwが気になってぐぐってみたら、携帯電話でアルファベットにして2〜9を
> # 順番に打つと出るんですね…

フフフ....そうなのです。人にアドレスを教えるときに便利なのです。まあ、最近は赤外
線とか使えば一発ですが。
結構競争率が高いのですが、自分のプロバイダと携帯電話はこのアドレスをGETしました。

いっぱいアカペンありがとうございました。
(スーパープログラマーな人もこうやってKnowHowを吸収してきたんかなぁ)

--
============================
Katsumi Tada
mailto:adgjmptw@xxxxx


投稿者 xml-rpc : 2008年7月 1日 14:55
役に立ちました?:
過去のフィードバック 平均:(0) 総合:(0) 投票回数:(0)
本記事へのTrackback: http://hoop.euqset.org/blog/mt-tb2006.cgi/74835
トラックバック
コメント
コメントする




画像の中に見える文字を入力してください。