IEのドイツ語など特殊文字(ウムラウトなど)をshift-jisに変換してeditやricheditに貼りつけたいのですが、単にPasteFromClipboardでは、ウムラウトが取れた状態になっています。unicodeからshift-jisに変換し、pasteする方法を教えてください。
▲äë
http://forum.nifty.com/fdelphi/samples/01515.html
>>▲
実際やってみると色々問題があることが分かるはずですが、
単にリンク貼るだけはちょっと答える側として不親切な気がします。
「これをやってみたらどうでしょうか?」というのと
「これをやればできます」なのかが分かりませんし。
単にgoogle検索に掛けただけのように取られても仕方ありません。
で私なりに色々やった結果ですが、Delphi付属のRichEditからは難しいです。
ですが「JVCL」プロジェクトの「JvRichEdit」や
VCLのUnicode化で有名な「TntRichEdit」がオープンソースでUnicodeに対応しているのでそのまま使えます。
ちなみに「JvRichEdit」はOLEにも対応しています(画像も貼れる)
Tnt Unicode Controls
http://www.tntware.com/delphicontrols/unicode/
JVCL
http://homepages.borland.com/jedi/jvcl/
procedure TForm1.Button1Click(Sender: TObject);
var
W1, W2 : WChar;
Pw1,Pw2 : WideString;
h : integer;
aCanvas : TCanvas;
begin
aCanvas := Image1.Canvas;
W1 := WChar($00AE);
W2 := WChar($8A21);
Pw1 := w1;
Pw2 := w2;
// 'MS Pゴシック'
Image1.Height := 50;
Image1.Width := 100;
aCanvas.Font.Size := 20;
aCanvas.Brush.Color := clWhite;
aCanvas.font.Name := 'Arial';
aCanvas.font.Color := clblack;
aCanvas.FillRect(Image1.ClientRect);
h := aCanvas.TextWidth(PW1) ;
if CheckBox1.Checked then
// Canvas.TextOut だとなぜか? Rとなる
begin
aCanvas.TextOut(1,1, PwideChar(Pw1));
aCanvas.font.Name := 'MS ゴシック';
aCanvas.TextOut(1+h,1, PwideChar(Pw2));
end
else
// 直接 TextOutW を呼ぶと○+Rが書き込める
begin
Windows.TextOutW(aCanvas.Handle,1,1, PwideChar(Pw1),1);
aCanvas.font.Name := 'MS ゴシック';
Windows.TextOutW(aCanvas.Handle,1+h,1, PwideChar(pw2),1);
end;
end;
実行時、直接手でコピペすればTRichEditには、ウムラウトはいる
HDD覗いたら昔Tnt Unicode Controlsしっかりダウンロードむかししてたの
忘れてた
上のTnt Unicode Controlsがいいでしょう
初心者ですのでなかなか解決のめどがたちません。
以前、いろいろな言語のファイルをネットスケープで検索して読む時、copy機能でクリップボードに調べたい単語を自作の辞書に取り込み、引いていました。その時は、特殊文字のあるほとんどのヨーロッパ言語を文字化けせずに取り込むことができました。ところが、unicode化してから特殊文字がただの文字に化けてしまって困っているのが質問のいきさつです。
まず、クリップボードに貼り付けた特殊文字を含むデーターをどう取り出せばいいのでしょうか。
>クリップボードに貼り付けた特殊文字を含むデーターをどう取り出せばいいのでしょうか。
なるへそ
uses Clipbrd;
function GetWideStrToClipboard : WideString;
var
MyHandle: THandle;
TextWPtr: PWChar; // CF_TEXT なら PChar
MyString: WideString; // ヘルプに載っていた物をPWCharに変えただけです。
begin
ClipBoard.Open;
try
if Clipboard.HasFormat(CF_UNICODETEXT) then
begin
MyHandle := Clipboard.GetAsHandle(CF_UNICODETEXT);
TextWPtr := GlobalLock(MyHandle);
MyString := WideString(TextWPtr);
GlobalUnlock(MyHandle);
end;
finally
Clipboard.Close;
end;
Result := MyString;
end;
procedure TForm1.Button1Click(Sender: TObject);
var ft : TFontname;
Ws : WideString;
begin
Ws := GetWideStrToClipboard;
Memo1.Text := Ws;
ft := Canvas.font.Name;
Canvas.font.Name := 'Arial';
Canvas.TextOut(1,20, WideCharToString(PWChar(Ws)));
Windows.TextOutW(Canvas.Handle,1,1,PWideChar(Ws) ,Length(Ws));
Canvas.font.Name := ft;
end;
{*
MemoとButtonを一個真ん中あたりに用意して実行してみてください。
wsの値を比較のため。オリジナル文字をフォームの左端に表示します
Unicodeをコピーして
実行すればわかりますが、TMemoやTEditに代入すると文字が変わります。
(勝手に変換されます)
そういうことでコンポーネントを紹介されているようです。
XPなら C:\WINDOWS\SYSTEM32\clipbrd.exe がクリップボードです。
元の文字を変数間で移動すれば問題ないと思います
*}
クリップボードからデーターを取得する件、ありがとうございました。
私の当初の目的は、Ansi形式の辞書データーとブラウザー上のファイル形式との互換性の問題で、いかにunicode形式のファイルをAnsi(S-jis)形式にして辞書の入力に取り込むかということです。
unicode>shift-Jisの変換は、今のところ少し後にさせて頂いて、EIなどのブラウザー上のファイルについて新たなる疑問が出てきましたので、別に質問いたします。
Utf8Encode 関数は,WideString 値を UTF8 文字列に変換します。
Utf8Decode 関数は,UTF8 文字列を Unicode 文字列(WideString)に変換します。
AnsiToUtf8 関数は,Ansi でエンコード化された文字列を UTF-8 に変換します。
Utf8ToUnicode 関数は,UTF-8 文字の文字列を Unicode 文字列に変換します。
Utf8ToAnsi 関数は,UTF8 文字列を Ansi 文字の文字列に変換します。
度々お世話になります。
クリップボードからウムラウト文字を呼び出し。Utf8EncodeやUtf8ToAnsi 関数で変換して、richeditに貼り付けたのですが、私の欲しい形式が得られません(例 p蒿=pの後にaのウムラウトが2つ続く。ブラウザーではpの後にaのウムラウトが2つ続く文字列です。これを p蒿 に変換したものが欲しいのです)
Unicode対応のコンポーネントをダウンロードする方が楽でいいと思いますけど。
応急処置として
同じデータ形式でコピーを作ればいいので、
IEでコピーした物を
ワードパッド
"C:\Program Files\Windows NT\Accessories\wordpad.exe"
に一度ペーストして、それを選択してコピーします。
それで Windows.SendMessage(RichEdit1.Handle,WM_PASTE,0,0);
おくればカーソル行に挿入はできます。
CD内にはいっているDelphi付属のWin32APIプログラマーレファレンス(Jphelp\API32WH.HLP)をみると
Windowsの動作が理解できるので、けっこういろいろ参考になります。
大抵のことは自己解決出来るようになります。
>(例 p蒿=p
RichEdit1.text := 'P' + Char($E4) +Char($E4);
のことですね。
文字コードとは、機械的には、一個の文字とそれに対応する数字のことです。
それを表にしたものが文字コード表です。
機械は、数字をみて、文字を表示しているだけです。
ですから、上の例で漢字が出るのは、Char($E4) +Char($E4)=蒿であって≠aウムラウトWChar($E4)+WChar($E4)ではありません。
日本のPCでウムラウトWChar($E4)+WChar($E4)が表示できるソフトは内部では1文字=2バイトや特殊記号と組み合わせなど違った状態で保存をしていると思います
シフトジスは2バイトで構成され、決められた範囲の1バイトと2バイト目にChar($E4)が該当するので、別の文字となるのです。
シフトジスでないときは、1バイトで文字が構成されるANSIとの混合文字列です。
マルチバイトという特殊な状態です
aウムラウトは、
標準で1バイトの日本語の半角カナが当たり前のように表示でき
外国のPCで表示されないのと同じようなことだと思ってください。
機械に埋め込まれたフォントの違いです。
上にもコードで例をだしているのでわかると思いますが
シフトジス文字を表す数字とコードがダブルので
ユニコード対応のコンポーネント使わない場合は
Delphiに限らず要するに自分で専用のフォントに該当する番号を送らないと表示できないってことです。
RichEdit1.text := WChar($E4);
ってしても ダメって事です、
=RichEdit1.text := Char($61); // = a
Stringに型キャストすると おせっかいで
かってに変換されます。
RichEditの内部保存領域にアクセスするには、
ストリーム操作がいり面倒なので
■●さんのリンクの紹介されているユニコード化されたTTntRichEditコンポを
インストールして使うと
WCharで文字を操作をするので、情報が失われず、表示もしてくれるので
苦労せずに済みます?。
(※使ったことがないので詳しくはしりません)
文字確認用
procedure TForm1.Button5Click(Sender: TObject);
var WS : WideString;
i : integer; s, Text : string;
begin
WS := GetWideStrFromClipboard;
Text := 'ユニコード文字(WideString)'+#13#10;
for i := 1 to Length(WS) do
Text := Text + format('%.4x ',[Word(WS[i])]);
s := WS;
Text := Text+#13#10+'stringに変換後'+#13#10;
for i := 1 to Length(S) do
Text := Text + format('%4.2x ',[Word(S[i])]);
Label1.caption := Text;
RichEdit1.text := WS;
end;
三角さんにはじめきついこと言っちゃってスミマセン。
ちと誤解してました。
で、WindowsXp,2000でUnicodeを勝手にShift-jis変換してしまう件ですが、
これは宿命です。
ウムラウトa,i,u,e,oはそもそもShift-jisでは定義されていないので、それに似た単語として、a,i,u,e,oが採択されます。(2000以前は無理やり文字化けコードを返していましたけど)
つまりプログラムで
Unicode→西ヨーロッパ文字コードセットもしくは
Shift-jis→西ヨーロッパ文字コードセットに変換しなくてはなりません。
では、Shift-jis変換は如何にして行われているかと言うと
これはどうやらIMEが行っている様です。
つまり、IMEをドイツ語に設定すれば、自動的にUnidoce→ドイツ語(西ヨーロッパ言語)になるというわけです。
西ヨーロッパ言語の文字コードについては何コードが何に相当するかは知りません。
誤>2000以前は無理やり文字化けコードを返していましたけど)
正>2000以前は無理やりその文字コードに相当するShift-jis文字を返していましたけど)
三角さんのUnicode取得ソースを使ってUnicodeと西ヨーロッパ言語の文字コードを比較して、文字コードが分かりました。
ウムラウト記号の半角は以下のソースでWindows9x系の文字が取得可能だと思います。ためしにEdit1.textをUnicode非対応アプリにコピペしたところ理想的な動作をしました。
//Unicode->西ヨーロッパ言語(英数、ウムラウトでのみ確認)
procedure TForm1.Button3Click(Sender: TObject);
var WS : WideString;
text:string;
i:integer;
begin
WS := GetWideStrFromClipboard; //GetWideStrtoClipboard;
for i := 1 to Length(WS) do
text:= text + Char(Word(WS[i])+1);
Edit1.Text := text;
end;
誤>Shift-jis→西ヨーロッパ文字コードセットに変換しなくてはなりません。
これはできません。(表現があいまいでスミマセン)
中島さん クリップボードから直接ペースト出来ました。
はっはっはぁ(・o・) ワラってごまかす人 (‥;)
(;´_`;)ということで文字取り出しも要領は同じです。
Exがついているものを使うといいみたいです。
でも古いricheditには通用しないようなので、下記のページに
その対応ものっているようです。
function StrCopyW(Dest: PWChar; const Source: PWChar): PWChar;
var i : integer;
begin
i := -1;
Repeat
Inc(i);
Dest[i] := Source[i];
until (Word(Source[i])=0);
Result := Dest;
end;
type
TSETTEXTEX = packed record
flags : DWORD;
codepage : UINT;
end;
const
EM_SETTEXTEX = WM_USER + 97;
ST_DEFAULT = 0;
ST_KEEPUNDO = 1;
ST_SELECTION = 2;
procedure TForm1.Button2Click(Sender: TObject);
var PW : PWChar;
SETTEXTEX : TSETTEXTEX;
begin // テキスト挿入
getmem(PW,20);
SETTEXTEX.flags := ST_SELECTION;
SETTEXTEX.codepage := 1200;
StrCopyW(PW,WideString('あ')+WChar($00E4)+WideString('あ'));
Windows.SendMessageW(RichEdit1.Handle,EM_SETTEXTEX
,integer(@SETTEXTEX),integer(PW));
FreeMem(PW);
end;
procedure TForm1.BitBtn1Click(Sender: TObject);
var WS : WideString;
SETTEXTEX : TSETTEXTEX;
begin // クリップボードから挿入。
WS := GetWideStrFromClipboard;
SETTEXTEX.flags := ST_SELECTION;
SETTEXTEX.codepage := 1200;
Windows.SendMessageW(RichEdit1.Handle,EM_SETTEXTEX
,integer(@SETTEXTEX),integer(WS));
end;
// 参考
// テキストも取り出せると思います。
// あとは自分でがんばってください。
//http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/richedit/richeditcontrols.asp
//http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/richedit/richeditcontrols/richeditcontrolreference/richeditmessages/em_settextex.asp
//http://www.honet.ne.jp/~tri/program/unicows02.html
// EM_GETTEXTLENGTHEX
// EM_GETTEXTEX
// などは自分で検索エンジンで 値探してください。
// VidualStudioおもちでしたらRichedit.hから持ってくるといいです。
// 持っていないので私にはわかりません。
> text:= text + Char(Word(WS[i])+1);
Char(Word(WS[i])+1) × +1個文字コードずれます
上位バイト切り捨てなら、Char(Word(WS[i]))のままでも通ります
→ Char(WordRec(WS[i]).Lo)
or
→ Char(Word(WS[i]) and $FF);
ウムラウトのコードそのままで
Sfhit-jisとかぶるのを覚悟で
強制変換されずに
Unicodeを強引に256未満を1バイトにするなら
for i := 1 to Length(WS) do
if (Word(WS[i])<=$FF ) then
S2 := S2 + Char(Word(WS[i]))
else
S2 := S2 + WS[i];
でいいのでは?
条件の数字は、好みで変えてください。
// 2バイトならChar(WordRec(WS[i]).Hi)+Char(WordRec(WS[i]).Lo)
サイズ情報を持ったString型を使うDelphiでは関係ないですが
Char(WordRec(WS[i]).Hi)のときには注意が要ります。
PCharを使うC,C++の世界では,Char(0)は文字列の終わりをしめしますので注意して下さい。
大変お世話になりました。特に、四角丸さんの2005/01/04(火) 23:39:53のアドバイスと四角丸さん▲さんの2005/01/04(火) 22:24:15、2005/01/05(水) 10:39:57で解決しました。ありがとうございました。
ツイート | ![]() |