22

Có một thường trình có sẵn trong Delphi 2007 để chuyển đổi các ký tự trong phạm vi cao của bảng ANSI (> 127) sang các ký tự tương đương trong ASCII thuần túy (<) = 127) theo một ngôn ngữ (mã)?Chuyển đổi các ký tự Hi-Ansi thành Ascii tương đương (é -> e)

Tôi biết một số ký tự không thể dịch tốt nhưng hầu hết có thể, đặc biệt. trong 192-255 khoảng:

  • ÀMột
  • àmột
  • ËE
  • ëe
  • ÇC
  • çc
  • -(en dash)-(gạch nối - đó có thể là phức tạp hơn)
  • -(dấu gạch ngang)-(gạch nối)

Trả lời

27

WideCharToMultiByte không lập bản đồ phù hợp nhất đối với bất kỳ ký tự không được hỗ trợ bởi bộ ký tự quy định, bao gồm cả dấu tước. Bạn có thể thực hiện chính xác những gì bạn muốn bằng cách sử dụng và chuyển 20127 (US-ASCII) làm mã.

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 rằng với các ví dụ của bạn tạo ra kết quả mà bạn đang tìm kiếm, bao gồm cả emdash-to-trừ trường hợp, mà tôi không nghĩ được xử lý bởi gợi ý Jeroen để chuyển đổi sang hình thức Normalization D. Nếu bạn đã làm muốn có cách tiếp cận đó, Michael Kaplan có một số blog post thảo luận rõ ràng về việc bỏ dấu phụ (thay vì bình thường hóa nói chung), nhưng nó sử dụng C# và một API được giới thiệu trong Vista. Bạn có thể nhận được một cái gì đó tương tự bằng cách sử dụng api FoldString (bất kỳ phiên bản WinNT). Tất nhiên nếu bạn chỉ làm điều này cho một bộ ký tự, và bạn muốn tránh chi phí từ việc chuyển đổi đến và từ một WideString, Padu là chính xác rằng một vòng lặp đơn giản và một bảng tra cứu sẽ chỉ có hiệu quả .

+0

Cảm ơn Craig. Đó là một giải pháp chung chung hơn so với tra cứu. Nó có một lỗi đánh máy trong số ma thuật, vì vậy tôi đã sửa nó và sử dụng một hằng số thay thế. Nhưng dù sao, nó hoạt động trên D2007 cũng như D2009. –

+0

Một điều chúng tôi nhận thấy với điều này, là 'β' (unicode 1E9E chữ cái latin sharp s) không được chuyển đổi, vì vậy chúng tôi làm điều này trước: StringReplace (aStr, 'β', 'SS', [rfReplaceAll]) – PatrickvL

3

Tôi tin rằng đặt cược tốt nhất của bạn là tạo ra một bảng tra cứu.

+0

Ngoài ra, nếu bạn đang sử dụng một thư viện regex phong nha với delphi, có thể được sử dụng là tốt, nhưng nó vẫn là một loại bảng tra cứu. –

+0

Cảm ơn Padu. Đó là những gì tôi nghĩ. Tôi vẫn chấp nhận câu trả lời của Craig bởi vì nó chung chung hơn. –

1

Điều bạn đang tìm kiếm là chuẩn hóa.

Michael Kaplan đã viết nice blog article about normalization.

Nó không ngay lập tức giải quyết vấn đề của bạn, nhưng chỉ cho bạn đi đúng hướng.

--jeroen

+1

NFKD + loại bỏ các dấu kết hợp hoạt động rất nhiều thời gian. Tuy nhiên, có các ký tự như 'ÆÐØÞßæðøþ' không phân hủy và phải được xử lý thủ công. – dan04

7

Chỉ cần để mở rộng câu trả lời Craig cho Delphi 2009:

Nếu bạn sử dụng Delphi 2009 và mới hơn, bạn có thể sử dụng một mã dễ đọc hơn với cùng một kết quả:

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

Thật không may, mã này không làm việc chỉ trên MS Windows. Trên máy Mac, các điểm nhấn không được thay thế bằng các ký tự được trang bị tốt nhất mà bằng các dấu hỏi.

Rõ ràng, Delphi sử dụng nội bộ WideCharToMultiByte trên Windows trong khi trên biểu tượng Mac được sử dụng (xem LocaleCharsFromUnicode trong System.pas). Câu hỏi đặt ra là nếu hành vi này khác nhau trên hệ điều hành khác nhau nên được coi là lỗi và báo cáo cho CodeCentral.

+0

iconv có tùy chọn '// TRANSLIT', nhưng' LocaleCharsFromUnicode() 'không sử dụng nó. –

Các vấn đề liên quan