delphi - 如何操作 UnicodeString 的子字符串而不是子数组?

标签 delphi unicode insert copy

我正在测试从 Delphi 5 到 XE 的迁移。由于不熟悉 UnicodeString,在提出问题之前我想先介绍一下它的背景。

Delphi XE 面向字符串的函数:CopyDeleteInsert 有一个参数 Index 告诉操作应该开始。 索引可以具有从 1 开始到应用函数的字符串长度结束的任何整数值。 由于字符串可以具有多元素字符,因此函数操作可以从属于编码名为代码点的单个 unicode 的多元素系列的元素(代理项)开始。 然后,拥有一个合理的字符串并使用其中一个函数,我们可以获得不合理的结果。

可以通过以下情况来说明这种现象,使用函数复制来表示相同命名代码点数组(即有意义的符号)的字符串em>)

  ($61, $13000, $63)

它是 'a'EGYPTIAN_HIEROGLYPH_A001'c' 的串联;它看起来像

enter image description here

情况 1. AnsiString 的副本(元素 = 字节)

我们从上面提到的 UnicodeString #$61#$13000#$63 开始,并将其转换为 UTF-8 编码的 AnsiString s0

然后我们测试一下函数

  copy (s0, index, 1)

对于索引的所有可能值;由于 s0 的长度为 6 个字节,因此有 6 个。

    procedure Copy_Utf8Test;
    type TAnsiStringUtf8 = type AnsiString (CP_UTF8);
    var ss    : string;
        s0,s1 : TAnsiStringUtf8;
        ii    : integer;
    begin
      ss := #$61#$13000#$63; //mem dump of ss: $61 $00 $0C $D8 $00 $DC $63 $00
      s0 := ss;              //mem dump of s0: $61 $F0 $93 $80 $80 $63
      ii := length(s0);      //sets ii=6 (bytes)
      s1 := copy(s0,1,1);    //'a'
      s1 := copy(s0,2,1);    //#$F0  F means "start of 4-byte series"; no corresponding named code-point
      s1 := copy(s0,3,1);    //#$93  "trailing in multi-byte series"; no corresponding named code-point
      s1 := copy(s0,4,1);    //#$80  "trailing in multi-byte series"; no corresponding named code-point
      s1 := copy(s0,5,1);    //#$80  "trailing in multi-byte series"; no corresponding named code-point
      s1 := copy(s0,6,1);    //'c'
    end;

第一个和最后一个结果在 UTF-8 代码页中是合理的,而其他 4 个结果则不然。

情况 2. UnicodeString 的副本(元素 = 单词)

我们从相同的 UnicodeString s0 := #$61#$13000#$63 开始。

然后我们测试一下函数

  copy (s0, index, 1)

对于索引的所有可能值;因为 s0 是 4 个字长,所以有 4 个。

    procedure Copy_Utf16Test;
    var s0,s1 : string;
        ii    : integer;
    begin
      s0 := #$61#$13000#$63; //mem dump of s0: $61 $00 $0C $D8 $00 $DC $63 $00
      ii := length(s0);      //sets ii=4 (bytes)
      s1 := copy(s0,1,1);    //'a'
      s1 := copy(s0,2,1);    //#$D80C surrogate pair member; no corresponding named code-point
      s1 := copy(s0,3,1);    //#$DC00 surrogate pair member; no corresponding named code-point
      s1 := copy(s0,4,1);    //'c'
    end;

第一个和最后一个结果在代码页 CP_UNICODE (1200) 内是合理的,而其他 2 个结果则不然。

结论。

面向字符串的函数:复制删除插入完美对被视为纯粹字符串的字符串进行操作字节或字数组。但是,如果字符串被视为其本质,即命名代码点数组的表示,那么它们就没有帮助。

以上两种情况都处理表示 3 个命名代码点的同一数组的字符串。它们被视为由 3 个有意义的符号组成的同一文本的表示(编码)(以避免滥用术语“字符”)。

人们可能希望能够提取(复制)任何这些有意义的符号,无论特定文本表示(编码)是单元素还是多元素。 我花了相当多的时间四处寻找与我在 Delphi 5 中使用的 Copy 等效的令人满意的方法。

问题。 是否存在这样的等效项,或者我必须自己编写它们?

最佳答案

您所描述的是Copy()Delete()Insert()如何ALWAYS 有效,即使对于 AnsiString 也是如此。这些函数对元素(即 Unicode 术语中的代码单元)进行操作,并且始终如此。

AnsiString 是一个 8 位 AnsiChar 元素的字符串,可以以任何 8 位 ANSI/MBCS 格式(包括 UTF-8)进行编码。

UnicodeString(和WideString)是一个 16 位 WideChar 元素的字符串,以 UTF-16 编码。

函数从未考虑编码。不适用于 MBCS AnsiString。不适用于 UTF-16 UnicodeString。索引是从字符串开头开始的绝对元素索引。

如果您需要在逻辑代码点边界上操作的编码感知Copy/Delete/Insert函数,其中每个代码点可能是字符串中的1+元素,那么您必须编写自己的函数,或者找到满足您需要的第三方函数。 RTL 中没有 MBCS/UTF 感知的毁损器函数。

关于delphi - 如何操作 UnicodeString 的子字符串而不是子数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25755822/

相关文章:

delphi - 如何使用 Free Pascal 调用物理连接的硬盘列表,或者如果失败,则使用 Delphi?

delphi - LiveBindings 在设计时工作,但在运行时不工作

java - Java 类名中的有效字符

unicode - 为什么从Unicode字符集中删除了U + D800到U + DFFF范围内的代码点?

postgresql - 创建新的架构、表并在同一 EXECUTE 中插入数据

mysql - Err 1292 - 截断了不正确的 DOUBLE 值

delphi - 如何在使用大量内存的程序中使用 AQTime 的内存分配分析器?

delphi - VirtualTreeView 的 Firemonkey 版本

windows - Windows 上的 Java Runtime Exec 因参数中的 Unicode 而失败

PHP 自动将数据插入数据库的烦恼