有没有办法在 Delphi 2009 中查看一个字符是使用 1 个字节还是 2 个字节?

Posted

技术标签:

【中文标题】有没有办法在 Delphi 2009 中查看一个字符是使用 1 个字节还是 2 个字节?【英文标题】:Is there a way to see if a character is using 1 or 2 bytes in Delphi 2009? 【发布时间】:2010-09-16 11:27:38 【问题描述】:

Delphi 2009 已将其字符串类型更改为使用 2 个字节来表示一个字符,这允许支持 unicode 字符集。现在当你得到 sizeof(string) 你得到 length(String) * sizeof(char) 。 Sizeof(char) 当前为 2。

我感兴趣的是是否有人知道一种方法,它可以逐个字符地找出它是否适合单个字节,例如找出一个 char 是 ascii 还是 Unicode。

我主要想知道的是,在我的字符串进入数据库(oracle、Documentum)之前,该字符串将用完多少字节。

我们需要能够预先实施限制,理想情况下(因为我们有一个庞大的安装基础),而无需更改数据库。如果字符串字段允许 12 个字节,则在 delphi 2009 中,长度为 7 的字符串将始终显示为使用 14 个字节,即使一旦它到达数据库,它只会使用 7(如果是 ascii)或 14(如果是双字节),或者介于两者之间的某个位置混合物。

【问题讨论】:

【参考方案1】:

您可以使用 StringElementSize 函数来确定字符串是 Unicode 还是 ANSI。 要检查字符是否为 ANSI,请使用 Character.pas 单元中的 TCharacter.IsAnsi 类函数。

【讨论】:

【参考方案2】:

你回答说你真的想知道你的字符串会占用多少字节。

转换成 UTF8String 怎么样? Ansi 字符将占用 1 个字节。请记住,在 UTF-8 中,Unicode 字符可能占用超过 2 个字节。

【讨论】:

【参考方案3】:

由于 AnsiString 1 char = 1 字节和 Unicode String 1 char = 2 字节,执行的简单测试是 IsAnsiString:= sizeof(aString)=length(aString);

【讨论】:

除非我弄错了,否则 SizeOf(String) 在所有 32 位版本的 Delphi 中都将返回 4,因为 String(AnsiString 或 UnicodeString)是指针类型。因此 SizeOf() 将返回指针的大小。 Length(String) 返回字符数,所以你的这个检查不起作用。【参考方案4】:

首先,请记住,您的数据库长度实际上可能是以字符而不是字节为单位的 - 您必须查看数据类型的文档。出于问题的目的,我将假设它确实是后者。

您的字符串将使用的字节数完全取决于存储它的字符编码。如果是 UTF-16,Delphi 中默认的字符串类型,那么它总是每个字符 2 个字节,不包括代理。

但是,假设数据库使用 Unicode 字符集,最可能的编码是 UTF-8。这是一种可变长度编码:字符可能需要 1 到 4 个字节,具体取决于字符。您可以在 Wikipedia 上查看范围如何映射的图表。

但是,如果您根本不更改数据库架构,那么这一定意味着以下三件事之一:

    您目前以二进制方式存储所有内容,而不是文本方式(通常不是一个好的选择) 数据库已经存储了 Unicode 和计数字符,而不是字节(否则,您现在就会遇到问题,在重音字母的情况下更是如此) 数据库存储在单字节代码页中,例如 Windows-1252,从而完全阻止您存储 Unicode 数据(这不成问题,因为字符的存储方式与以前相同,尽管您可以' t 使用 Unicode)

我不熟悉 Oracle,但如果您查看 MSSQL,它们有两种不同的数据类型:varchar 和 nvarchar。 Varchar 以字节计,而 nvarchar 以字符计,因此适用于 Unicode。另一方面,mysql 只有 varchar,而且它总是以字符计(从 4.1 开始)。因此,您应该检查 Oracle 文档和您的数据库架构,以获得关于这是否是问题的决定性答案。

【讨论】:

【参考方案5】:

如果你不想在 Delphi 2009 中使用 Unicode,你可以使用 AnsiString 类型。但你为什么要这样做。

一个繁琐但有效的测试可能是:

function IsAnsi(const AString: string): Boolean;
var
  tempansi : AnsiString;
  temp : string;
begin
  tempansi := AnsiString(AString);
  temp := tempansi;
  Result := temp = AString;
end;

【讨论】:

我认为 AnsiString 应该被强制使用特定的代码页,例如 AnsiString(CP_UTF8)。 @skamradt AnsiString(CP_UTF8) 不会破坏函数的全部目的吗?所有 unicode 字符串也可以用 UTF-8 表示,因此检查将始终返回 true。【参考方案6】:

一个 ASCII 字符总是适合一个字节。您不能对 unicode 字符说同样的话,因为这取决于它的编码方式。您无法从单个字节中看出它是 ASCII 还是 unicode 字符,或者根本就不是字符。那么你的问题又是什么?为什么你需要知道?我的猜测是你误解了 unicode 或者我误解了你的问题。

【讨论】:

【参考方案7】:

你可以检查字符的值:

if ord(c) < 128 then
    // is an ascii character

【讨论】:

既然你用的是D2009,那么看一下新的TCharacter类,即:if TCharacter.IsLatin1(c) then @RemyLebeau-TCharacter.IsLatin 在 Delphi XE7 中不可用。有人知道它的替代品吗?

以上是关于有没有办法在 Delphi 2009 中查看一个字符是使用 1 个字节还是 2 个字节?的主要内容,如果未能解决你的问题,请参考以下文章

在 Delphi 2009 中显示 PDF 文件的最佳方法是啥[关闭]

delphi 的字太小了怎么办?

将 Delphi 逐步移植到 C++

如何在 Delphi 2009 中对自定义组件进行鼠标平移

Delphi中的递归类实例大小

在 Delphi 2009 中逐步升级 Indy 10