ADOで取得した結果が文字化けする


かすとまいず  2005-06-03 01:07:30  No: 122175

はじめまして

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で扱っているあたりが、怪しいと思いますが、
全くわかりません。

教えていただけないでしょうか。
宜しくお願い致します。


もげ  2005-06-03 17:16:52  No: 122176

>cnnRead.Open "dsn=XXXXX;uid=AAAAA;pwd=BBBBB"
ということなら、コード変換はODBCドライバが行っているのでは?
ODBCドライバSybaseとネイティヴ接続できるOLEDBプロバイダがあるのかどうか?
を確認するのと、
文字化けの内容というか傾向というか、
「本来どういうコードでくることが期待されていて、
実際どういうコードかきている」
のかが明確になれば、自ずと解決が見えてくるはずです。


もげ  2005-06-03 17:18:14  No: 122177

>ODBCドライバSybaseとネイティヴ接続できるOLEDBプロバイダがあるのかどうか?

訂正。

ODBCドライバ経由じゃなくて、
その代わりに、Sybaseとネイティヴ接続できるOLEDBプロバイダがあるのかどうか?
それがあるなら、そっちを試してみるとか。


かすと  2005-06-03 23:00:41  No: 122178

>ODBCドライバ経由じゃなくて、
その代わりに、Sybaseとネイティヴ接続できるOLEDBプロバイダがあるのかどうか?

ご回答ありがとうございます。

上記内容(OLEDBプロバイダの有無)はどのように確認すればよろしいのでしょうか?

またSybaseのDBテーブルに対して、ACCESSからリンクテーブルでテーブルの
内容を見ると、文字化けずに見えます。


魔界の仮面弁士  2005-06-04 00:40:06  No: 122179

> 上記内容(OLEDBプロバイダの有無)はどのように確認すればよろしいのでしょうか?
このあたりを見てみるとか。
http://www.carlprothman.net/Default.aspx?tabid=81

で、当方の場合だと、DataDirectのConnect製品を使う事も多いです。
http://www.datadirect.co.jp/products/index.asp

# もっとも、Sybase自体は利用経験が無いので、
# お力にはなれそうに無いですが……。


もげ  2005-06-04 15:46:49  No: 122180

>またSybaseのDBテーブルに対して、ACCESSからリンクテーブルでテーブルの
>内容を見ると、文字化けずに見えます。

であれば、そのリンクテーブル(MDB)をVBから読めば化けないかもです。
この場合Jetが文字コード変換している可能性がありますね。

#いや、私もそのSybaseの経験は薄くて環境もないですが。


かすとまいず  2005-06-06 22:21:48  No: 122181

回答ありがとうございます。

Sybase側のテーブルによってはINDEXが多くてACCESS側にリンクテーブルを
作成できないテーブルがあります。(ACCESSの制限)
またSybaseのINDEXを削除してINDEXを減らすことはしない方法が
必要です。


ななし  2005-06-07 01:15:44  No: 122182

ASA リファレンス・マニュアルの
 -ct コマンド・ライン・オプション
かな?(使ったことありませんけど)

Sybase使ってますけど、普通に化けたことがないので
原因は分かりません。掲示のプログラムも正しく日本語取得できました。

ただ文字セットはセットアップ時のデフォルトで使っていますので
Microsoft CP932 = Win31J-DBCS でした。
もしかしてDBファイルはどこかから提供されたのですか?

#UTF8と分かっているなら自前で変換(VB側で)もありかもです。


かすとまいず  2005-06-07 03:46:46  No: 122183

>もしかしてDBファイルはどこかから提供されたのですか?
そうなんです。
それで文字コードがUTF-8で格納されているらしいです。

>#UTF8と分かっているなら自前で変換(VB側で)もありかもです。
変換方法がわかりません。
色々StrConv等を使ってためしました。


ななし  2005-06-07 05:33:03  No: 122184

なるほど

とりあえずこんなのとか
文字列を 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
などでしょうか。(むずかしそう。。)


通ってみた  2005-06-07 23:45:51  No: 122185

面倒クサイようなら「エンコード  DLL」で検索してみるといいかもしれない


かすとまいず  2005-06-08 00:20:58  No: 122186

>文字列を UTF-8 に変換>http://www.geocities.co.jp/SilkRoad/4511/vb/utf8.htm
>またはMultiByteToWideChar APIを使った方法などが
>あるようです。

上記サイトの内容は以前に利用して試して見ました。
結果はNGでした。

こうなるとDBがおかしいのでしょうか?


Dental  2005-06-08 00:37:21  No: 122187

>> #UTF8と分かっているなら自前で変換(VB側で)もありかもです。
> 変換方法がわかりません。
> 色々StrConv等を使ってためしました。

急にStrConvという話が出てきた理由は不明ですが、それはさておき。

そもそも、結果が UTF-8 で受け取られているのかどうかは確認されましたか?
Sybase側が UTF-8 であり、結果が文字化けしているという話はでてきていますが、
文字化けした結果が、具体的にどのように化けているのかと言う話が無いようで。

ADOから返されるデータが、「UTF-8形式のバイナリ」になっているならば、
それを VBで読める形式(UCS-2 または Shift_JIS)に置き換えるのは
さほど難しい作業では無いと思います。
文字コードの変換ならば、過去ログにも幾つかサンプルがありますから。

でも、受け取った時のデータの内容が、Shift_JIS でも UCS-2 でも UTF-8 でも
無いのだとしたら……それは既にデータが破損している状態なのでしょう。
この場合、化けた結果を復元するのは、ほぼ無理でしょうから、化ける原因を
絶つ方向で調査しないと、問題は解決しないのではないでしょうか。


もげ  2005-06-08 01:23:49  No: 122188

最初に書いたのですが、

>文字化けの内容というか傾向というか、
>「本来どういうコードでくることが期待されていて、
>実際どういうコードかきている」
>のかが明確になれば、自ずと解決が見えてくるはずです。

どういうデータがきているのか確認せずにやみくもにStrConvを使ってもダメでしょう。

そもそも、その辺は本来、ODBCドライバの仕事なので、
無理にVBプログラムでドライバの尻ぬぐいを試みるより、
正しい文字を返す環境を手に入れるほうが賢明かもと思うのです。


かすとまいず  2005-06-08 01:50:18  No: 122189

>文字化けした結果が、具体的にどのように化けているのかと言う話が無いようで。
以下の通りです。
例)"東京"→"譚ア莠ャ"に化けています。


魔界の仮面弁士  2005-06-08 02:36:55  No: 122190

> 例)"東京"→"譚ア莠ャ"に化けています。

データが化ける、という点について話をしていますので、
文字列としてだけではなく、バイナリ形式として
どのように化けているのかまで、突っ込んで調べてみてください。

たとえば、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"


魔界の仮面弁士  2005-06-08 02:46:23  No: 122191

> 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


もげ  2005-06-08 03:52:46  No: 122192

譚ア莠ヤ(全角カナは実際は半角カナ)
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


かすとまいず  2005-06-13 20:19:19  No: 122193

Dim bTest() As Byte

bTest = vTemp

上記でbTestに格納した後、確認してみると以下のような結果でした。
90
139
113
255
160
131
108
255

>しかし、5A 8B 71 FF A0 83 6C などとして送られてきているのであれば、
>既にデータが破損していますので、完全には復元できません。
上記の記述によれば、データ破損しているということなのでしょうか?


魔界の仮面弁士  2005-06-14 00:22:49  No: 122194

>>既にデータが破損していますので、完全には復元できません。
> 上記の記述によれば、データ破損しているということなのでしょうか?

今回のデータについては、化けてはいますが、破損はしていません。
ですが、元データによっては、「破損する可能性がある」という事です。

私は、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バイト『β』だけです。これではデータベースとしては致命的です。

もし、欠損の可能性が無い範囲の文字しか使われていなかったとしても、
データの格納時には、この逆の変換作業を行わなければなりませんよね。

この時も、同様の理由でデータの破損が起こりえますので、利用できる文字は
さらに限定されてしまいます。なので、化けた後に対処するのは無意味でしょうね。


かすとまいず  2005-06-14 01:06:08  No: 122195

詳しいコメントありがとうございました。
おっしゃっている内容は理解できました。
一点確認したいことがあります。
>UTF-8のバイナリが、Shift_JIS とみなされて変換されているというわけです。
これを直すには、ADOのプロパティ設定等ではなく、
Sybase側(使用しているDSNも含めて?)の設定変更が
必要ということですか?


魔界の仮面弁士  2005-06-14 01:32:21  No: 122196

> これを直すには、ADOのプロパティ設定等ではなく、
> Sybase側(使用しているDSNも含めて?)の設定変更が
> 必要ということですか?

わかりません。繰り返しになってしまいますが、私自身は、
今回の場合の具体的な対処方法を知らないのです。

# 実行環境のコードページに依存しているのか、DSN設定やOleDbの
# 動的プロパティで指定できるのか、Sybase側の設定変更が必要なのか、
# それとも、接続後に何かコマンドを投げる必要があるのか……?

Sybaseに詳しい人のレスを待つか、あるいは別のコミュニティや専門家に
質問される事をお奨めします。(もはやVBとは関係無さそうですし)


あど  2006-06-24 19:44:52  No: 122197

初めて質問します。私もかすとまいずさんと同じような課題で悩んでおります。
私の場合はデータベースがMySQLでEUCで書き込まれた文字列フィールドをやはり
ADOでレコードセットを取得し、SJISに変換して別のテーブルのフィールドに書き込むという処理です。
やはり文字化けしてしまい変換できません。adodb.streamも試してみたのですが
思うような結果得られません。アドバイスいただければ幸いです。


at  URL  2006-12-01 08:01:06  No: 122198

解決方法(?)

初めまして。
昨日から、私もかすとまいずさんと同様の症状になり困ることになりました。
インターネットで調べているうちにこのページを見つけたのですが、
もう解決されたでしょうか?
私の方で試行錯誤しているうちに解決できたので紹介します。

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"(日本語使用設定)
を記述しても文字化けしたまま。

こんなところでしょうか。
参考にしていただければ幸いです。(^^;


at  2006-12-01 08:10:33  No: 122199

※訂正です。

↑の14行目あたり、
「cnnRead.Open "dsn=XXXXX;uid=AAAAA;pwd=BBBBB;cs=jjis"」
の、"cd"の設定が"jjis"になってしまってます。

正しくは、
「cnnRead.Open "dsn=XXXXX;uid=AAAAA;pwd=BBBBB;cs=sjis"」
です。

失礼しました。(^^;;


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加