Solve E2010 Incompatible types: 'AnsiChar' and 'Char'

后端 未结 2 1836
一个人的身影
一个人的身影 2021-01-28 09:59

I try to convert some code from D2007 to XE5 and got

E2010 Incompatible types: \'AnsiChar\' and \'Char\'

from this code

  TSetOfChar = Set of Cha         


        
相关标签:
2条回答
  • 2021-01-28 10:16
      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;
    

    Alternatively:

      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;
    
    0 讨论(0)
  • 2021-01-28 10:18

    The base type for a Delphi set can have at most 256 elements. Which means that your set is in fact really set of AnsiChar.

    And your code is failing because AnsiUpperCase(s[j]) is of type string which is UnicodeString. Hence AnsiUpperCase(s[j])[1] is of type char which is WideChar. Which is what the compiler is trying to tell you. Despite their names, AnsiUpperCase and AnsiLowerCase operate on, and return UnicodeString.

    If you really do still want to work with ANSI strings then you will need to use the AnsiUpperCase and AnsiLowerCase functions from the AnsiStrings unit. These versions operate on, and return AnsiString. Add that unit to your uses clause, and make sure you pass AnsiString values:

    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;
    

    Of course, it seems extremely inefficient to be creating strings containing single characters. Surely you can find a way to do this without using heap allocated strings and operating directly on characters.

    An obvious improvement would be to call AnsiUpperCase once, passing the entire string, and iterate over the upper case string returned. Likewise for AnsiLowerCase. Or you could use CharUpperBuff and CharLowerBuff to avoid heap allocations.

    And of course there's the whole issue of Unicode. You are using a Unicode Delphi but being confined to ANSI. Do you really want to do that? If you want to support Unicode then you have to stop using Delphi sets, I am afraid. You'll need a data type that can support sets of wide characters. You would also perhaps need to consider what to do with multi-byte UTF-16 characters.

    0 讨论(0)
提交回复
热议问题