2

对于每个 ASCII 字符,我需要的是一个等价的 Unicode 字符列表。

问题在于,当人们在文档中键入内容时,Microsoft Excel 和 Word 等程序会插入非 ASCII 双引号、单引号、破折号等。我想将此文本存储在“varchar”类型的数据库字段中,该字段需要单字节字符。

为了存储 ASCII(单字节)文本,其中一些 Unicode 字符可以被认为与特定 ASCII 字符等效或足够相似,因此将 Unicode 字符替换为等效的 ASCII 字符就可以了。

我想要一个像 MapToASCII 这样的简单函数,它将 Unicode 文本转换为 ASCII 等价物,允许我为与任何 ASCII 字符不相似的任何 Unicode 字符指定替换字符。

4

2 回答 2

1

Win32 API WideCharToMultiByte可用于此转换(Unicode 到 ANSI)。使用 CP_ACP 作为第一个参数。这样的事情可能比尝试构建自己的映射功能更好。

编辑冒着听起来像是我试图将其作为一种违背 OP 意愿的解决方案来推广的风险,似乎值得指出的是,这个 API 做了很多(全部?)所要求的事情。目标是(我认为)尽可能多地将 Unicode 字符串映射到“ANSI”(在这种情况下,ANSI 可能是一个移动的目标)。另一个要求是能够为那些无法映射的字符指定一些替代字符。以下示例执行此操作。它将 Unicode 字符串“转换”为char并使用下划线(倒数第二个参数)来表示那些无法转换的字符。

ret = WideCharToMultiByte( CP_ACP, 0, L"abc個חあЖdef", -1, 
                           ac, sizeof( ac ), "_", NULL );
for ( i = 0; i < strlen( ac ); i++ )
  printf( "%c %02x\n", ac[i], ac[i] );
于 2011-04-13T14:50:35.053 回答
0

这里有一个高度相关的问题:Replaceing unicode punctuation with ASCII approximations

虽然那里的答案不够充分,但它给了我一个想法。我可以将基本多语言平面 (0) 中的每个 Unicode 代码点映射到等效的 ASCII 字符(如果存在)。下面的 C# 代码将有助于创建一个 HTML 表单,您可以在其中为每个值键入一个替换字符。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.IO;

namespace UnicodeCharacterCategorizer
{
    class Program
    {
        static void Main(string[] args)
        {
            string output_filename = "output.htm"; //set a filename if not specifying one through the command line
            Dictionary<UnicodeCategory,List<char>> category_character_sets = new Dictionary<UnicodeCategory,List<char>>();
            foreach (UnicodeCategory c in Enum.GetValues(typeof(UnicodeCategory)))
                category_character_sets.Add( c, new List<char>() );
            for (int i = 0; i <= 0xFFFF; i++)
            {
                if (i >= 0xD800 && i <= 0xDFFF) continue; //Skip ranges reserved for high/low surrogate pairs.
                char c = (char)i;
                UnicodeCategory category = char.GetUnicodeCategory( c );
                category_character_sets[category].Add( c );
            }
            StringBuilder file_data = new StringBuilder( @"<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd""><html xmlns=""http://www.w3.org/1999/xhtml""><head><title>Unicode Category Character Sets</title><style>.categoryblock{border:3px solid black;margin-bottom:10px;padding:5px;} .characterblock{display:inline-block;border:1px solid grey;padding:5px;margin-right:5px;} .character{display:inline-block;font-weight:bold;background-color:#ffeeee} .numericvalue{color:blue;}</style></head><body><form id=""charactermap"">" );
            foreach (KeyValuePair<UnicodeCategory,List<char>> entry in category_character_sets)
            {
                file_data.Append( @"<div class=""categoryblock""><h1>" + entry.Key.ToString() + ":</h1><br />" );
                foreach (char c in entry.Value)
                {
                    string hex_value = ((int)c).ToString( "x" );
                    file_data.Append( @"<div class=""characterblock""><span class=""character"">&#x" + hex_value + @";<br /><span class=""numericvalue"">" + hex_value + @"</span><br /><input type=""text"" name=""r_" + hex_value + @""" /></div>" );
                }
                file_data.Append( "</div>" );
            }
            file_data.Append("</form></body></html>" );
            File.WriteAllText( output_filename, file_data.ToString(), Encoding.Unicode );
        }
    }
}

具体来说,该代码将生成一个 HTML 表单,其中包含 BMP 中的所有字符,以及以前缀为“r_”的十六进制值命名的输入文本框(r 代表“替换值”)。如果将此移植到 ASP.NET 页面,则可以编写附加代码以尽可能多地预填充替换值:

  • 如果已经是 ASCII,则使用它们自己的值,或者
  • 使用 Unicode 规范化 FormD 或 FormKD 分解等效项,或
  • 整个类别的单个 ASCII 值(即所有带有 ASCII 双引号的“标点首字母”字符)

然后,您可以手动进行调整并进行调整,并且可能不会像您想象的那样花很长时间。只有 64512 个代码点,整个类别的大块可能会被视为“甚至不接近任何 ASCII”。所以,我要建立这个地图和功能。

于 2011-04-14T18:36:15.757 回答