22

Czy jest dostępna rutyna w Delphi 2007 do konwersji znaków w wysokim zakresie tabeli ANSI (> 127) na ich odpowiedniki w czystym ASCII (< = 127) według lokalizacji (strony kodowej)?Konwersja znaków Hi-Ansi do odpowiednika Ascii (é -> e)

Wiem, że niektóre znaki nie mogą być dobrze przetłumaczone, ale większość może, szczególnie. w zakresie 192-255:

  • ÀA
  • à
  • Ëe
  • ëe
  • ÇC
  • çC
  • -(en kreską)-(kreska - które mogą być trudniejsze)
  • -(em dash)-(myślnik)

Odpowiedz

27

WideCharToMultiByte robi najlepiej dopasowanych mapowanie dla wszelkich znaków, które nie są obsługiwane przez określony zestaw znaków, w tym na usuwaniu znaków diakrytycznych. Możesz zrobić dokładnie to, co chcesz, używając tego i mijając 20127 (US-ASCII) jako stronę kodową.

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; 

Wywołanie że ze swoimi przykładami produkuje wyniki szukasz, w tym przypadku emdash-do-minus, który nie sądzę, jest obsługiwane przez sugestię Jeroen do konwersji do normalizacji forma D. Jeśli tak chcąc przyjąć takie podejście, Michael Kaplan ma numer blog post, który wyraźnie omawia usuwanie znaków diakrytycznych (zamiast normalizacji w ogóle), ale używa C# i API, który został wprowadzony w systemie Vista. Możesz uzyskać coś podobnego za pomocą aplikacji FoldString api (dowolne wydanie WinNT).

Oczywiście, jeśli robisz to tylko dla jednego zestawu znaków, i chcesz uniknąć kosztów związanych z konwersją do iz WideString, Padu ma rację, że prosta pętla for i tabela odnośników byłyby równie skuteczne .

+0

Dzięki Craig. To bardziej ogólne rozwiązanie niż wyszukiwanie. Miał literówkę w magicznej liczbie, więc poprawiłem ją i użyłem stałej. W każdym razie działa na D2007 i D2009. –

+0

Jedną z rzeczy, które zauważyliśmy, jest to, że "β" (Unicode 1E9E latin capital letter sharp s) nie jest konwertowane, więc robimy to wcześniej: StringReplace (astr, "β", "SS", [rfReplaceAll]) – PatrickvL

3

wierzę najlepiej jest stworzenie tabeli.

+0

Ponadto, jeśli używasz przyzwoitej biblioteki regex z delphi, to może być również używana, ale nadal jest rodzajem tabeli odnośników. –

+0

Dzięki Padu. Tak myślałem. Mimo to przyjmuję odpowiedź Craiga, ponieważ jest bardziej ogólna. –

1

Czego szukasz to normalizacja.

Michael Kaplan napisał nice blog article about normalization.

Nie rozwiązuje to natychmiast problemu, ale wskazuje właściwy kierunek.

--jeroen

+1

Usuwanie znaków łączących NFKD + działa bardzo często. Istnieją jednak znaki takie jak "ÆÐÆÐÞßæðøþ", które nie rozkładają się i muszą być traktowane ręcznie. – dan04

7

Wystarczy przedłużyć odpowiedź Craiga dla Delphi 2009:

Jeśli używasz Delphi 2009 i nowsze, można użyć kod bardziej czytelny z takim samym skutkiem:

function OStripAccents(const aStr: String): String; 
type 
    USASCIIString = type AnsiString(20127);//20127 = us ascii 
begin 
    Result := String(USASCIIString(aStr)); 
end; 

Niestety, ten kod działa tylko w systemie MS Windows. W systemie Mac akcenty nie są zastępowane najlepiej dopasowanymi znakami, ale znakami zapytania.

Oczywiście, Delphi używa wewnętrznie WideCharToMultiByte w systemie Windows, podczas gdy na Macu ikona jest używana (patrz LocaleCharsFromUnicode w System.pas). Pytanie brzmi, czy to inne zachowanie w różnych systemach operacyjnych powinno być traktowane jako błąd i zgłoszone do CodeCentral.

+0

iconv ma opcję '// TRANSLIT', ale' LocaleCharsFromUnicode() 'jej nie używa. –