Search code examples
delphicharacter-encodingasciidelphi-2007non-ascii-characters

Convert Hi-Ansi chars to Ascii equivalent (é -> e)


Is there a routine available in Delphi 2007 to convert the characters in the high range of the ANSI table (>127) to their equivalent ones in pure ASCII (<=127) according to a locale (codepage)?

I know some chars cannot translate well but most can, esp. in the 192-255 range:

  • ÀA
  • àa
  • ËE
  • ëe
  • ÇC
  • çc
  • (en dash)- (hyphen - that can be trickier)
  • (em dash)- (hyphen)

Solution

  • WideCharToMultiByte does best-fit mapping for any characters that aren't supported by the specified character set, including stripping diacritics. You can do exactly what you want by using that and passing 20127 (US-ASCII) as the codepage.

    function BestFit(const AInput: AnsiString): AnsiString;
    const
      CodePage = 20127; //20127 = us-ascii
    var
      WS: WideString;
    begin
      WS := WideString(AInput);
      SetLength(Result, WideCharToMultiByte(CodePage, 0, PWideChar(WS),
        Length(WS), nil, 0, nil, nil));
      WideCharToMultiByte(CodePage, 0, PWideChar(WS), Length(WS),
        PAnsiChar(Result), Length(Result), nil, nil);
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
       ShowMessage(BestFit('aÀàËëÇç–—€¢Š'));
    end;
    

    Calling that with your examples produces results you're looking for, including the emdash-to-minus case, which I don't think is handled by Jeroen's suggestion to convert to Normalization form D. If you did want to take that approach, Michael Kaplan has a blog post the explicitly discusses stripping diacritics (rather than normalization in general), but it uses C# and an API that was introduces in Vista. You can get something similar using the FoldString api (any WinNT release).

    Of course if you're only doing this for one character set, and you want to avoid the overhead from converting to and from a WideString, Padu is correct that a simple for loop and a lookup table would be just as effective.