手动在ASCII和.NET字符之间进行转换

6

我正在编写代码来清理用户输入到我的ASP.NET站点的文本。我需要清理输入以删除所有对ASCII字符145、146、147和148的引用,这些字符有时会从我的Mac用户复制并粘贴在他们的Mac上的字处理器中。

我的问题是下面这三个字符串应该输出相同的文本。

string test1 = Convert.ToChar(147).ToString();
string test2 = String.Format("'{0}'", Convert.ToChar(147));

char[] characters = System.Text.Encoding.ASCII.GetChars(new byte[] { 147 });
string test3 = new string(characters);

然而,当我将ASP TextBox设置为以下内容时:

txtShowValues.Text = test1 + "*" + test2 + "*" + test3;

我得到了test1的空值,test2正常工作,而test3输出为'?'。
有人能解释一下发生了什么不同的事情吗?我希望这可以帮助我理解.NET如何对128以上的字符使用ASCII值,以便我可以编写一个好的清洗脚本。
编辑 我提到的值(145-148)是卷曲引号。所以单引号左、单引号右、双引号左、双引号右。
“正常工作”意味着它在我的浏览器中输出一个卷曲引号。
第二次编辑 以下代码(在答案中提到)也输出卷曲引号。所以也许问题出在test 3中使用ASCII。
char[] characters2 = System.Text.Encoding.Default.GetChars(new byte[] { 147 });
string test4 = new string(characters2);

第三次编辑
我找到了一台可以借用的 Mac 电脑,并成功复制了出现问题的情况。当我从 Word 中复制并粘贴带有引号符号的文本到 Mac 上的 Web 应用程序中时,它会粘贴弯曲的引号(147 和 148)。当我保存后,数据库中将保存弯曲的引号,因此我将使用你们帮助我的代码来清理该内容。

第四次编辑
根据这里的回答编写了更多的示例代码,并注意到这与 ASP.NET 中的多行文本框有关。这里有很好的信息,所以我决定开一个新的问题:ASP.NET 多行文本框允许输入高于 UTF-8


但是为什么test2可以工作呢?如果说,我更期望test3能够正常运行。 - Justin C
“works correctly” 是什么意思?这是一个不可见的控制字符 - 它应该显示为空字符串。你期望输出什么? - Mark Byers
字符145是什么?它是字母还是某种图形? - John Knoeller
2
你在 #2 周围加了两个单引号。也许 test2 会打印 '',这很容易与“混淆。 - Greg
3个回答

11

第147个字符是U+0093 SET TRANSMIT STATE。与范围在0-255的所有Unicode字符一样,它与相同编号的ISO-8859-1字符相同。ISO-8859-1将147分配给此不可见的控制代码。

你所考虑的不是“ASCII”甚至不是“ISO-8859-1”,而是Windows代码页1252。这是一种非标准编码方式,类似于8859-1,但将字符128-159分配给各种印刷扩展,如智能引号,而不是大部分无用的控制代码。在代码页1252中,字符147是,也就是U+201C左双引号。

如果你想将Windows代码页(通常误称为“ANSI”)转换为Unicode字符,你需要指定所需的代码页,例如:

System.Text.Encoding.getEncoding(1252).GetChars(new byte[] { 147 })

System.Text.Encoding.Default会给你服务器上的默认编码。对于西欧地区的服务器,这将是1252。在其他地方,它不会是1252。通常不建议在服务器应用程序中使用语言环境的默认代码页。

无论如何,你不应该获取表示输入中的一些字符,如147代表"。如果出现这种情况,那只有当你的页面本身处于1252编码时才会发生。(而且更令人困惑和误导的是,当你说你的页面是以ISO-8859-1格式时,浏览器将自动使用1252代码页)。如果没有为页面指定任何编码,则页面可能也存在于1252中(浏览器猜测;其他语言环境将猜测不同的代码页,所以这会是一个大混乱)。

确保在Web应用程序中使用UTF-8进行所有编码,并标记你的页面为UTF-8。今天,所有的Web应用程序都应该使用UTF-8。


@bobince - 非常有用的信息,非常感谢。不知道您是否有关于这种问题的文档链接?在实施修复之前,我只是尽可能多地了解这个问题。 - Justin C
通常在这个时候,人们会引用Spolsky的文章!(http://www.joelonsoftware.com/articles/Unicode.html)...我对其中的一些内容持保留意见,但我想这是一个足够合理的入门指南。 - bobince
@Bobince - 有没有可能用户从字处理器中复制并粘贴内容到网页界面?这是一个相当罕见的问题,但我采访过的每个用户都说他们在Mac上从他们的文字处理器中复制和粘贴。 - Justin C
1
Web浏览器DOM的整个内容模型,包括input.value,本质上是基于Unicode的。粘贴到输入字段中的字符将始终按照页面声明的charset进行编码提交,因此如果页面以cp1252编码,则为字节0x93,如果以UTF-8编码,则为字节0xE2、0x80、0x9C。虽然从UTF-8编码的页面提交真正的字符147(作为序列0xC2 0x93)在技术上是可能的,但很少有人会输入字符147。 - bobince
我更喜欢保留任何粘贴的“智能引号”或其他排版细节(如–,—)不变。尝试自动将直引号转换为智能引号通常是一个坏主意,因为这不是一个可靠的过程。我会关闭那个功能。无论如何,“擦洗”这些特定字符并不能带来任何好处;如果您的应用程序无法处理它们,那么它可能也无法处理任何其他非ASCII字符,这是需要修复的问题。 - bobince
显示剩余3条评论

3

.NET使用Unicode(UCS-2),对于小于128的值,它与ASCII相同。

ASCII不定义大于127的值。

我认为您可能在考虑ANSI,它将大于127的值定义为(大多数)欧洲语言所需的语言字符,或者OEM(原始IBM PC字符集),它将大于127的字符定义为(大多数)符号。

上面127个字符的差异被称为代码页或编码(因此System.Text.Encoding)。因此,如果您使用不同的编码,例如System.Text.Encoding.Default,则可以使测试3正常工作。

编辑:现在我们知道您想要的编码是ANSI,清楚了正在发生什么。

字符转换的规则是将无法在编码中表示的字符替换为其他字符 - 通常是一个方框。但是对于ASCII,没有方框字符,因此它使用?代替。这就解释了测试3。

test1和2都使用Convert.ToChar与整数常量。这将把输入解释为UNICODE字符,而不是ANSI字符,因此没有应用任何转换。 Unicode字符147是一个非打印字符。


0

我在控制台应用程序(.NET 3.5SP1)中针对这三个字符得到问号。 就我所知,它们都应该是等效的。 John Knoeller 关于 ASCII vs ANSI 是正确的。

您是否尝试过在原始字符串上使用 Encoding 类的 GetBytes() 方法,并迭代遍历并删除(通过将“好”的字节复制到另一个缓冲区)不想要的值?

例如(使用 Linq):

byte[] original = System.Text.Encoding.ASCII.GetBytes(badString);
byte[] clean = (from b in original where b < 145 || b > 148 select b).ToArray<byte>();
string cleanString = System.Text.Encoding.ASCII.GetString(clean);

说实话,在这里使用ASCII可能不是一个好主意;如果原始文本是Unicode,那么它有可能做出一些错误的操作(例如,如果你传递了UTF-16)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接