【问题标题】:Why won't Delphi 2009 let me Include a Char in a set?为什么 Delphi 2009 不允许我在集合中包含一个字符?
【发布时间】:2010-01-23 17:53:39
【问题描述】:

这是另一个关于将旧代码转换为 D2009 和 Unicode 的问题。我确定这很简单,但我没有看到解决方案...... CharacterSet 是一组 Char,s[i] 也应该是一个 Char。 但是编译器仍然认为 AnsiChar 和 Char 之间存在冲突。

代码:

TSetOfChar = Set of Char;

procedure aFunc;
var
  CharacterSet: TSetOfChar;
  s: String;
  j: Integer;
  CaseSensitive: Boolean;
begin
  // Other code that assign a string to s
  // Set CaseSensitive to a value

  CharacterSet := [];
  for j := 1 to Length(s) do
  begin
    Include(CharacterSet, s[j]);  // E2010 Incompatible types: 'AnsiChar' and 'Char'
    if not CaseSensitive then
    begin
      Include(CharacterSet, AnsiUpperCase(s[j])[1]);
      Include(CharacterSet, AnsiLowerCase(s[j])[1])
    end
  end;
end;  

【问题讨论】:

    标签: delphi unicode delphi-2009


    【解决方案1】:

    因为 Pascal 集的范围不能高于 0..255,所以编译器会悄悄地将字符集转换为 AnsiChars 集。这就是给你带来麻烦的原因。

    【讨论】:

    • 哇,恕我直言,这是一些奇怪的行为。 A 肯定更喜欢编译器在这里给出错误。当所有其他转换导致编译器警告时,为什么要在这里“安静地”?
    【解决方案2】:

    这个问题没有好的简单答案(梅森已经给出了原因)。好的解决方案是重新考虑算法以摆脱“字符集”类型。快速而肮脏的解决方案是保留 ansi 字符和字符串:

    TSetOfChar = Set of AnsiChar;
    
    procedure aFunc;
    var
      CharacterSet: TSetOfChar;
      s: String;
      S1, SU, SL: Ansistring;
      j: Integer;
      CaseSensitive: Boolean;
    begin
      // Other code that assign a string to s
      // Set CaseSensitive to a value
    
      S1:= s;
      SU:= AnsiUpperCase(s);
      SL:= AnsiLowerCase(s);
      CharacterSet := [];
      for j := 1 to Length(S1) do
      begin
        Include(CharacterSet, S1[j]);
        if not CaseSensitive then
        begin
          Include(CharacterSet, SU[j]);
          Include(CharacterSet, SL[j]);
        end
      end;
    end;  
    

    【讨论】:

      【解决方案3】:

      Delphi 不支持 Unicode 字符集。您只能在集合中使用 AnsiChar,但这不足以容纳您的字符串可能包含的所有可能字符。

      不过,您可以使用 TBits 类型,而不是 Delphi 的本机集合类型。

      procedure aFunc;
      var
        CharacterSet: TBits;
        s: String;
        c: Char;
        CaseSensitive: Boolean;
      begin
        // Other code that assign a string to s
        // Set CaseSensitive to a value
      
        CharacterSet := TBits.Create;
        try
          for c in s do begin
            CharacterSet[Ord(c)] := True;
            if not CaseSensitive then begin
              CharacterSet[Ord(Character.ToUpper(c))] := True;
              CharacterSet[Ord(Character.ToLower(c))] := True;
            end
          end;
        finally
          CharacterSet.Free;
        end;
      end;
      

      TBits 对象自动扩展以容纳它需要表示的最高位。

      我对您的代码所做的其他更改包括使用new "for-in" loop style 和新的Character 单元来处理Unicode 字符。

      【讨论】:

      • 我不确定这个问题是否真的暗示了“set-of-all-widechar's”的构造——比如类型。更有可能的是,作者实际上是在使用所有 unicode 字符的一小部分。
      • 输入类型是 UnicodeString。我们没有被告知它只包含当前代码页中的字符。不管子集有多么小,如果它不是 AnsiChar 的子集也没关系。
      • 非常方便的想法。如果你真的需要一个 65K 位数组,这很好用,并且自动扩展以填充你实际使用的代码点数意味着你不必预先分配到 16 位。
      • 还有一点要记住的是,UnicodeString 基于 UTF-16,它使用 2 字符代理来表示 Unicode 代码点的子集。为了政治正确,您应该在处理“字符”集之前将 UTF-16 解码为 UTF-32。 TCharacter 类具有处理 UTF-32 代码点和 UTF-16 代理项的方法。
      猜你喜欢
      • 1970-01-01
      • 2020-11-01
      • 2014-02-19
      • 1970-01-01
      • 2015-01-28
      • 2019-03-06
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      相关资源
      最近更新 更多