确定字符是否可打印

时间:2014-06-24 11:46:42

标签: delphi winapi codepages

我想开发一个hex-dump-view,并且在当前活动的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和字体Courier New,字符$ 81,$ 8D,$ 8F,$ 90,$ 9D是不可见的。 GetACP返回1252,所以我使用的是Windows-1252。根据{{​​3}},我发现的范围没有在Windows-1252中定义。如何检查当前活动代码页中是否定义了序号为j的字符?

2 个答案:

答案 0 :(得分:2)

调用支持详细字符分类的GetStringTypeW函数。

也可以使用GetStringTypeEx或已弃用的GetStringTypeA函数,但两者都只根据MSDN调用GetStringTypeW。此外,GetStringTypeEx隐藏ANSI和Unicode版本之间的差异,并由MSDN推荐用于字符类型检索。

另一种可能性是使用TCharacter.GetUnicodeCategory()中的character.pas方法。

答案 1 :(得分:1)

GetGlyphIndices与GGI_MARK_NONEXISTING_GLYPHS一起使用,以检查字体中是否存在特定字符。

以下是一个例子:

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;