【问题标题】:How to Generate all the characters in the UTF-8 charset in .net如何在 .net 中生成 UTF-8 字符集中的所有字符
【发布时间】:2010-12-12 17:15:20
【问题描述】:

我的任务是生成 UTF-8 字符集中的所有字符,以测试系统如何处理每个字符。我对字符编码没有太多经验。我要尝试的方法是增加一个计数器,然后尝试将该基数为 10 的数字转换为等效的 UTF-8 字符,但到目前为止,我还没有在 C# 3.5 中找到有效的方法

任何建议将不胜感激。

【问题讨论】:

  • Unicode 标准中有 1,112,064 个代码点。您真的要生成所有这些吗?
  • 感谢您的反馈,这大大澄清了事情。为了更好地解释我的任务,我正在测试一项似乎对某些汉字感到窒息的服务。因此决定我们应该能够测试所有外来字符,因为系统需要能够处理各种国际语言。我正在寻找一种简单有效的解决方案,它不会花费很长时间来创建并具有最大的覆盖范围。

标签: c# .net utf-8 character-encoding


【解决方案1】:

Powershell 代码,我将 Jake 建议的代码中的行放在一个 256 行长的文本文件中。

服务符号创建两个在原始文本中不存在的空行,必须在原始文本文件中删除它们才能进行 Powershell 处理,以便正确创建结果文件。

我将在这里发布 ASC2 部分的外观。

NUL SOH STX ETX EOT ENQ ACK BEL BS TAB LF VT FF CR SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US Space ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; ? @ABCDEFGHIJKLMNOPQRSTU VWXYZ [ \ ] ^ _ ` abcdefghijklmnopqrstu vwxyz { | } ~ PAD HOP BPH NBH IND NEL SSA ESA HTS HTJ VTS PLD PLU RI SS2 SS3 DCS PU1 PU2 STS CCH MW SPA EPA SOS SGCI SCI CSI ST OSC PM APC Non-breakspace ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Û Û Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ

在初始文件中,每个字符将换行。

最好使用记事本++查看服务符号。最好用手用文字代替。

包含另外两个服务符号,就在 asc2 部分的下方和末尾 - 很多。

但是,要欣赏彩色表情符号,您只需将喜欢的文本复制到 Word 或社交网络中即可。 Word 比记事本更好地解释字符,但比网站更差。

$arrayFromFile = [IO.File]::ReadAllLines('C:\utf-8.txt')
$counter = [pscustomobject] @{ Value = 0 }
$groupSize = 256
$text=''
$groups = $arrayFromFile | Group-Object -Property { [math]::Floor($counter.Value++ / $groupSize) }
foreach ($group in $groups){
    $text+=$group.Group -join (' ')
    $text+="`n"
}
$text | Out-File -FilePath 'C:\utf-8 (sorted).txt'

【讨论】:

    【解决方案2】:

    您可以暴力破解Encoding 来确定它支持哪些代码点。为此,只需遍历所有可能的代码点,将它们转换为字符串,然后查看Encoding.GetBytes() 是否抛出异常(在将Encoding.EncoderFallback 设置为EncoderExceptionFallback 之后)。

    IEnumerable<int> GetAllWritableCodepoints(Encoding encoding)
    {
        encoding = Encoding.GetEncoding(encoding.WebName, new EncoderExceptionFallback(), new DecoderExceptionFallback());
    
        var i = -1;
        // Docs for char.ConvertFromUtf32() say that 0x10ffff is the maximum code point value.
        while (i != 0x10ffff)
        {
            i++;
    
            var success = false;
            try
            {
                encoding.GetByteCount(char.ConvertFromUtf32(i));
                success = true;
            }
            catch (ArgumentException)
            {
            }
            if (success)
            {
                yield return i;
            }
        }
    }
    

    此方法应支持在 .net 中发现由 Char 的代理对表示的字符。但是,它非常慢(在我的机器上运行需要几分钟)并且可能不切实际。

    【讨论】:

      【解决方案3】:

      此代码将在文件中生成输出。所有可打印或不可打印的字符都将在其中。

      Encoding enc = (Encoding)Encoding.GetEncoding("utf-8").Clone();
      enc.EncoderFallback = new EncoderReplacementFallback("");
      char[] chars = new char[1];
      byte[] bytes = new byte[16];
      
      using (StreamWriter sw = new StreamWriter(@"C:\utf-8.txt"))
      {
          for (int i = 0; i <= char.MaxValue; i++)
          {
              chars[0] = (char)i;
              int count = enc.GetBytes(chars, 0, 1, bytes, 0);
      
              if (count != 0)
              {
                  sw.WriteLine(chars[0]);
              }
          }
      }
      

      【讨论】:

      • 太棒了。甚至不必打开VS。我用脚本编译了代码。它立即开始工作,立即准确,几乎就像直接“开箱即用”
      【解决方案4】:

      这将为您提供一个字符集中的所有字符 - 只需确保在指定编码时指定一个字符集:

      var results = new ConcurrentBag<int> ();
      Parallel.For (0, 10, set => {
          var encoding = Encoding.GetEncoding ("ISO-8859-1");
          var c = encoding.GetEncoder ();
          c.Fallback = new EncoderExceptionFallback ();
          var start = set * 1000;
          var end = start + 1000;
          Console.WriteLine ("Worker #{0}: {1} - {2}", set, start, end);
      
          char[] input = new char[1];
          byte[] output = new byte[5];
          for (int i = start; i < end; i++) {
              try {
                  input[0] = (char)i;
                  c.GetBytes (input, 0, 1, output, 0, true);
                  results.Add (i);
              }
              catch {
              }
          }
      });
      var hashSet = new HashSet<int> (results);
      //hashSet.Remove ((int)'\r');
      //hashSet.Remove ((int)'\n');
      var sorted = hashSet.ToArray ();
      Array.Sort (sorted);
      var charset = new string (sorted.Select (i => (char)i).ToArray ());
      

      【讨论】:

        【解决方案5】:
        System.Net.WebClient client = new System.Net.WebClient();
        string definedCodePoints = client.DownloadString(
                                 "http://unicode.org/Public/UNIDATA/UnicodeData.txt");
        System.IO.StringReader reader = new System.IO.StringReader(definedCodePoints);
        System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
        while(true) {
          string line = reader.ReadLine();
          if(line == null) break;
          int codePoint = Convert.ToInt32(line.Substring(0, line.IndexOf(";")), 16);
          if(codePoint >= 0xD800 && codePoint <= 0xDFFF) {
            //surrogate boundary; not valid codePoint, but listed in the document
          } else {
            string utf16 = char.ConvertFromUtf32(codePoint);
            byte[] utf8 = encoder.GetBytes(utf16);
            //TODO: something with the UTF-8-encoded character
          }
        }
        

        上面的代码应该遍历当前分配的 Unicode 字符。您可能希望在本地解析 UnicodeData 文件并修复我犯的任何 C# 错误。

        当前分配的 Unicode 字符集少于可以定义的集。当然,当您将其中一个字符打印出来时,您是否能看到一个字符取决于许多其他因素,例如字体和它在发送到您的眼球之前会经过的其他应用程序。

        【讨论】:

          【解决方案6】:

          没有“UTF-8 字符”。你是指Unicode字符还是Unicode字符的UTF-8编码?

          将 int 转换为 Unicode 字符很容易,当然前提是该代码存在映射:

          char c = (char)theNumber;
          

          如果你想要那个字符的 UTF-8 编码,那也不是很难:

          byte[] encoded = Encoding.UTF8.GetBytes(c.ToString())
          

          您必须检查 Unicode 标准才能查看定义了 Unicode 字符的数字范围。

          【讨论】:

            【解决方案7】:

            即使您生成了所有字符,您也会发现这不是一个有效的测试。一些字符是 combining 标记,这意味着它们将与紧随其后的下一个字符组合 - 一个充满组合标记的字符串没有多大意义。还有其他一些特殊情况。使用需要支持的语言的实际文本会更好。

            【讨论】:

              【解决方案8】:

              正如其他人所说,UTF / Unicode 是一种编码而不是字符集。

              如果您略读 http://www.joelonsoftware.com/articles/Unicode.html,它应该有助于澄清 unicode 是什么。

              【讨论】:

                【解决方案9】:

                UTF-8 不是字符集,它是一种编码。 Unicode 中的任何值都可以用不同字节长度的 UTF-8 编码。

                对于 .net,字符是 16 位的(它不是完整的 unicode 集,但最实用),所以你可以试试这个:

                 for (char i = 0; i < 65536; i++) {
                     string s = "" + i;
                     byte[] bytes = Encoding.UTF8.GetBytes(s);
                     // do something with bytes
                 }
                

                【讨论】:

                • 您的代码是正确的,但您的第二段具有误导性。 System.Char 是一个 16 位值,是的。但是 MSDN 明确指出 System.Char 是一个 UTF-16 代码点,这意味着它在技术上不是一个字符。有很多 Unicode 字符可以用 UTF-8 表示,其代码点高于 65536。你说“它不是最实用的完整 unicode 集”——我不确定这是真的,而且肯定是不是避免测试 U+FFFF 以上代码点的好理由。
                【解决方案10】:

                UTF-8 不是字符 - 它是一个字符encoding,它能够将Unicode 字符集中的任何字符编码为二进制数据。

                您能否提供更多有关您正在尝试做的事情的信息?您可以对所有可能的 Unicode 字符(包括目前未分配的字符)进行编码,但如果您需要处理基本多语言平面之外的字符(即 U+FFFF 以上的字符),那么它会变得有点棘手......

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-07-16
                  • 2021-09-24
                  • 1970-01-01
                  • 2012-01-14
                  • 2010-12-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多