【问题标题】:C# String confusion compared to Java与 Java 相比,C# 字符串混淆
【发布时间】:2014-04-19 21:41:13
【问题描述】:

作为一名尝试进入 C# 的 Java 开发人员,我感到很困惑。我已经阅读了有关字符串类型的信息,它是不可变的,与 java 没有太大区别,只是它似乎不像那里的对象,但无论如何我都会有奇怪的行为。我在一个类上有以下 toString 方法

    public override string ToString()
    {
        StringBuilder builder = new StringBuilder();

        builder.Append("BlockType: ");
        builder.Append(BlockType + "\n");
        //builder.Append(System.Text.ASCIIEncoding.ASCII.GetChars(Convert.FromBase64String("dHh0AA==")));
        //builder.Append("\n");
        builder.Append("BlockName: ");
        builder.Append(BlockName + "\n");
        //builder.Append(System.Text.ASCIIEncoding.ASCII.GetChars(Convert.FromBase64String(this.BlockName)));
        //builder.Append("\n");
        builder.Append("BlockLength: " + this.BlockLength + "\n");
        builder.Append("pBlockData: " + this.pBlockData + "\n");
        return builder.ToString();
    }

当我用数据填充它时。考虑到 BlockType 和 BlockName 将包含一个 Base64 字符串。我得到以下结果

FileVersionNo: 0
nx: 1024
ny: 512
TileSize: 256
HorizScale: 10
Precis: 0,01
ExtHeaderLength: 35
nExtHeaderBlocks: 1
pExtHeaderBlocks: System.Collections.Generic.LinkedList`1[LibFhz.HfzExtHeaderBlock]

BlockType: dHh0AA==
BlockName: YXBwLW5hbWUAAAAAAAAAAA==
BlockLength: 11
pBlockData: System.Byte[]

这正是我想要的完美,但是当我尝试获取那些 Base64(或 UTF-8,我都尝试过)的 ASCII 值时,我得到以下结果

FileVersionNo: 0
nx: 1024
ny: 512
TileSize: 256
HorizScale: 10
Precis: 0,01
ExtHeaderLength: 35
nExtHeaderBlocks: 1
pExtHeaderBlocks: System.Collections.Generic.LinkedList`1[LibFhz.HfzExtHeaderBlock]

BlockType: txt

代码似乎停止了,没有错误或堆栈跟踪。我不知道发生了什么。我首先认为缺少一个 \0 所以我已经将它添加到字符串中,然后我认为我需要一个 \r\n ...再次不是解决方案,我开始与只想知道如何做的人一起搜索Bas64 到 UTF-8 的转换......但这部分似乎很简单......这个代码停止不是。

任何关于 .net 中字符串处理的见解或链接都将不胜感激

【问题讨论】:

  • Convert.FromBase64String() 可能会返回二进制零值,这些值将被转换为 ASCII NULL 字符。我想这可能会弄乱输出。你期待什么输出?
  • base64 字符串通常没有有意义的 ASCII 值。如果是这样,那么一开始就没有理由对其进行编码,所以这看起来很奇怪。
  • BlockType: txt BlockName: app-name 是 Base64 内容的可读文本值,但您的二进制零值建议可能是罪魁祸首。小注意变量的内容被这个字符串填充了 blockName = Convert.ToBase64String(reader.ReadBytes(16));, 从流中读取的字节

标签: c# string utf-8 base64 ascii


【解决方案1】:

第一个

builder.Append("pBlockData: " + this.pBlockData + "\n");

不做你认为它做的事,特别是如果 pBlockData 是一个字节数组,你会得到这样的东西(从 scriptcs 输出):

> byte[] data = new byte[11];
> StringBuilder sb  = new StringBuilder();
> sb.Append("data = ")
{Capacity:16,MaxCapacity:2147483647,Length:7}
> sb.Append(data);
{Capacity:32,MaxCapacity:2147483647,Length:20}
> sb.ToString()
data = System.Byte[]

第二个 C# 字符串(通常是 .NET 字符串)是 UTF-16,因此它并不真正知道如何处理显示字节。它是 bas64 编码还是 ASCII 或法国泡菜都没关系 ;-) 运行时只是将其视为二进制。也不需要空终止,字符串的长度作为字符串对象的属性保存。

所以你需要在输出之前将你拥有的字节数组转换为 UTF-16 字符数组或字符串。如果字节数组包含有效的 ASCII,您可以查看 'System.Text.ASCIIEncoding.ASCII.GetDecoder().Convert' 方法作为完成此操作的一种方法。

【讨论】:

  • 谢谢,这可能会帮助我在源头做到这一点:string blockName = Convert.ToBase64String(reader.ReadBytes(16));是当前来源,所以我可以在这里将其读入 UTF-16。尽管这仍然可能保留 \0,但文件的这一部分始终是 16 字节长的空终止,我只记得文件规范中的这一点!
  • 如果有 16 个字节可用,阅读器将读取它们,如果其中包含一个或多个 \0 值,它也会读取这些值。由于 Unicode 还包含一个空终止字符作为有效值,因此这些字符应出现在“blockName”字符串中,并将计为字符串总长度的一部分。
  • 好的,如果是数据,我不应该触摸 \0,因为它们是数据的一部分。但是对于表示,那么剥离它们并没有错。谢谢,这很有启发性
【解决方案2】:

我看看你从中得到了什么:

var test = Convert.FromBase64String("YXBwLW5hbWUAAAAAAAAAAA==");
var builder = new StringBuilder();
builder.Append(System.Text.Encoding.ASCII.GetChars(test));

答案是字符串“app-name”,末尾带有空 (0) 个字符。

您可以尝试通过在返回 builder.ToString() 之前添加此行来删除所有空字符:

builder.Replace("\0", null);

这可能有帮助,也可能没有帮助,具体取决于您对返回的字符串所做的操作。

【讨论】:

  • 谢谢这是解决方案。我将返回的字符串用作 toString,因此人们可以在使用 Class 时在调试中读取 Class 对象,而不是用于任何其他有意义的处理(否则我只会保留 Base64)
猜你喜欢
  • 1970-01-01
  • 2014-04-15
  • 2017-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-20
  • 1970-01-01
相关资源
最近更新 更多