[delphi-users:3054] MIME BASE64 XE環境でUNICODE変換で互換漢字の対応方法を教えてください

362 views
Skip to first unread message

おんそく

unread,
Mar 12, 2013, 3:04:13 AM3/12/13
to delphi...@freeml.com
皆様初めまして。

DELPHI XE+INDY10でメールを受信するアプリを作成したところ、どうして解決できないことが発生してしまいました。

漢字の?という文字が・になってしまうんです。
ググったところ、デブキャンの資料
http://edn.embarcadero.com/article/images/40483/devcamp_encore_20100415_Seminar.pdf
これでは、互換漢字ということになっていました。

DELPHI 2005+jconvert+INDYでは、きちんと表示ができたの、
なんとか、XEでもと思い、いろいろ調べてみました。

実際には
=?iso-2022-jp?B?GyRCOzN5dTlieXU1XHl1GyhC?=
この文字列をMIME BASE64でデコードして、XEなのでUNICODEにできればいいのだと思い

IdCoderHeaderにあるDecodeHeaderを使ってみました
結果は「山?高?宮?」
となりました。

DELPHI2005ではjconvertを使って
jis2sjis(DecodeHeaderString( MIME文字 ))と実行すると
結果は「山?高?宮?」
となりました。

なんとか、XEでもこのように結果を出したいのですが、どうすればいいか教えてください
よろしくお願いします。

かわむら(@会社)



MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
メンバーで使える掲示板を活用しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=jA75i
------------------------------------------------------[freeml byGMO]--

おんそく

unread,
Mar 12, 2013, 3:08:59 AM3/12/13
to delphi...@freeml.com
すいません、どうやら肝心の漢字が表示されないようです。
WEBからの投稿では、表示されていたのですが、
?になっている表示したい漢字は崎の大の字が立となっている漢字です


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
メールだけでみんなを招待できる便利機能♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=jA79a
------------------------------------------------------[freeml byGMO]--

DEKO

unread,
Mar 12, 2013, 4:33:26 AM3/12/13
to delphi...@freeml.com
こんにちは。

そもそも iso-2022-jp では "たちざき (機種依存文字)" を扱えません。
# 機種依存文字が含まれるメールは
# OS X や Linux、スマホのメーラーで正しく表示できるとは限りません。

[メールに使ってはいけない文字 (地球環境情報学研究室)]
http://www.is.kochi-u.ac.jp/sango/Members/tkikuchi/courses/se2007/x.html

"たちざき" は U+E1CC という PUA エリア (U+E000~U+F8FF) のコードポイントへ
アサインされてしまうようです。よって、これを StringReplace() 等で
U+FA11 に変換してやれば一応は解決すると思います。

ただ、
「"たちざき" 以外の機種依存文字も U+E1CC という同一コードポイントへアサインされるのではないか?」
「他にも、○囲み数字等の機種依存文字が PUA へアサインされるのではないか?」
という懸念はあります。

MIME BASE64 のデコードを自前で行い、
iso-2022-jp の変換に CP51932 を使えば機種依存文字の変換はうまくいくと思います。

--
by DEKO
-----------------------------
http://ht-deko.minim.ne.jp/
de...@ht-deko.minim.ne.jp
-----------------------------


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
練習や試合の予定調整は「とっとと決め太郎」におまかせ!
http://ad.freeml.com/cgi-bin/sa.cgi?id=jA8HW
------------------------------------------------------[freeml byGMO]--

DEKO

unread,
Mar 12, 2013, 5:39:16 AM3/12/13
to delphi...@freeml.com
> iso-2022-jp の変換に CP51932 を使えば機種依存文字の変換はうまくいくと思います。
何を寝惚けているんでしょうね。CP51932 ではなく CP50220 です。

uses
 ..., EncdDecd, SkRegularExpressions; // XE では RegularExpressions を使用するとエラーになります

procedure TForm1.Button1Click(Sender: TObject);
const
 Exp = '=\?(?<ENCODING>.+)\?(?<BASE64STR>.+)=';
var
 Buf: TBytes;
 Match: TMatch;
 sHeader, sEncName, sBASE64: string;
 Enc: TEncoding;
begin
 // Edit1 にある MIME BASE64 文字列を変換し、Edit2 に表示
 sHeader := Edit1.Text;
 Match := TRegEx.Match(sHeader, Exp);
 if not Match.Success then
  Exit;
 sEncName := Match.Groups.Item['ENCODING' ].Value;
 sBASE64 := Match.Groups.Item['BASE64STR'].Value;
 Buf := DecodeBASE64(sBASE64);
 Enc := TEnCoding.GetEncoding(50220);
 try
  Edit2.Text := Enc.GetString(Buf);
// Edit2.Text := StringReplace(Edit2.Text, #$E1CC, #$FA11, [rfReplaceAll]);
 finally
  Enc.Free;
 end;
end;

EncdDecd の DecodeBASE64 を使ってみましたが、結果は同じでした。

--
by DEKO
-----------------------------
http://ht-deko.minim.ne.jp/
de...@ht-deko.minim.ne.jp
-----------------------------


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
毎日豪華プレゼントキャンペーン開催中!くまポン
http://ad.freeml.com/cgi-bin/sa.cgi?id=jA9JU
------------------------------------------------------[freeml byGMO]--

DEKO

unread,
Mar 12, 2013, 6:33:37 AM3/12/13
to delphi...@freeml.com
XE 以降なら GetEncoding() に EncodingName が使えるのでしたね。

uses
 ..., EncdDecd, SkRegularExpressions; // XE では RegularExpressions を使用するとエラーになります

procedure TForm1.Button1Click(Sender: TObject);
const
 Exp = '=\?(?<ENCODING>.+)\?(?<QUOT>.+)\?(?<BASE64STR>.+)=';
var
 Buf: TBytes;
 Match: TMatch;
 sHeader, sEncName, sQuot, sBASE64: string;
 Enc: TEncoding;
begin
 // Edit1 にある MIME BASE64 文字列を変換し、Edit2 に返す
 sHeader := Edit1.Text;
 Match := TRegEx.Match(sHeader, Exp);
 if not Match.Success then
  Exit;
 sEncName := Match.Groups.Item['ENCODING' ].Value;
 sQuot  := Match.Groups.Item['QUOT'   ].Value; // B(BASE64) or Q(Printed-Quotable)
 sBASE64 := Match.Groups.Item['BASE64STR'].Value;
 Buf := DecodeBASE64(sBASE64);
 Enc := TEncoding.GetEncoding(sEncName); // Encoding Name (XE or later)
 try
  Edit1.Text := Enc.GetString(Buf);
// Edit1.Text := StringReplace(Edit1.Text, #$E1CC, #$FA11, [rfReplaceAll]);
 finally
  Enc.Free;
 end;
end;

--
by DEKO
-----------------------------
http://ht-deko.minim.ne.jp/
de...@ht-deko.minim.ne.jp
-----------------------------


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
いつでもどこでもメールチェック!freemlのスマートフォンアプリ
http://ad.freeml.com/cgi-bin/sa.cgi?id=jAA9g
------------------------------------------------------[freeml byGMO]--

DEKO

unread,
Mar 12, 2013, 10:33:02 AM3/12/13
to delphi...@freeml.com
誤: Exp = '=\?(?<ENCODING>.+)\?(?<QUOT>.+)\?(?<BASE64STR>.+)=';
正: Exp = '=\?(?<ENCODING>.+)\?(?<QUOT>.+)\?(?<BASE64STR>.+)\?=';

--
by DEKO
-----------------------------
http://ht-deko.minim.ne.jp/
de...@ht-deko.minim.ne.jp
-----------------------------


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
かわいいベジモンがたくさん!自分だけの農場を作ろう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=jAEnz
------------------------------------------------------[freeml byGMO]--

おんそく

unread,
Mar 12, 2013, 9:09:20 PM3/12/13
to delphi...@freeml.com

DEKO様、解決プランとサンプルコードをありがとうございました。

このサンプルをつかって解決方法を模索しました。
$E1CCの置換は、やはりDEKO様の指摘通り他の機種依存文字が全部"たちざき"となってしまうことを考えると他に方法がないかを考えました。

DecodeBASE64からEnc.GetStringの間に、SJISに変換して"たちざき"のSJISのコードである#FAB1の文字の位置を保存して
それを使って、UNICONDEに変換後の文字で置換すれば解決でき予感がしたので、コードにしようと思ったのですが
どうやって、SJISにすればいいか分かりませんでした(涙)

MIMEの変換などでググったところ、PzConvへ辿りつきました。
内部がAnsiString化してあるとのコメントがあったので、CharをAnsiCharへ書き換えをして。XEでコンパイルできたので
さっそく
var
AnsiBuf: AnsiString;
begin
AnsiBuf := PzConv.MIMEHeaderDecode( '=?iso-2022-jp?B?GyRCOzN5dTlieXU1XHl1GyhC?=' );
Edit2.Text := AnsiToUTF16( AnsiBuf );
end;
として、とりあえず、コード変換後を確認して、Posとか組もうとおもっていたら
なぜか、Edit2に"たちざき"が表示されました。??

双方の違いを見ると、結局BASE64のデコード後にjis2sjisがあるかないかだったんですが
果たして結果オーライなのか、
試しに
for i := 0 to Length(Edit2.Text) do begin
Memo1.Lines.Add( IntToHex(Ord(Edit2.Text[i]),2) );
end;
こんなことをして、本当にUNICODEで表示されているの確認したら、UNICODEでした。

この検証を踏まえた結果から考察すると、MECSUtilsを使ってサンプルを変更して
AAnsiBuf: ByteString;
DAnsiBuf: ByteString;

  Buf := DecodeBASE64(sBASE64);
AAnsiBuf := MecsAnsiStringOf( BUF );
ConvertString( 50220,932,AAnsiBuf,DAnsiBuf);
Edit2.Text := AnsiToUTF16( DAnsiBuf );
これで、求めていた結果になるのですが、この方法は正しいのでしょうか?
ただし、iso-2022-jpの場合限定だと思いますが。

かわむら(@会社)



MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
アイテムたくさん☆freemlのプロフィール画像をアバターに♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=jAIkp
------------------------------------------------------[freeml byGMO]--

DEKO

unread,
Mar 13, 2013, 4:01:09 AM3/13/13
to delphi...@freeml.com
こんにちは。

> この検証を踏まえた結果から考察すると、MECSUtilsを使ってサンプルを変更して
> AAnsiBuf: ByteString;
> DAnsiBuf: ByteString;
>
>   Buf := DecodeBASE64(sBASE64);
> AAnsiBuf := MecsAnsiStringOf( BUF );
> ConvertString( 50220,932,AAnsiBuf,DAnsiBuf);
> Edit2.Text := AnsiToUTF16( DAnsiBuf );
> これで、求めていた結果になるのですが、この方法は正しいのでしょうか?
> ただし、iso-2022-jpの場合限定だと思いますが。

恐らくそれでいいのだと思います。
デブキャン資料にも書いた "マッピングの問題" な気がしてきました。

ISO-2022-JP -> Unicode では正しく機種依存文字がマッピングされませんが、
Shift_JIS -> Unicode では正しくマッピングされます。

検証された結果からすると、CP50220 (ISO-2022-JP) -> CP932 (Shift_JIS) も
正しくマッピングされるのでしょう (同じ JIS X 0208 ベースですし)。

UnicodeString を介さず、
バイトバッファ(ISO-2022-JP) -> バイトバッファ(Shift_JIS) -> Unicode (UnicodeString)
と変換するしかないのでしょうね...勉強になりました m(_ _)m

....

totonica さんの CP51932Encoding (http://www.watercolor-city.net/oldblog/blog/log/eid1221.html) を
ベースにして、TIso2022jpEncoding を作ってみました。

[Iso2022jpEncoding]
http://ht-deko.minim.ne.jp/software/uIso2022jpEncoding.zip

これを使うと、以下のように MECSUtils なしでスッキリ書けます。

uses
 ..., EncdDecd, SkRegularExpressions, uIso2022jpEncoding;

procedure TForm1.Button1Click(Sender: TObject);
const
 Exp = '=\?(?<ENCODING>.+)\?(?<QUOT>.+)\?(?<BASE64STR>.+)\?=';
var
 Buf: TBytes;
 Match: TMatch;
 sHeader, sEncName, sQuot, sBASE64: string;
begin
 // Edit1 にある MIME BASE64 文字列を変換し、Edit2 に返す
 sHeader := Edit1.Text;
 Match := TRegEx.Match(sHeader, Exp);
 if not Match.Success then
  Exit;
 sEncName := Match.Groups.Item['ENCODING' ].Value;
 sQuot  := Match.Groups.Item['QUOT'   ].Value; // B(BASE64) or Q(Printed-Quotable)
 sBASE64 := Match.Groups.Item['BASE64STR'].Value;
 Buf := DecodeBASE64(sBASE64);
 with TIso2022jpEncoding.Create do
  begin
   Edit2.Text := GetString(Buf);
   Free;
  end;
end;

--
by DEKO
-----------------------------
http://ht-deko.minim.ne.jp/
de...@ht-deko.minim.ne.jp
-----------------------------


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
ランキングを作るだけでお小遣いがもらえる!
http://ad.freeml.com/cgi-bin/sa.cgi?id=jANRi
------------------------------------------------------[freeml byGMO]--

おんそく

unread,
Mar 14, 2013, 2:08:17 AM3/14/13
to delphi...@freeml.com
お世話になります。

DEKO様、いろいろありがとうございました。
作成していただいたクラスを使って、理想的な結果を得ることができました。
感謝感激です。

かわむら(@会社)



MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
あなたの知っている順位やこだわりを表現しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=jBcCy
------------------------------------------------------[freeml byGMO]--

Reply all
Reply to author
Forward
0 new messages