Unicodeの世界では、1つの"文字"(書記素、grapheme)が1つのコードポイント(code point)で表されるとは限りません。サロゲートペアとか結合文字とか絵文字とか、文字列に入っているものがどれくらいの"文字数"になっているのかを知るのは意外に難しい話です。
現在一般的と考えられる方法として、
- ICU( International Components for Unicode、https://icu.unicode.org/)を使う
- 正規表現で"\X"でマッチする
- Unicodeの規格(Unicode Standard Annex #29)を元に自前で実装するr
ところがDelphi 12で標準サポートされたSkia4Delphiでは簡単に文字列を書記素クラスタで分割できるようになりました(ICUを取り込んでいるようです)。試しに正規表現(PCRE)による分割と比較してみましょう。
なおDelphi 11 Alexandriaおよびそれ以前のバージョンではSkia4Delphiをインストールする必要があります(現時点(2023/12)の最新は6.0.0)。
新規プロジェクトを作成し、フォーム(フォントサイズを大きめにしておくと結果が見やすくなります)にTEditを1つ、TButtonを2つ、結果表示のためのTMemoを1つ配置します。またプロジェクトツールウィンドウでプロジェクトを右クリック→Skiaを有効化を選択して、実行ファイルと同じ場所にsk4d.dllが配置されるようにします。
usesにSystem.Skiaを追加し、フォームのOnShowイベントで
procedure TForm1.FormShow(Sender: TObject);
begin
Edit1.Text := #$20BB7 + '野屋のコピペ' +
#$00E5 + #$00E1 + #$0302 + #$0303 + #$0304 +
#$1F62D +
#$1F937 + #$1F3FD + #$200D + #$2640 + #$FE0F +
#$1F468 + #$200D + #$1F469 + #$200D + #$1F467 + #$200D + #$1F466 +
#$1F469 + #$1F3FD + #$200D + #$1F4BB +
#$1F1EF + #$1F1F5;
end;
とEdit1.Textにサンプル文字列を設定し、Button1のOnClickイベントで
procedure TForm1.Button1Click(Sender: TObject);
begin
for var Match in TRegEx.Matches(Edit1.Text,'\X') do
begin
Memo1.Lines.Add(Match.Value);
end;
end;
Button2のOnClickイベントで
procedure TForm1.Button2Click(Sender: TObject);
var
SkUnicode: ISkUnicode;
begin
SkUnicode := TSkUnicode.Create;
for var S in SkUnicode.GetBreaks(Edit1.Text,TSkBreakType.Graphemes) do
begin
Memo1.Lines.Add(S);
end;
end;
とします。では実行してみましょう。まず正規表現です。𠮷
野
屋
の
コ
ピ
ペ
å
á̂̃̄
😭
🤷
🏽
♀️
👨
👩
👧
👦
👩
🏽
💻
🇯🇵
(Windows上の表示とは若干異なります)正規表現による分割では絵文字のZWJ(ゼロ幅接合子)による結合はうまく処理できないようです。これはPCRE 8.45がだいぶ古いバージョンで、最新のUnicodeに対応できていないことが原因と考えられます。
次にSkia4Delphiです。
𠮷
野
屋
の
コ
ピ
ペ
å
á̂̃̄
😭
🤷🏽♀️
👨👩👧👦
👩🏽💻
🇯🇵
0 件のコメント:
コメントを投稿