【问题标题】:TextWriter.ReadToEnd vs. Unix wc CommandTextWriter.ReadToEnd 与 Unix wc 命令
【发布时间】:2009-07-23 02:20:25
【问题描述】:

另一个问题。 Unicode、终端,现在是 C# 和 wc。如果我写这段简单的代码

  int i=0;
  foreach(char c in Console.In.ReadToEnd())
  {
    if(c!='\n') i++;
  }
  Console.WriteLine("{0}", i);

并只输入字符“€”(utf-8 中的 3 个字节),wc 返回 3 个字符(可能使用 wint_t,虽然我没有检查),但 ReadToEnd() 返回 1(一个字符) .在这种情况下,ReadToEnd 的行为究竟是什么?我怎么知道ReadToEnd在幕后做什么?

我正在运行使用 utf-8.en.US 初始化的 xterm,运行 Ubuntu Linux 和 Mono。

谢谢。

【问题讨论】:

    标签: c# c unicode mono


    【解决方案1】:

    wc 和大多数类似 unix 的命令根据 C char 数据类型处理字符,该数据类型通常是无符号的 8 位整数。 wc 只是从标准输入中逐个读取字节,不做任何转换,确定有 3 个字符。

    .NET 根据其自己的 Char 数据类型处理字符,该数据类型是 16 位无符号整数并表示 UTF-16 字符。控制台类已收到 3 个字节的输入,确定它所连接的控制台是 UTF-8 并且已正确地将它们转换为单个 UTF-16 欧元字符。

    【讨论】:

    • 所以,快速跟进问题。如果我用 C 语言编写相同的程序,使用 wchar 或 wint_t 我会浪费(两次)空间。在这种情况下,它是微不足道的,因为它只有 16 位,但在巨大的文件中,差异是显而易见的。这是正确的吗?
    • 视情况而定。如果您正在处理英文文本,8 位字符类型和 Latin-1 或 UTF-8 编码可能会占用最少的空间。如果您正在处理中文或日文文本,UTF-8 的效率将低于其他编码,Latin-1 将根本无法表示您的文本。为此,使用 UTF-16、UCS-2 或一种特定于语言的编码会更紧凑。另请注意,使用字符具有可变字节数的编码也更加复杂。选择更紧凑的编码可能会使您的文本处理速度变慢。
    【解决方案2】:

    您需要考虑字符编码。目前您只是在计算字节数,chars 和 bytes 的大小不一定相同。

    Encoding encoding = Encoding.UTF8;
    string s = "€";
    
    int byteCount = encoding.GetByteCount(s);
    Console.WriteLine(byteCount); // prints "3" on the console
    
    byte[] bytes = new byte[byteCount];
    encoding.GetBytes(s, 0, s.Length, bytes, 0);
    int charCount = encoding.GetCharCount(bytes);
    Console.WriteLine(charCount); // prints "1" on the console
    

    【讨论】:

      【解决方案3】:

      ReadToEnd 返回一个字符串。 .NET 中的所有字符串都是 Unicode。它们不仅仅是一个字节数组。

      显然,wc 正在返回字节数。字节数和字符数曾经是一回事。

      【讨论】:

        【解决方案4】:

        wc 默认返回文件中的行数、字数和字节数。如果您想根据活动区域设置的编码返回字符数,而不仅仅是字节数,那么您应该查看现代wc 具有的-m--chars 选项。

        【讨论】:

          猜你喜欢
          • 2020-05-10
          • 1970-01-01
          • 1970-01-01
          • 2017-01-12
          • 1970-01-01
          • 2012-01-28
          • 2014-10-10
          • 2014-01-02
          • 1970-01-01
          相关资源
          最近更新 更多