2014-06-24 61 views
3

我想開發一個十六進制轉儲視圖,並且在當前活動的ANSI代碼頁(CP_ACP)中不可打印字符時出現問題。我如何檢測它們並打印一個點呢?確定字符是否可打印

我目前的功能如下:

function HexChar(j: byte): AnsiChar; 
begin 
    if j < $20 then result := '.' 

    // Dirty workaround which only supports the undefined characters of Windows-1252 
    else if (GetACP=1252) and ((j=$81) or (j=$8D) or (j=$8F) or (j=$90) or (j=$9D)) then result := '.' 

    else result := AnsiChar(j); 
end; 

用Delphi XE4和字體宋體,人物$ 81 $ 8D,8F $,$ 90 $ 9D是看不見的。 GetACP返回1252,所以我使用Windows-1252。根據Wikipedia,我發現的範圍未在Windows-1252中定義。如何檢查在當前活動代碼頁中是否定義了具有序號值j的字符?

+0

你將需要定義的字符集。馬上,你的代碼會犯下嚴重的弊端。 「Char」是一個兩字節的UTF-16字符。這不是你想要的。對於十六進制編輯器,您希望使用ASCII或可能是ANSI代碼頁之一。你需要在這方面做出一些決定。兩個字節的「Char」根本無濟於事。 –

+0

我想要一個ANSI轉儲。我以爲'Char'是好的,因爲ANSI字符會自動映射到unicode。 'HexChar'將被'HexDump'函數調用,它將使用s:= s + HexChar(x)'在右邊構建可讀的列。 –

+0

有很多ANSI代碼頁。你想要哪一個?並且爲什麼要以16位類型存儲8位數據。請注意,'Chr(j)'不會按照您的想法從ANSI轉換爲Unicode。它產生一個帶序數值「j」的UTF-16字符元素。 –

回答

2

致電GetStringTypeW支持詳細字符分類的功能。

也可以使用GetStringTypeEx或不建議使用的GetStringTypeA函數,但都只是根據MSDN調用GetStringTypeW。此外,GetStringTypeEx還隱藏了ANSI和Unicode版本之間的區別,並由MSDN推薦用於字符類型檢索。

另一種可能性是從character.pas使用TCharacter.GetUnicodeCategory()方法。

+0

唉,'IsC​​harAlphaNumeric'不會打印類似'^'或'〜'的東西,因爲它們既不是數字也不是alpha。 –

+0

感謝您的提示。 'GetStringType'似乎非常可靠。這是我的[使用'GetStringTypeW'](http://pastebin.com/2SpjQadb)的代碼以及過時的['GetStringTypeA'](http://pastebin.com/SR25banY)。 我還有一個問題。 $ 98在我的電腦上映射到Unicode [$ 02DC](http://www.fileformat.info/info/unicode/char/2dc/index.htm)。因此,此代字號將自動與其鄰居合併(因此十六進制轉儲看起來不太好)。這個組合信息也可以使用'GetStringTypeW' /'CT_CTYPE3'查詢嗎? –

+0

您使用哪個函數來顯示結果字符串?如果你輸出原始的ANSI字符作爲輸入到'IsAnsiPrintable()'並帶有適當的功能,那麼我認爲這不應該是什麼問題。 – ThinkJet

1

使用帶有GGI_MARK_NONEXISTING_GLYPHS的GetGlyphIndices以檢查字體中是否存在特定字符。

下面是一個例子:

procedure ReplaceNonPrintableChars(var s: string); 
var 
    GlyphIndicesA: PWordArray; 
    Len: Integer; 
    I: Integer; 
    Cnt: DWORD; 
    DC: THandle; 
    C: TCanvas; 
begin 
    DC := GetDC(0); 
    try 
    C := TCanvas.Create; 
    try 
     C.Handle := DC; 
     C.Font.Name := 'Arial'; 
     Len := Length(S); 
     GetMem(GlyphIndicesA, SizeOf(Word) * Len); 
     try 
     Cnt := GetGlyphIndices(C.Handle, PChar(S), Len, PWord(GlyphIndicesA), GGI_MARK_NONEXISTING_GLYPHS); 
     if not (Cnt = GDI_ERROR) then 
      for I := 0 to Cnt - 1 do 
      if GlyphIndicesA[I] = $FFFF then 
       S[I+1] := '.'; 
     finally 
     Dispose(GlyphIndicesA); 
     end; 
    finally 
     C.Free; 
    end; 

    finally 
    ReleaseDC(0, DC); 
    end; 
end; 
+0

嗯......我該如何使用它? 'var x:word; dc:hdc;開始dc:= GetDc(Memo1.Handle); GetGlyphIndices(dc,PChar(Char(AnsiChar(j))),1,pword(@x),GGI_MARK_NONEXISTING_GLYPHS)總是返回'GDI_ERROR'。 –

+0

我已經添加了一個示例。 –

+0

你的代碼檢測一個字符是否定義了一個字體。但問題是如果字符是在CODEPAGE中定義的。 – Elmue