【问题标题】:ansiToUtf8 doesnt work with converted Delphi XE projects from Delphi 7?ansiToUtf8 不适用于从 Delphi 7 转换的 Delphi XE 项目?
【发布时间】:2011-05-10 04:23:52
【问题描述】:

有一个带有 CL8MSWIN1251 代码页设置的 Oracle 9 db 和带有一些编辑字段的 Delphi XE。

我需要将 Delphi 7 中制作的项目转换为 Delphi Xe 项目才能使用并能够看到 UTF8 数据。

所以我使用 Delphi XE 打开了 dpr 文件,它自动转换为 dproj。但是当我尝试向数据库中插入一些数据时,我得到了问题符号(“?”)而不是一些 utf8 字符。 我尝试使用 ansitoUTF8(edit1.text) 从 Edits (Tedit) 转换数据。它不起作用。 然后我在 XE 中开始了一个新项目,快速添加了一些编辑来检查 ansitoutf8 函数,它运行良好,并将数据插入到同一个数据库和同一个表中。

有一条规则:我不能更改 db 中的代码页设置。

begin
  adoquery1.close;
  adoquery1.sql.text:='insert into table (data1,data2) values ('+#39+ansitoUTF8(edit1.text)+#39+','+#39+ansitoUTF8(edit2.text)+#39+')';
  adoquery1.execsql;
end;

有什么建议吗?

【问题讨论】:

  • 您知道 sql.text 是一个字符串,因此类似于 D2009 中的 UnicodeString 吗?无论您之前做什么,它都会在分配给 sql.text 时转换为 unicode。您可以通过使用查询参数来解决这个问题(无论如何我都会推荐),将 DataType 设置为 ftString。
  • 您无法更改数据库代码页,但表是否在您的控制之下?检查 nvarchar 类型:download.oracle.com/docs/cd/A91202_01/901_doc/server.901/a90120/…

标签: delphi utf-8 delphi-7 oracle9i delphi-xe


【解决方案1】:

CL8MSWIN1251 不是 UTF-8 代码页,是 Windows 1251(西里尔文)代码页的 Oracle 实现。 Delphi XE 始终使用 UTF-16。 Oracle 数据库和客户端能够执行字符集转换。您应该正确设置客户端/会话的 NLS_LANG 参数。如果您不想更改客户端代码页,您可以在登录时发出 ALTER SESSION SET NLS_LANGUAGE = ... 以仅针对该会话更改它。对于带有 Oracle 9i 数据库的 XE Unicode 应用程序,您可以在客户端使用 AL16UTF16 来告知客户端数据是 UTF-16 格式并让 Oracle 执行其转换。

PS:类似代码

#39+ansitoUTF8(edit1.text)+#39+...

是引入SQL注入漏洞的最好方法。您应该使用绑定变量,或者至少使用 QuotedStr/AnsiQuotedStr 之类的函数,以确保字符串保持字符串并且不会成为 SQL 命令落入坏人之手。

【讨论】:

  • @ldsandon,没有“UTF-8 代码页”之类的东西。 UTF8 是 Unicode 文本的表示法,代码页用于 ANSI 字符串,以创建 ANSI 字符集和现在称为 Unicode 子集的映射。
  • @Cosmin: 就在 Windows 代码页 65001 是 UTF-8...msdn.microsoft.com/en-us/library/dd317756(v=vs.85).aspx
  • @Idsandon:你说:"CL8MSWIN1251 is not an UTF-8 code page";假设某些代码页是 UTF-8,而 CL8MSWIN1251 不是。它假定有多个 UTF-8 代码页,而实际上 UTF8 是一种符号,而不是代码页。 Windows 使用代码页 65001 处理 UTF8 数据这一事实并没有什么不同:代码页 65001 和 UTF8 之间的1:1 映射是 Windows 的伎俩。
  • iana.org/assignments/character-sets en.wikipedia.org/wiki/Code_page en.wikipedia.org/wiki/UTF-8 UTF-8 是一个字符编码/字符集,因此是一个代码页。好的,我的断言可能被误读(当然不需要多个 UTF-8 代码页)。
  • 好的,所以给 UTF-8 一个代码页编号不仅是 Windows 的把戏,而且 UTF-8 还是一个符号,或“转换”,而不是代码页。您应该编辑答案以消除任何可能的混淆。
【解决方案2】:

在 Delphi XE 中与 AnsiToUTF8() 函数存在向后兼容性中断,实际上在它调用的 Utf8Encode() 函数中。

在 Delphi XE 中,它返回一个 RawByteString 类型的字符串。所以你必须将结果类型强制为UTF8String。像这样:UTF8String(ansitoUTF8(...)

但我想这可能不是你的问题。

在您的代码中:

adoquery1.sql.text:='insert into table (data1,data2) values ('+#39+ansitoUTF8(edit1.text)+#39+','+#39+ansitoUTF8(edit2.text)+#39+')';

sql.text 表达式是 UnicodeString,因此您将在连接表达式中使用 Delphi XE 编译器进行显式转换。

以下行是否有效?

adoquery1.sql.text:='insert into table (data1,data2) values ('+#39+edit1.text+#39+','+#39+edit2.text+#39+')';

它应该在XE下工作,并且应该通过VCL从原始UnicodeString转换成UTF8。

【讨论】:

  • +1。我实际上会声明一个像这样的类型 type Ansi1251 = type AnsiString(1251) 然后转换使用 Ansi1251(AnsiToUTF8(...));这会将AnsiToUTF8 的结果视为具有1251 代码页的ANSI 文本中的文本,因此以下所有转换为Unicode 并返回1251 将保留字节值。
  • 不要那样做。让 Oracle 执行其转换。正确配置 Oracle,无需在每次需要写入数据时来回切换 ANSI 代码页。 Oracle 比 Delphi 更了解国家语言支持。
  • @Idsandon,据我了解这个问题,数据库列已经定义为使用代码页 1251,并且无法更改,但是 OP 想要将国际字符放在那里; OP 希望首先将国际文本编码为 UTF8,将其推入 DB 列不变,并且(我假设)在从 DB 读取文本时手动进行转换。由于 AnsiToUtf8 的结果用于字符串连接,原始字节被转换回 Unicode,我的猜测是转换映射到代码页 1251 中没有等效的一些 Unicode 代码点。 [... ]
  • [...] 强制 AnsiToUTF8 的结果被解释为 Ansi1251 保证转换为 Unicode 返回可以在 Ansi1251 代码页中表示的字符;由于从 Ansi1251 到 Unicode 到 Ansi1251 的转换保证是无损的,Oracle 将保留 UTF8 文本(不会用问号替换任何内容)。由于保留了 UTF8,因此可以随意将其转换回 Unicode。
  • 它在 Delphi 级别所做的任何事情都将在客户端/数据库级别进行 Oracle 转换,具体取决于 NLS 设置。如果他试图 hack 以另一种编码发送 UTF-8 数据的数据库,只有当且仅当客户端和数据库设置相同时它才会起作用,并且在任何其他情况下都会产生奇怪的结果.它在索引/查询数据时也会有奇怪的行为,除非使用纯二进制排序规则,这又会产生奇怪的结果。另外 CL8MSWIN1251 是单字节,而 UTF-8 不是,也会导致更多问题。
猜你喜欢
  • 1970-01-01
  • 2023-03-18
  • 2011-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
相关资源
最近更新 更多