oracleの「〜」を文字化けせずに取得するには?

解決


ちゃか  2008-04-03 05:38:22  No: 30389

いつもお世話になっております。
ちゃかです。
環境は以下の通りです。

・Windows Vista Bussiness
・Delphi 7 Professinal
・Oracle 10g

早速ですが、質問です。

以下のようにADOQueryを使用し、oracleに接続し、文字列を取得しようと思っています。
しかし、「〜」が「?」となって文字化けしてしまいます。
解決方法を探していたのですが、どうやらOracle の UNICODE のコードマッピングが原因なようです。
(引用元:http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=071738
しかし、オラクルの設定をキャラセットを「Windows-31J」等に変更すれば解決するらしいのですが
環境を変えるのはこちらの都合で申し訳ないのですが不可能なのです(すいません・・・)。

ネット上にある文字列変換関数ユニットを使用してみたのですがどうもうまくいきません。
(SJIStoUTF,SJIStoUTFN,UTFtoSJIS,UTFNtoSJIS,JisToSJis,SJisToJis,HanToZen,
  HanToZen2,UTFtoSJIS,UTFNtoSJIS,Utf8Decode,Utf8Encode等々・・・)

VBでは
VBのReplace関数を使用した「〜」文字化け対策の例】
strSHONIN_NAME = Replace("" & OraDynaset("SHONIN_NAME"), ChrW(12316), "〜", 1, -1, vbTextCompare)
と簡単に変換できるようなのですが、Delphiでは不可能なのでしょうか?

皆様のお力をお借りしたいです。
多くの方がこの問題にて躓いてるみたいなので既出だと思います。
自分の情報収集能力の無さに愕然としながら恥を忍んで質問させていただきました。
どうかよろしくお願い致します。

//-----------------------------------------
//以下ソース
//-----------------------------------------
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('select * from test');
ADOQuery1.Open;

while ADOQuery1.Eof = False do
begin
  showmessage(ADOQuery1.FieldByName('text').AsString);
  ADOQuery1.Next;
end;

ADOQuery1.Close;

結果:DB上「あいう」  →「あいう」
    :    「え〜お」  →「え?お」


DEKO  2008-04-03 08:08:34  No: 30390

所謂"波ダッシュ(WAVE DASH)問題"ですね。
http://ja.wikipedia.org/wiki/%E6%B3%A2%E3%83%80%E3%83%83%E3%82%B7%E3%83%A5#Unicode.E3.81.AB.E9.96.A2.E9.80.A3.E3.81.99.E3.82.8B.E5.95.8F.E9.A1.8C

>Delphiでは不可能なのでしょうか?
Delphiでも2007とかだとAsWideStringが使えるので、
#$301C(波ダッシュ:WAVE DASH)と#$FF5E(全角チルダ:FULLWIDTH TILDE)を
変換(VBの例のように)するだけでいいと思われるのですが、
残念ながらDelphi7にはAsWideStringがありません。

試せる環境がないので推測ですが、

1.WideStringの変数(Wとする)を用意。
2.そこへAsVariantで取得した値を代入。
  W := ADOQuery1.FieldByName('text').AsVariant;
3.#$301Cを#$FF5Eへ置換。
4.(Ansi)String型の変数(Aとする)へWideStringの変数を代入。
  A := W;

これでうまくいくかもしれません。


ちゃか  2008-04-03 23:53:46  No: 30391

DEKO様
いつもお世話になっております。
ちゃかです。

お返事ありがとうございます。
「〜」文字はうまく取れるようになりました。
しかし、「?」文字も「〜」に変換されてしまいました。
これは変換方法がまずいのでしょうか?

いろいろ考えてみたのですが以下の結果から
Oracleの「〜」と「?」は「#$301C」ということなのでしょうか・・?
「?」は「#$FF1F」だと思ったのですが・・・。

(*
引用元:http://ash.jp/code/unitbl21.htm

区 点 JIS  SJIS EUC  UTF-8  UTF-16 字
01 33 2141 8160 A1C1 E3809C 301C   〜
01 09 2129 8148 A1A9 EFBC9F FF1F   ?
*)

理解できないことばかりでうまく説明できていませんが、
引き続き皆様よろしくお願い致します。

//-----------------------------------------
//以下ソース
//-----------------------------------------
var
  WS : WideString;
  AS : AnsiString;

begin

  ADOQuery1.SQL.Clear;
  ADOQuery1.SQL.Add('select * from test');
  ADOQuery1.Open;

  while ADOQuery1.Eof = False do
  begin

    WS := ADOQuery1.fieldByName('test').AsVariant;
    AS := StringReplace(wk_WS,#$301C,#$FF5E,[rfReplaceAll]);
    
    showmessage(ADOQuery1.FieldByName('text').AsString);
    ADOQuery1.Next;
  end;

  ADOQuery1.Close;

end;

結果:DB上 ⇒ ShowMessage
  ・「あいう」⇒「あいう」
  ・「あ〜う」⇒「あ〜う」
  ・「あ?う」 ⇒「あ〜う」
  ・「? / 〜」⇒「〜 / 〜」
  ・「〜 / ?」⇒「〜 / 〜」


DEKO  2008-04-04 00:20:51  No: 30392

StringReplaceはWideStringに対応していません。

# WideStringを突っ込むと暗黙的にAnsi変換が行われて
# 処理されるので、すべての?が〜に変換されてしまいます。

WideStringをforで回すなりして自前で置換する必要があります。

var
  i:Integer;  
  A: String;
  WS: WideString;
begin
  WS := (処理);
  for i:=1 to Length(WS) do
    if WS[i] = #$301C then
      WS[i] := #$FF5E;
  A := WS;

こんな感じです。

>Oracleの「〜」と「?」は「#$301C」ということなのでしょうか・・?
>「?」は「#$FF1F」だと思ったのですが・・・。

SHIFT-JISの"〜"は波ダッシュ(8160:#$301C)です。
しかし、Windowsはこれを全角チルダ(#$FF5E)に割り当てています。
UnicodeからSHIFT-JISへ変換しようとすると#$FF5Eに相当するJIS文字がないため、
変換できなかった文字の代替文字として設定されている"?(#$FF1F)"が表示されてしまうという事です。


もにゃ  2008-04-04 00:34:57  No: 30393

横から失礼
環境はVistaみたいですし、
今回の場合は
WS:WideString;
WS := ADOQuery1.fieldByName('test').AsVariant;
showmessage(WS);
でいいと思います。
Oracle,WindowsのどちらでSHIFT-JIS変換するかの問題のように思えます。


もにゃ  2008-04-04 00:39:51  No: 30394

あー失礼しました。
だめなんですね。
知らないことには顔を出してはいかんですな;;
すみません


DEKO  2008-04-04 01:04:32  No: 30395

Oracleに格納されているコードが(多分)波ダッシュ(8160:#$301C)なのです。
# Unicodeで格納されているのでしょう。

これをString(AsString)で取り出そうとすると、WindowsのUnicode変換処理が行われます。
Windowsは"〜=全角チルダ(#$FF5E)"という認識ですから、
#$301Cが変換できずに代替文字である"?"が表示されてしまいます。

# 上の書き方は紛らわしかったですね、スミマセン。

var
  A: String;
  W: WideString;
begin
  W := #$301C;
  A := W;

WをTextOutW等で直接描画すれば波ダッシュが描画されますが、
Aを表示させると"?"になってしまいます。


ちゃか  2008-04-04 02:33:42  No: 30396

DEKO様
もにゃ様

いつもお世話になっております。
ちゃかです。

まずは無事正常動作しました事をご報告致します。

>>DEKO様
参考ページやソースまでコーディングしていただきありがとうございました。
UNICODEの解説も詳しくしていただき感謝しています。

>>もにゃ様
アドバイスありがとうございます。
知らないことでもそこから切り口が見つかる事も多くあると思いますので
またアドバイスをお願い致します。

今後の同一の問題の為にソース等を残しておきます。
皆様本当にありがとうございました。
またよろしくお願い致します。

管理人様貴重なスペースありがとうございました。

//--------------------------------------------------------
//以下問題解決ソース
//--------------------------------------------------------

(*  環境
      ・Windows Vista Bussiness
      ・Delphi 7 Professinal
      ・Oracle 10g
*)

{ 関数宣言 }
//「〜」文字変換関数  (「#$301C」 → 「#$FF5E」)
function F_WaveDashReplace(WS : WideString): String;

{ 関数処理 }
//=================================================
// 「〜」文字置換処理
//=================================================
function TForm1.F_WaveDashReplace(WS : WideString): String;
var
  i : Integer;
begin

  for i := 1 to Length(WS) do
  begin
    if WS[i] = #$301C then
    begin
      WS[i] := #$FF5E;
    end;

  end;

  result := WS;
end;

//-----------------------------------------
// メイン処理
//-----------------------------------------

  ADOQuery1.SQL.Clear;
  ADOQuery1.SQL.Add('select * from test');
  ADOQuery1.Open;

  while ADOQuery1.Eof = False do
  begin
  //showmessage(ADOQuery1.FieldByName('text').AsString);   ← このままでは「〜」文字が「?」に文字化け

    showmessage(F_WaveDashReplace(ADOQuery1.fieldByName('text').AsVariant))
    ADOQuery1.Next;
  end;

  ADOQuery1.Close;

end;

結果:DB上 ⇒ ShowMessage
  ・「あいう」⇒「あいう」
  ・「あ〜う」⇒「あ〜う」
  ・「あ?う」 ⇒「あ?う」
  ・「? / 〜」⇒「? / 〜」
  ・「〜 / ?」⇒「〜 / ?」


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

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






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