En Dash 和 Guarded Area 字符的开始

En Dash and Start of Guarded Area characters

我想弄清楚为什么相同的源数据会根据我用来获取它的方法提供两个不同的输出字符串。

我有两个 CSV 文件,其中包含来自 QuickBooks 的数据。一个是使用 QuickBooks 的内置报告功能创建的,另一个是使用使用 QuickBooks SDK 的数据访问 API 创建的。在这两个 CSV 文件中,都有一个文本列,我应该可以将其用作关联所述文件中数据的键。

但是,两个文件似乎无法在特定行中的一个特定字符达成一致:

这会导致问题,因为我的代码认为这两个字符串不同(从技术上讲它们是不同的,但不应该),因此无法匹配它们。我确信一定有某种编码错误,但我在两个字符之间找不到任何 link。

我不希望有人能够弄清楚到底发生了什么,因为我们无法访问 QuickBooks 或 API 在幕后做的事情。但我希望有人能给我一些关于为什么这个角色被错误翻译的想法。

问题是他们(可能)在内部将破折号编码为 U+0096,这对应于 Windows-1252 byte (0x96) for en-dash, but in Unicode, it actually represents "Start of Guarded Area" special character

出于某些向后兼容的原因,网络浏览器将此字符转换为 U+2013 以便在网页上显示。

所以有两个问题 - QuickBooks 方面的错误编码和浏览器的混淆行为,即将字符从 windows-1252 转换为 Unicode。

关于这个问题有几个相关的问题:

  • Some UTF-8 characters do not show up on browser
  • Display \u0096 in a jsp
  • UTF-8 charecter - UC2-Decimal(150).How to handle this char?

rouckas的回答提醒我,我确实解决了这个问题。他基本上是对的,但问题与网络浏览器无关,所以我想我会提供我所做的修复工作。

据我所知,QuickBooks 实际上使用 windows-1252(这是从 QB 导出到文本文件时使用的编码)存储和输出其数据。但是,当通过基于 SDK 的 API 读取数据时,windows-1252 代码被错误地解释为 Unicode(QB SDK,第 3 方 API或 .NET Framework 本身;我无法知道)。

这在大多数情况下都有效,因为 0 到 127(包括英文字母表中的所有字母)的字符代码在两种编码之间是相同的。但是从 128 开始这两个方案不同,所以 windows-1252 中的 150 表示 "en-dash" 但在 Unicode 中它表示 "Start of Guarded Area".

为了纠正这个问题,我使用了以下代码:

Dim Builder As New Text.StringBuilder(Input)
For i = 0 To Builder.Length - 1
    Dim n = AscW(Builder(i))

    If n > 127 AndAlso n < 256 Then
        Dim b As Byte = n
        Builder(i) = System.Text.Encoding.Default.GetChars({b})(0)
    End If
Next

Return Builder.ToString

这会获取每个字符的字符代码(使用 AscW),如果代码在 127 和 256 之间(不包括)(255 是 windows-1252 中的最后一个字符),使用 windows-1252 编码正确解释它,然后将其正确转换为 Unicode。