【问题标题】:Solve E2010 Incompatible types: 'AnsiChar' and 'Char'解决 E2010 不兼容的类型:“AnsiChar”和“Char”
【发布时间】:2014-03-23 16:19:08
【问题描述】:

我尝试将一些代码从 D2007 转换为 XE5 并得到了

E2010 不兼容的类型:“AnsiChar”和“Char”

从此代码

  TSetOfChar = Set of Char;

  var
    CharacterSet: TSetOfChar;
    s: String;

    for j := 1 to Length(s) do
    begin
      Include(CharacterSet, s[j]);  // Error E2010
      if not CaseSensitive then
      begin
        Include(CharacterSet, AnsiUpperCase(s[j])[1]);  // Error E2010
        Include(CharacterSet, AnsiLowerCase(s[j])[1])   // Error E2010
      end
    end;

对解决方案有什么建议吗?我认为处理 AnsiStrings 就足够了。

【问题讨论】:

  • 类似的东西:在最近的 Delphi 版本中,我一直对 s[1] in ['A'..'Z','a'..'z','0'..'9'] 等所有内容发出警告。因为我不关心 Ansi 范围之外的任何事情,所以我会做AnsiChar(s[1]) in [etc。
  • 或者使用CharInSet(),就像编译器警告说的那样。
  • @Stijn 有测试字符属性的函数。无需回避国际文本。
  • sigh 如果你有兴趣,我已经在这里发泄过:plus.google.com/105759934778773466450/posts/LRqD794jd7q

标签: delphi delphi-xe5


【解决方案1】:

Delphi 集的基本类型最多可以有 256 个元素。这意味着你的集合实际上是set of AnsiChar

您的代码失败了,因为AnsiUpperCase(s[j]) 的类型为string,即UnicodeString。因此AnsiUpperCase(s[j])[1] 的类型为char,即WideChar。这就是编译器试图告诉你的。尽管有他们的名字,AnsiUpperCaseAnsiLowerCase 仍然在运行,并返回 UnicodeString

如果您确实仍想使用 ANSI 字符串,则需要使用 AnsiStrings 单元中的 AnsiUpperCaseAnsiLowerCase 函数。这些版本运行并返回AnsiString。将该单元添加到您的 uses 子句中,并确保您传递 AnsiString 值:

var
  AnsiStr: AnsiString;
....
AnsiStr := AnsiString(s);
for j := 1 to Length(AnsiStr) do
begin
  Include(CharacterSet, AnsiStr[j]); 
  if not CaseSensitive then
  begin
    Include(CharacterSet, AnsiUpperCase(AnsiStr[j])[1]);  
    Include(CharacterSet, AnsiLowerCase(AnsiStr[j])[1])   
  end
end;

当然,创建包含单个字符的字符串似乎效率极低。当然,您可以找到一种方法来做到这一点,而无需使用堆分配的字符串并直接对字符进行操作。

一个明显的改进是调用一次AnsiUpperCase,传递整个字符串,然后遍历返回的大写字符串。 AnsiLowerCase 也是如此。或者您可以使用CharUpperBuffCharLowerBuff 来避免堆分配。

当然还有整个 Unicode 问题。您使用的是 Unicode Delphi,但仅限于 ANSI。你真的想这样做吗?如果你想支持 Unicode,那么恐怕你必须停止使用 Delphi 集。您需要一种可以支持宽字符集的数据类型。您可能还需要考虑如何处理多字节 UTF-16 字符。

【讨论】:

  • 在每次循环迭代中对字符串进行类型转换效率低下,并且具有潜在危险,因为循环仍在迭代 UnicodeString,但现在索引到 AnsiString。当给定字符串在 Ansi 和 Unicode 之间转换时,两个版本的长度不能保证相同。最好先将源 UnicodeString 分配给本地 AnsiString 变量,然后在不进行类型转换的情况下遍历 AnsiString
  • @Remy 是的。我说了大部分。但你对长度是正确的。让我收拾一下。
【解决方案2】:
  uses
      ..., AnsiStrings;

  type
    TSetOfChar = Set of AnsiChar;

  var
    CharacterSet: TSetOfChar;
    s: AnsiString;

    for j := 1 to Length(s) do
    begin
      Include(CharacterSet, s[j])
      if not CaseSensitive then
      begin
        Include(CharacterSet, AnsiStrings.AnsiUpperCase(s[j])[1]);
        Include(CharacterSet, AnsiStrings.AnsiLowerCase(s[j])[1]);
      end
    end;

或者:

  uses
      ..., AnsiStrings;

  type
    TSetOfChar = Set of AnsiChar;

  var
    CharacterSet: TSetOfChar;
    s, s2: AnsiString;

    if CaseSensitive then
    begin
      for j := 1 to Length(s) do
        Include(CharacterSet, s[j]);
    end else 
    begin
      s2 := AnsiStrings.AnsiUpperCase(s);
      for j := 1 to Length(s2) do
        Include(CharacterSet, s2[j]);
      s2 := AnsiStrings.AnsiLowerCase(s);
      for j := 1 to Length(s2) do
        Include(CharacterSet, s2[j]);
      end
    end;

【讨论】:

  • 你要解释这些,还是我的回答中的解释足够了?
猜你喜欢
  • 2011-10-13
  • 1970-01-01
  • 2021-03-02
  • 2012-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多