はじめまして
VB、ADO共に初心者です。
VB6.0でADOでSybaseのDBから以下のようにデータを取得しようとした時に、
rsRead.Fields(0).valueの値が日本語の場合、文字化けしてしまいます。
'Connection(DBFファイル読み込み用)
Set cnnRead = CreateObject("ADODB.Connection")
cnnRead.Open "dsn=XXXXX;uid=AAAAA;pwd=BBBBB"
'RecordSet(DBFファイル読み込み用)
Set rsRead = CreateObject("ADODB.Recordset")
'DBFファイルのデータ検索用SQL文作成処理
sSelSql = "SELECT COL1 FROM ・・・・・"
'SQL実行
rsRead.Open sSelSql, cnnRead
Do Until (rsRead.EOF)
vTemp = rsRead.Fields(0).value
Loop
SybaseのDBというのがUTF-8でデータが格納されています。
VBがUnicodeで扱っているあたりが、怪しいと思いますが、
全くわかりません。
教えていただけないでしょうか。
宜しくお願い致します。
>cnnRead.Open "dsn=XXXXX;uid=AAAAA;pwd=BBBBB"
ということなら、コード変換はODBCドライバが行っているのでは?
ODBCドライバSybaseとネイティヴ接続できるOLEDBプロバイダがあるのかどうか?
を確認するのと、
文字化けの内容というか傾向というか、
「本来どういうコードでくることが期待されていて、
実際どういうコードかきている」
のかが明確になれば、自ずと解決が見えてくるはずです。
>ODBCドライバSybaseとネイティヴ接続できるOLEDBプロバイダがあるのかどうか?
訂正。
ODBCドライバ経由じゃなくて、
その代わりに、Sybaseとネイティヴ接続できるOLEDBプロバイダがあるのかどうか?
それがあるなら、そっちを試してみるとか。
>ODBCドライバ経由じゃなくて、
その代わりに、Sybaseとネイティヴ接続できるOLEDBプロバイダがあるのかどうか?
ご回答ありがとうございます。
上記内容(OLEDBプロバイダの有無)はどのように確認すればよろしいのでしょうか?
またSybaseのDBテーブルに対して、ACCESSからリンクテーブルでテーブルの
内容を見ると、文字化けずに見えます。
> 上記内容(OLEDBプロバイダの有無)はどのように確認すればよろしいのでしょうか?
このあたりを見てみるとか。
http://www.carlprothman.net/Default.aspx?tabid=81
で、当方の場合だと、DataDirectのConnect製品を使う事も多いです。
http://www.datadirect.co.jp/products/index.asp
# もっとも、Sybase自体は利用経験が無いので、
# お力にはなれそうに無いですが……。
>またSybaseのDBテーブルに対して、ACCESSからリンクテーブルでテーブルの
>内容を見ると、文字化けずに見えます。
であれば、そのリンクテーブル(MDB)をVBから読めば化けないかもです。
この場合Jetが文字コード変換している可能性がありますね。
#いや、私もそのSybaseの経験は薄くて環境もないですが。
回答ありがとうございます。
Sybase側のテーブルによってはINDEXが多くてACCESS側にリンクテーブルを
作成できないテーブルがあります。(ACCESSの制限)
またSybaseのINDEXを削除してINDEXを減らすことはしない方法が
必要です。
ASA リファレンス・マニュアルの
-ct コマンド・ライン・オプション
かな?(使ったことありませんけど)
Sybase使ってますけど、普通に化けたことがないので
原因は分かりません。掲示のプログラムも正しく日本語取得できました。
ただ文字セットはセットアップ時のデフォルトで使っていますので
Microsoft CP932 = Win31J-DBCS でした。
もしかしてDBファイルはどこかから提供されたのですか?
#UTF8と分かっているなら自前で変換(VB側で)もありかもです。
>もしかしてDBファイルはどこかから提供されたのですか?
そうなんです。
それで文字コードがUTF-8で格納されているらしいです。
>#UTF8と分かっているなら自前で変換(VB側で)もありかもです。
変換方法がわかりません。
色々StrConv等を使ってためしました。
なるほど
とりあえずこんなのとか
文字列を UTF-8 に変換http://www.geocities.co.jp/SilkRoad/4511/vb/utf8.htm
またはMultiByteToWideChar APIを使った方法などが
あるようです。
UTF-8については
http://homepage1.nifty.com/nomenclator/unicode/ucs_utf.htm#utf8
などでしょうか。(むずかしそう。。)
面倒クサイようなら「エンコード DLL」で検索してみるといいかもしれない
>文字列を UTF-8 に変換>http://www.geocities.co.jp/SilkRoad/4511/vb/utf8.htm
>またはMultiByteToWideChar APIを使った方法などが
>あるようです。
上記サイトの内容は以前に利用して試して見ました。
結果はNGでした。
こうなるとDBがおかしいのでしょうか?
>> #UTF8と分かっているなら自前で変換(VB側で)もありかもです。
> 変換方法がわかりません。
> 色々StrConv等を使ってためしました。
急にStrConvという話が出てきた理由は不明ですが、それはさておき。
そもそも、結果が UTF-8 で受け取られているのかどうかは確認されましたか?
Sybase側が UTF-8 であり、結果が文字化けしているという話はでてきていますが、
文字化けした結果が、具体的にどのように化けているのかと言う話が無いようで。
ADOから返されるデータが、「UTF-8形式のバイナリ」になっているならば、
それを VBで読める形式(UCS-2 または Shift_JIS)に置き換えるのは
さほど難しい作業では無いと思います。
文字コードの変換ならば、過去ログにも幾つかサンプルがありますから。
でも、受け取った時のデータの内容が、Shift_JIS でも UCS-2 でも UTF-8 でも
無いのだとしたら……それは既にデータが破損している状態なのでしょう。
この場合、化けた結果を復元するのは、ほぼ無理でしょうから、化ける原因を
絶つ方向で調査しないと、問題は解決しないのではないでしょうか。
最初に書いたのですが、
>文字化けの内容というか傾向というか、
>「本来どういうコードでくることが期待されていて、
>実際どういうコードかきている」
>のかが明確になれば、自ずと解決が見えてくるはずです。
どういうデータがきているのか確認せずにやみくもにStrConvを使ってもダメでしょう。
そもそも、その辺は本来、ODBCドライバの仕事なので、
無理にVBプログラムでドライバの尻ぬぐいを試みるより、
正しい文字を返す環境を手に入れるほうが賢明かもと思うのです。
>文字化けした結果が、具体的にどのように化けているのかと言う話が無いようで。
以下の通りです。
例)"東京"→"譚ア莠ャ"に化けています。
> 例)"東京"→"譚ア莠ャ"に化けています。
データが化ける、という点について話をしていますので、
文字列としてだけではなく、バイナリ形式として
どのように化けているのかまで、突っ込んで調べてみてください。
たとえば、UTF-8形式の「東京」(E6 9D B1 E4 BA AC)を取得したときに、
VB側ではどのようなバイナリとして取得されますか?
Byte型の配列に受け取ってみて、その内容を確認してみてください。
もし、そのまま、E6 9D B1 E4 BA AC のまま送られてきているのであれば、
Streamオブジェクトを使うことで、UCS-2の「東京」に復元できます。
しかし、5A 8B 71 FF A0 83 6C などとして送られてきているのであれば、
既にデータが破損していますので、完全には復元できません。
'=======================
Dim B() As Byte, S As String
'UTF-8形式の「東京」のバイナリ
ReDim B(5)
B(0) = &HE6
B(1) = &H9D
B(2) = &HB1
B(3) = &HE4
B(4) = &HBA
B(5) = &HAC
'この化け方なら、復元可能です。
'表示上は化けて見えますが、バイナリ自体は変化していません。
S = StrConv(B, 0, 1041)
MsgBox B, , "OK"
'これらの化け方をしているなら、復元は不可能です。
'ある程度の復元はできますが、文字コードの変換時に、
'データの一部が欠損/破壊される事があるため、
'完全には元に戻りません。
S = StrConv(B, vbUnicode, 1041)
MsgBox S, , "NG"
S = StrConv(B, vbFromUnicode, 1041)
MsgBox S, , "NG"
> S = StrConv(B, 0, 1041)
> MsgBox B, , "OK"
上記は、
S = StrConv(B, 0, 1041)
MsgBox S, , "OK"
の間違いです。(まぁ、結果は一緒ですけど)
そして、この "OK" な化け方に限り、下記のようにして復元できます。
Dim Stm As ADODB.Stream
Dim Dst As String
'=== 文字化けデータが、UTF-8のバイナリを持ったString型である場合 ===
Set Stm = New ADODB.Stream
Stm.Open
Stm.WriteText S, adWriteChar 'UTF-8形式のデータを書き込む
Stm.Position = 0
Stm.Charset = "UTF-8"
Dst = Stm.ReadText(adReadAll)
Stm.Close
Set Stm = Nothing
MsgBox Dst
'=== 文字化けデータが、UTF-8のバイナリを持ったByte配列である場合 ===
Set Stm = New ADODB.Stream
Stm.Open
Stm.Type = adTypeBinary
Stm.Write B 'UTF-8形式のデータを書き込む
Stm.Position = 0
Stm.Type = adTypeText
Stm.Charset = "UTF-8"
Dst = Stm.ReadText(adReadAll)
Stm.Close
Set Stm = Nothing
MsgBox Dst
譚ア莠ヤ(全角カナは実際は半角カナ)
008B71FFA0836CFF(エンディアン違うかも)
ということなら
UTF-8を間違ってShift_JISと解釈して、Unicodeへ変換してませんか?
なおすなら、
文字列⇒Shift_JIS変換⇒StreamオブジェクトでUTF-8⇒Unicode
でいけませんか?
?modoshi("譚ア莠ャ")
東京
以下、実験コード
Function modoshi(sInput As String)
Dim bInput() As Byte
bInput = StrConv(sInput, vbFromUnicode)
sInput = convertCharset(bInput, "UTF-8")
Debug.Print sInput
End Function
Function convertCharset(striInText As Variant, toCharset As String) As String
Dim oStream As Object
Set oStream = CreateObject("ADODB.Stream")
oStream.Open
oStream.Type = 1
oStream.write (striInText)
oStream.position = 0
oStream.Type = 2
oStream.Charset = toCharset
convertCharset = oStream.readText()
Set oStream = Nothing
End Function
Dim bTest() As Byte
bTest = vTemp
上記でbTestに格納した後、確認してみると以下のような結果でした。
90
139
113
255
160
131
108
255
>しかし、5A 8B 71 FF A0 83 6C などとして送られてきているのであれば、
>既にデータが破損していますので、完全には復元できません。
上記の記述によれば、データ破損しているということなのでしょうか?
>>既にデータが破損していますので、完全には復元できません。
> 上記の記述によれば、データ破損しているということなのでしょうか?
今回のデータについては、化けてはいますが、破損はしていません。
ですが、元データによっては、「破損する可能性がある」という事です。
私は、Sybaseの事は全くわかりませんので、具体的な対処方法は
わかりませんが……ご自身で環境設定を行う自信が無いのであれば、
Sybaseに詳しい方に、設定を依頼した方が良いかもしれませんよ。
=== 以下、蛇足情報 ===
VB6の使うUnicodeは、UCS-2相当のデータなので、本来は、
[UTF-8のバイナリ]……DB
↓
(DB/ADOの文字コード変換処理)……★UTF-8 → UCS-2 変換
↓
[UCS-2のバイナリ]……VB(文字列型の内部形式)
という流れで変換が行われています。
(さらにこの後、UCS-2→Shift_JIS変換がありますが)
そしてこの場合、UTF-8の「東京」という文字列は、バイナリとしては
DB: E6 9D B1 E4 BA AC
VB: 71 67 AC 4E
OS: 93 8C 8B 9E
のように変換される事が望まれます。
ところが今回は、90,139,113,255,160,131,108,255、すなわち、
16進数で 5A,8B,71,FF,A0,83,6C,FF というデータとして渡っています。
# これを、UCS-2として文字列化した物が「譚ア莠ャ」(ア,ャは、半角カナ) です。
この現在の状況を見ると、上記 ★ の部分が、Shift_JIS → UCS-2 変換に
なってしまっているようです。すなわち、UTF-8のバイナリが、Shift_JIS と
みなされて変換されているというわけです。
無変換ならば、まだ手の打ちようはあったのですが、間違った変換が
行われている以上、データが破損する可能性があるわけです。
そもそも、Shift_JISにはバイナリとして使える範囲が決まっています。
具体的には、
1バイト文字/制御コード: 00-1F, 20-7E, A1-DF, 7E
2バイト文字の1バイト目: 81-9F, E0-EF
2バイト文字の2バイト目: 40-7E, 80-FC
という範囲として定義されます。
今回使った『(UTF-8)東京』のバイナリは、E6 9D B1 E4 BA AC でしたが、
この場合、Shift_JIS の定義では、幸いにも
[E6 9D] [B1] [E4 BA] [AC]
という並びで処理され、データの欠損はありませんでした。
具体的には、Chr(&HE69D) & Chr(&HB1) & Chr(&HE4BA) & Chr(&HAC) の文字列
すなわち『(Shift_JIS)譚ア莠ャ』のデータとして処理され、さらにそれが
Unicode変換され、『(UCS-2)譚ア莠ャ』の5A,8B,71,FF,A0,83,6C,FF として
VB に渡されているのが、現在の状況です。
しかし、これが「東京」以外の文字だったらどうなるでしょう。
たとえば、DB側が『(UTF-8)β版』という文字列だったとしましょう。
この場合のバイナリは、CE B2 E7 89 88 の 「5バイト」で表されます。
そしてこれを Shift_JIS と誤認して変換した場合、
[CE] [B2] [E7 89] [破損]
となってしまいます。
最後の 88 は、全角文字の2バイト目となるべきデータなので、
S = Chr(&HCE) & Chr(&HB2) & Chr(&HE789) & Chr(&H88)
の変換で、「最後の文字が破損」してしまい、正しく文字列化できません。
すなわち、『(Shift_JIS)ホイ迚?』(ホ,イは半角カナ、?は不定値)となります。
しかも今回は、さらに Unicode 変換までされてから VB に渡るのですから、
最終的には『(UCS-2)ホイ迚?』の 8E FF 72 FF DA 8F ?? ?? となります。
すでに破損してしまった ?? ?? の部分は、もはや復元不可能です。
もし、残っている 8E FF 72 FF DA 8F の部分だけ UTF-8 に戻したとしても、
最終的に生き残るのは、CE B2 E7 89 という「4 バイト」のバイナリだけですし、
その4バイトを UTF-8 の文字列に戻そうとしても、完全に戻るのは
最初の2バイト『β』だけです。これではデータベースとしては致命的です。
もし、欠損の可能性が無い範囲の文字しか使われていなかったとしても、
データの格納時には、この逆の変換作業を行わなければなりませんよね。
この時も、同様の理由でデータの破損が起こりえますので、利用できる文字は
さらに限定されてしまいます。なので、化けた後に対処するのは無意味でしょうね。
詳しいコメントありがとうございました。
おっしゃっている内容は理解できました。
一点確認したいことがあります。
>UTF-8のバイナリが、Shift_JIS とみなされて変換されているというわけです。
これを直すには、ADOのプロパティ設定等ではなく、
Sybase側(使用しているDSNも含めて?)の設定変更が
必要ということですか?
> これを直すには、ADOのプロパティ設定等ではなく、
> Sybase側(使用しているDSNも含めて?)の設定変更が
> 必要ということですか?
わかりません。繰り返しになってしまいますが、私自身は、
今回の場合の具体的な対処方法を知らないのです。
# 実行環境のコードページに依存しているのか、DSN設定やOleDbの
# 動的プロパティで指定できるのか、Sybase側の設定変更が必要なのか、
# それとも、接続後に何かコマンドを投げる必要があるのか……?
Sybaseに詳しい人のレスを待つか、あるいは別のコミュニティや専門家に
質問される事をお奨めします。(もはやVBとは関係無さそうですし)
初めて質問します。私もかすとまいずさんと同じような課題で悩んでおります。
私の場合はデータベースがMySQLでEUCで書き込まれた文字列フィールドをやはり
ADOでレコードセットを取得し、SJISに変換して別のテーブルのフィールドに書き込むという処理です。
やはり文字化けしてしまい変換できません。adodb.streamも試してみたのですが
思うような結果得られません。アドバイスいただければ幸いです。
解決方法(?)
初めまして。
昨日から、私もかすとまいずさんと同様の症状になり困ることになりました。
インターネットで調べているうちにこのページを見つけたのですが、
もう解決されたでしょうか?
私の方で試行錯誤しているうちに解決できたので紹介します。
sybaseに接続するときに、データソースネーム(dsn)やユーザーID(uid)、
パスワード(pwd)なんかを指定すると思いますが、
そこに文字コード・キャラクターセット(cs)を指定できるようです。
で、"cs=sjis"と書いてやれば綺麗に表示されました。
かすとまいずさんの例だと、
cnnRead.Open "dsn=XXXXX;uid=AAAAA;pwd=BBBBB;cd=jjis"
でしょうか。
(ちなみにUTF-8の場合は、"UTF8"と書いてください。
ハイフンを入れるとエラーになります。)
また、(Windowsの)管理ツール→データソース(ODBC) からでも
sybaseODBCドライバの設定ができ、
CharactorSetという項目があるのでそこに"sjis"と入力しても
良いと思います。
開発環境は、
・データベース:sybase
・言語:ASP(VBScript、非.NET)
・サーバ:Windows2000 Server(かな?)
・クライアント:Windows2000
症状、試行結果
・sybaseから取得した日本語の値をHTMLに書き出して
ブラウザで表示すると文字化けする。
・書き出されたHTMLのソースコードを見ても化けている。
・ACCESSからリンクテーブルでテーブルの
内容を見ると文字化けずに見える。
・ブラウザのエンコードをUnicode(UTF-8)にすると、
完全ではないが日本語が表示されるようになる。
しかしブラウザ上で、他の正常な日本語が化ける。
・BASP21のkconv(文字コード変換関数)を使っても
おかしな表記になる。
・aspコード内で、"<%@ CODEPAGE= 932 %>" や、
"SESSION.CODEPAGE=932"(日本語使用設定)
を記述しても文字化けしたまま。
こんなところでしょうか。
参考にしていただければ幸いです。(^^;
※訂正です。
↑の14行目あたり、
「cnnRead.Open "dsn=XXXXX;uid=AAAAA;pwd=BBBBB;cs=jjis"」
の、"cd"の設定が"jjis"になってしまってます。
正しくは、
「cnnRead.Open "dsn=XXXXX;uid=AAAAA;pwd=BBBBB;cs=sjis"」
です。
失礼しました。(^^;;
ツイート | ![]() |