月別アーカイブ: 2014年7月

Programmer’s Edit Gear “Peggy”シリーズ が閉鎖されます。

開発担当も不在となり、開発中止となったPeggyシリーズですが、2014年7月31日(木)をもってダウンロードページも閉鎖するようです。

http://www.anchorsystems.jp/

Peggy に興味がない方も、MocaScriptはコマンドライン版が単体で使えるので、入手しておくと面白いかも。

http://www.anchorsystems.jp/anchor/ashp/moca/mocaindex.html
http://www.anchorsystems.jp/anchor/cgi/as_download.cgi

MocaScriptページのコマンドライン版の入門ガイドリファレンスのページをコピーしておくと、使い方も分かります。

無くなってしまうのは残念です。

 

KnjTest11.exe の結果

KnjTest11.exe の実行後、作成されたテキストファイルをメモ帳(notepad.exe)で開くと以下の様になります。
プログラムの流れと合わせて見てください。
吉の土版は、MS 明朝/MS ゴシックでは表示できません。メイリオなどフォント設定を変えて見てください。
プログラムから表示しているメッセージボックスの画像も最後に載せました。

【ANSIテキストファイル.txt】
surro004

【UNICODEテキストファイル.txt】
surro002

【UTF8テキストファイル.txt】
surro003

【メッセージボックス】
surro005

Free Pascal 2.x で日本語処理(5)

今回は、ユニコードのサロゲートペアについて投稿します。

FreePascal(Lazarus)やC#, Delphiなどで扱うUnicodeは、基本的にはUTF-16で、通常1文字は16ビットで表現されます。UTF-16では、全ての文字コードをカバーできないので、サロゲートペアという32ビット形式で16ビットでカバーできない文字コードを表現します。(UTF-32を使用すれば全て32ビットコードになります)
サロゲートペアは、UTF-16の文字コードに割り当てられていないコードを2つ使用し、上位サロゲートと下位サロゲートの組合わせで表現します。サロゲートペアについては、Webで調べるといろいろ出てきます。
通常のUTF-16の文字コードはSjift-JIS(CP932)と変換可能なものが多いですが、サロゲートペアで表されるものはSjift-JIS(CP932)では表すことは出来ません。UTF-8はUnicodeを可変で表すのでサロゲートペアも含めてUTF-16と変換可能です。

ふだん使用する可能性のある漢字の中でも、サロゲートペアで表現されるものがあります。
例えば、叱る(しかる)の”叱”は、Shift-JISにもありますが、新しい常用漢字ではサロゲートペアで表されるコードになります。
有名な牛丼屋さんの「吉野家」さんの吉も、本当は上の部分は”士”ではなく”土”です。公式サイトでも文書では”吉”を使っていますが、オレンジ色の看板を見ると分かります。この件もWebで調べるといろいろ出てきます。

前置きはさておき、Free Pascal(Lazarus)でこれらの文字を扱うことが出来るのかということが気になります。
出来るとはどういうことか考えると、サロゲートペアを含むUnicodeファイルのI/Oが出来る。プログラムの中で、Unicodeとしてデータを保持できる。プログラムの中で、UTF-8と相互に変換が出来る、ソースコードでサロゲートペアの文字列リテラルを扱える。という範囲で考えます。
Shift-JIS(CP932)とUTF-16の変換では、変換不能文字は’?’,’??’等になります。

以下のサンプルプログラム KnjTest11.pp でこれらを実行しています。
ソースコードをUTF-8で作成し、{$CodePage UTF8}ディレクティブを指定すると、コンパイル後文字列リテラルはUTF-16コードになり、サロゲートペアも指定できます。

surro001

Free Pascalコンパイラを単体で使用する場合、上記の様にサロゲートペアの漢字を直接記述してコンパイルできます。
しかし、同じFree Pascalコンパイラを使用しているLazarusでは、IDEでコンパイルするとエラーになります。
そのため、KnjTest11.ppはサロゲートペアを#$xxxx#$xxxxの形式で直接上位サロゲートと下位サロゲートを指定します。この場合はLazarusでもコンパイル可能です。

program KnjTest11;

{$Mode ObjFpc}{$H+}
{$CodePage UTF8}    // ソースコードは UTF-8。

uses
  Classes, SysUtils, Windows;

const
  // {$CodePage UTF8}が指定されているので、
  // 文字列リテラルはUnicodeString(UTF-16)となる。
  //                                            Unicode             SJIS  UTF8
  C1 = '叱る';            // '叱'             = U+53F1              8EB6  E5:8F:B1
  C2 = #$D842#$DF9F'る';  // '叱'の新常用漢字 = U+20B9F(D842:DF9F)  ----  F0:A0:AE:9F
  C3 = '吉野';            // '吉'             = U+5409              8B67  E5:90:89
  C4 = #$D842#$DFB7'野';  // '吉'の士が土     = U+20BB7(D842:DFB7)  ----  F0:A0:AE:B7
  // (D842:DF9F)と(D842:DFB7)は1文字をUTF-16コード2つ(上位サロゲート:下位サロゲート)で表すサロゲートペア。

var
  S1, S2, S3, S4 : AnsiString;
  U1, U2, U3, U4 : UnicodeString;
  Fs : TFileStream = nil;

{== 手続き:SBCS/MBCS文字列出力 ==}
procedure WriteStr(S: AnsiString); overload;
begin
  if Length(S) > 0 then
    Fs.WriteBuffer(S[1], Length(S));
  Fs.WriteBuffer((#$0d#$0a)[1], 2);
end;

{== 手続き:Unicode/ワイド文字列出力 ==}
procedure WriteStr(U: UnicodeString); overload;
begin
  if Length(U) > 0 then
    Fs.WriteBuffer(U[1], Length(U) * 2);
  Fs.WriteBuffer((#$0d#$00#$0a#$00)[1], 4);
end;

{=== メイン ===}
begin
  try
    try
      S1 := C1;   // UTF-16 -> CP932 変換可能。
      S2 := C2;   // UTF-16 -> CP932 変換不可。1文字目は'??'になる。
      S3 := C3;   // UTF-16 -> CP932 変換不可。
      S4 := C4;   // UTF-16 -> CP932 変換可能。1文字目は'??'になる。

      Fs := TFileStream.Create('ANSIテキストファイル.txt', fmOpenWrite or fmCreate);
      WriteStr(AnsiString('その1'));
      WriteStr(S1);
      WriteStr(S2);
      WriteStr(S3);
      WriteStr(S4);

      S1 := '叱る';           // S1 := C1; と同じ。
      S2 := #$D842#$DF9F'る'; // S2 := C2; と同じ。
      S3 := '吉野';           // S3 := C3; と同じ。
      S4 := #$D842#$DFB7'野'; // S4 := C4; と同じ。

      WriteStr(''); // '' はUTF-16にはならず、AnsiStringとなる。
      WriteStr(AnsiString('その2'));
      WriteStr(S1);
      WriteStr(S2);
      WriteStr(S3);
      WriteStr(S4);
      Fs.Free;

      U1 := S1;   // CP932 -> UTF-16 復元可能。
      U2 := S2;   // CP932 -> UTF-16 復元不可。'??'は元には戻らない。
      U3 := S3;   // CP932 -> UTF-16 復元可能。
      U4 := S4;   // CP932 -> UTF-16 復元不可。'??'は元には戻らない。

      Fs := TFileStream.Create('UNICODEテキストファイル.txt', fmOpenWrite or fmCreate);
      WriteStr(#$FEFF'その1');
      WriteStr(U1);
      WriteStr(U2);
      WriteStr(U3);
      WriteStr(U4);
      Fs.Free;

      S1 := UTF8Encode(C1); // UTF-16 -> UTF-8 変換可能。
      S2 := UTF8Encode(C2); // UTF-16 -> UTF-8 変換可能。
      S3 := UTF8Encode(C3); // UTF-16 -> UTF-8 変換可能。
      S4 := UTF8Encode(C4); // UTF-16 -> UTF-8 変換可能。

      Fs := TFileStream.Create('UTF8テキストファイル.txt', fmOpenWrite or fmCreate);
      WriteStr(S1);
      WriteStr(S2);
      WriteStr(S3);
      WriteStr(S4);
      Fs.Free;

      U1 := UTF8Decode(S1); // UTF-8 -> UTF-16 変換可能。
      U2 := UTF8Decode(S2); // UTF-8 -> UTF-16 変換可能。
      U3 := UTF8Decode(S3); // UTF-8 -> UTF-16 変換可能。
      U4 := UTF8Decode(S4); // UTF-8 -> UTF-16 変換可能。

      Fs := TFileStream.Create('UNICODEテキストファイル.txt', fmOpenWrite);
      Fs.Seek(0, soEnd);
      WriteStr(UnicodeString(''));  // ''はAnsiStringとなるので、UnicodeStringへの変換が必要。
      WriteStr('その2');
      WriteStr(U1);
      WriteStr(U2);
      WriteStr(U3);
      WriteStr(U4);

      // WinAPI(Unicode版)でサロゲートペアを使用。
      MessageBoxW(0, PUnicodeChar(U4 + U2), 'サロゲートペア', mb_OK);
    except
      on Ex: Exception do
        WriteLn(StdErr, Ex.Message);
    end;
  finally
    Fs.Free;
  end;
end.

重要なポイントは、Shift-JIS(CP932)で表せないUnicodeを扱う場合は、文字列に対しUnicodeString型かWideString型を使用し、マルチバイト文字列(AnsiString型やUTF8String型)にする場合は、Shift-JIS(CP932)への変換は行わず、UTF-8へ変換するようにします。
上記のプログラムではAnsiString型を使用していますが、UTF-8用の変数であることを明示したい場合はUTF8String型で定義すると分かりやすいと思います。
AnsiString型もUTF8String型も単にマルチバイト文字列型であり、文字エンコーディングの指定はありません。

もう一点注意することは、UnicodeString/WideStringとAnsiString/UTF8Stringの代入時の型変換は、Unicode(UTF-16)Ansi(CP932)が規定の変換になります(日本語Windowsの場合)。
そのため、Unicode(UTF-16)とUTF-8の変換にはUTF8Encode()関数とUTF8Decode()関数を使用します。

Lazarus 1.2.4 がリリースされました。

Lazarus 1.2.4 が出ました。
http://www.lazarus.freepascal.org
Free Pascal 2.6.4 ベースです。(Lazarus 1.2.0まではFree Pascal 2.6.2ベースです)

Win64ユーザは、Win32 + 64bitクロス環境を使用することが推奨されることは変りません。

Lazarus 1.2.4 の Win32版とx64クロスコンパイラは以下からダウンロードできます。
http://sourceforge.net/projects/lazarus/files/Lazarus%20Windows%2032%20bits/Lazarus%201.2.4/

インストール手順や使い方は Lazarus 1.2.0 と同じです。
インストール手順は、Pascal日和ホームページにあります。1.2.0を1.2.4に読み替えて下さい。