在.Net中找出Unicode字符名称

Posted

技术标签:

【中文标题】在.Net中找出Unicode字符名称【英文标题】:Finding out Unicode character name in .Net 【发布时间】:2010-01-18 16:54:12 【问题描述】:

.Net 中有没有办法找出某个字符的 Unicode 名称?

如果没有,是否有图书馆可以做到这一点?

【问题讨论】:

【参考方案1】:

现在比以往任何时候都容易,因为 nuget 中有一个名为 Unicode Information 的包

有了这个,你可以调用:

UnicodeInfo.GetName(character)

【讨论】:

【参考方案2】:

这是一个您可以立即实施的解决方案,例如复制/粘贴/编译。

首先,在此处下载 Unicode 数据库 (UCD):http://www.unicode.org/Public/UNIDATA/UnicodeData.txt

接下来,将此代码添加到您的项目中以读取 UCD 并创建字典以查找 .NET 字符值的名称:

string[] unicodedata = File.ReadAllLines( "UnicodeData.txt", Encoding.UTF8 );
Dictionary<char,string> charname_map = new Dictionary<char,string>( 65536 );
for (int i = 0; i < unicodedata.Length; i++)

    string[] fields = unicodedata[i].Split( ';' );
    int char_code = int.Parse( fields[0], NumberStyles.HexNumber );
    string char_name = fields[1];
    if (char_code >= 0 && char_code <= 0xFFFF) //UTF-16 BMP code points only
    
        bool is_range = char_name.EndsWith( ", First>" );
        if (is_range) //add all characters within a specified range
        
            char_name = char_name.Replace( ", First", String.Empty ); //remove range indicator from name
            fields = unicodedata[++i].Split( ';' );
            int end_char_code = int.Parse( fields[0], NumberStyles.HexNumber );
            if (!fields[1].EndsWith( ", Last>" ))
                throw new Exception( "Expected end-of-range indicator." );
            for (int code_in_range = char_code; code_in_range <= end_char_code; code_in_range++)
                charname_map.Add( (char)code_in_range, char_name );
        
        else
            charname_map.Add( (char)char_code, char_name );
    

UnicodeData.txt 文件采用 UTF-8 编码,并由每个 Unicode 代码点的一行信息组成。每行包含一个以分号分隔的字段列表,其中第一个字段是十六进制的 Unicode 代码点(没有前缀),第二个字段是字符名称。有关文件和每行包含的其他字段的信息可以在这里找到:有关 UCD 格式的信息可以在这里找到:http://www.unicode.org/reports/tr44/#Format_Conventions

一旦您使用上述代码构建了字符到字符名称的映射,您只需从映射中检索它们,如下所示:

char c = 'Â';
string character_name;
if (!charname_map.TryGetValue( c, out character_name ))
    character_name = "<Character Name Missing>"; //character not found in map
//character_name should now contain "LATIN CAPITAL LETTER A WITH CIRCUMFLEX";

我建议将 UnicodeData.txt 文件嵌入到您的应用程序资源中,并将此代码包装到一个类中,该类在静态初始化程序中加载和解析文件一次。为了使代码更具可读性,您可以在该类“char”类中实现扩展方法,例如“GetUnicodeName”。我特意将值限制在 0 到 0xFFFF 的范围内,因为这是 .NET UTF-16 字符所能容纳的全部内容。 .NET char 实际上并不代表真正的“字符”(也称为代码点),而是 Unicode UTF-16 代码单元,因为某些“字符”实际上需要两个代码单元。这样一对代码单元称为高和低代理。高于 0xFFFF(16 位字符可以存储的最大值)的值在基本多语言平面 (BMP) 之外,根据 UTF-16 编码需要两个 chars 进行编码。在此实现中,作为代理对的一部分的各个代码将以“非私人使用高代理”、“私人使用高代理”和“低代理”等名称结束。

【讨论】:

【参考方案3】:

如果您使用进程监视器查看charmap.exe 访问的文件,您会看到它打开了一个名为C:\Windows\system32\getuname.dll 的文件。该文件在其资源中包含角色名称(实际上资源本身位于特定文化子目录中的 .mui 文件中)。

所以您所要做的就是使用LoadString API 从此文件中获取名称。我写了一个辅助类来做到这一点:

public class Win32ResourceReader : IDisposable

    private IntPtr _hModule;

    public Win32ResourceReader(string filename)
    
        _hModule = LoadLibraryEx(filename, IntPtr.Zero, LoadLibraryFlags.AsDataFile | LoadLibraryFlags.AsImageResource);
        if (_hModule == IntPtr.Zero)
            throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());
    

    public string GetString(uint id)
    
        var buffer = new StringBuilder(1024);
        LoadString(_hModule, id, buffer, buffer.Capacity);
        if (Marshal.GetLastWin32Error() != 0)
            throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());
        return buffer.ToString();
    

    ~Win32ResourceReader()
    
        Dispose(false);
    

    public void Dispose()
    
        Dispose(true);
        GC.SuppressFinalize(this);
    

    public void Dispose(bool disposing)
    
        if (_hModule != IntPtr.Zero)
            FreeLibrary(_hModule);
        _hModule = IntPtr.Zero;
    

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern int LoadString(IntPtr hInstance, uint uID, StringBuilder lpBuffer, int nBufferMax);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern bool FreeLibrary(IntPtr hModule);

    [Flags]
    enum LoadLibraryFlags : uint
    
        AsDataFile = 0x00000002,
        AsImageResource = 0x00000020
    

你可以这样使用它:

string path = @"C:\Windows\System32\getuname.dll";
using (var reader = new Win32ResourceReader(path))

    string name = reader.GetString(0xA9);
    Console.WriteLine(name); // Copyright Sign

【讨论】:

非常好(至少如果你手头有 Windows)。另见pinvoke.net/default.aspx/getuname/GetUName.html 优点是它内置在 Windows 中(甚至在 XP 上)。缺点是字符串是本地化的,并且在一个字符串中包含所有信息。它不是分别给我“名称”和“类别”信息,而是在一个字符串中返回所有信息。例如在西班牙语 Windows 上:“Letra latina mayúscula G con gancho”。为此,我更喜欢 Rik Hemsley 接受的答案。他的图书馆提供了更多信息。【参考方案4】:

它不是 .NET 的内置功能。您可以从 Charmap.exe 中找到,它会在状态栏中显示代码点名称。如果您在自己的程序中需要它,您可以将 Unicode Character Database 编译到您的应用程序中。

【讨论】:

【参考方案5】:

我认为 .NET 中没有内置任何东西来识别这个...但是有一个 Unicode character database。

【讨论】:

【参考方案6】:

正如 Hans Passant 和 MichaelBray 所说,.NET 没有提供任何内置功能来获取字符的 Unicode 名称。

您可以使用位于 http://unicode.org/ucd 的 Unicode 字符数据库 - 今天它包含所有 Unicode 5.2 字符的完整信息(附件 #44)。

另一种选择是使用 Windows 中的字符映射,您可以通过 Start\App Programs\Accessories\System Tools\Character Map (Win+R =>魅力图)

您还可以使用 Unicode 转换器工具,它是http://unicode.codeplex.com 上的一个开源工具,它还提供了一个用于获取信息的用户界面,以及它从 Unicode UCD(附件 #44)的使用。这个软件的主题是您可以将此应用程序的 EnterpriseAppUnit dll 添加到您的应用程序并使用提供的 API。

这个程序集包含一些静态方法,它们接受一个“字符”并返回名称、十六进制代码、十进制代码等。

【讨论】:

以上是关于在.Net中找出Unicode字符名称的主要内容,如果未能解决你的问题,请参考以下文章

本地化:如何将文化信息映射到脚本名称或 Unicode 字符范围?

找出icon-font图标的unicode字符码

如何在 unicode 形式之间进行转换:字符串、名称、数字

来自字符的 UNICODE 名称

iOS应用程序名称中的Unicode字符?

PHP Pear Mail 无法发送带有 Unicode 字符的名称