网页中的编码与乱码(1)--概述

授人以鱼不如授人以渔, 在这里我会告诉有关网页中的编码的一些事实与结论, 但我更希望传达给你分析问题的方法, 当你遇到乱码困扰时, 你能够独立迅速地分析并解决问题.

在之前谈了很多关于 字符集编码与乱码 的基础知识, 可以说, 如果你掌握了这些, 对于各种乱码问题, 就有了一个良好的基础, 基本能够分析甚至独立地解决各类的乱码问题.

自然, 基础问题的重要性无需多言, 但另一方面, 具体的问题也同样很重要. 据我的观察, 具体的问题有很多是关于 web 开发方面所碰到的乱码, 尽管从原理方面来说, 道理都是一样的, 但导致问题产生的许多细节还是值得一说的, 所以这次也打算具体谈谈这些方面.

首先谈网页中的编码与乱码问题, 之后还会谈表单的编码, 后台接收参数时的解码与乱码, url(uri) 的编码与解码, 文件下载中文件名的编码乃至数据库中的编码等等.

这些具体问题的分析要建立在字符集编码基础知识之上, 所以, 如果你觉得自己在基础方面还不够扎实,

比如, 字符集与编码的联系与区别是什么? Unicode 具体是如何编码的? 几种 Unicode 编码实现间的联系与区别是什么? 什么是 UTF-16 的代理对等等,

如果你尚不能很清晰地回答以上一些问题, 那么我还是建议你先看看那些基础的介绍, 这样在分析 web 开发中遇到的具体编码及乱码问题时, 理解得会更好.

继续阅读

在开发者工具中查看响应头的字符集编码信息

介绍了如何在浏览器的开发者工具中查看响应头(Response Headers)下的 Content-type 中的字符集编码信息

要想查看某个文档的响应头中的字符集编码信息, 以 Chrome 浏览器为例, 首先打开"开发者工具":

可以按快捷键 F12, 或单击窗口右上角的选项按钮, 然后选择 "更多工具--开发者工具"即可打开"开发者工具"窗口.

如下图打开 我的网站 为例所示:

开发者工具

缺省情况下显示在原窗口下面, 可以选择最右边三个竖点的按钮, 然后在 dock side 中选择不同的显示位置.

继续阅读

非 BMP 字符判断及判断字符串中是否包含非 BMP 字符

判断一个字符是 BMP 字符还是非 BMP 字符(增补字符), 以及判断字符串中是否包含非 BMP 字符.

在 Java 中, 要判断一个字符是否为增补字符, 也即所谓的非 BMP 字符, 可以综合使用 String 类中的 codePointAtCharacter 类中的 isSupplementaryCodePoint 方法, 具体如下:

@Test
public void testSupplementaryCodePoint() throws Exception {
	// 一个非 BMP 字符
	String s = "𧿹";
	// 长度为 2
	assertThat(s.length()).isEqualTo(2);
	// 属于增补字符
	assertThat(Character.isSupplementaryCodePoint(s.codePointAt(0))).isTrue();
}

当然也可以简单地尝试将这个字符赋值给一个 char 变量, char 变量只能接受一个 BMP 字符, 如果是非 BMP 字符, 则编译不通过. 如果是一串的字符, 想知道其中是否存在非 BMP 字符, 则可以使用 codePointCount 方法:

@Test
public void testCodePointCount() throws Exception {
	String normalStr = "hi你";
	String strContainNoneBMP = "h𧿹你";
	
	// 两者的 length 不同
	assertThat(normalStr.length()).isEqualTo(3);
	assertThat(strContainNoneBMP.length()).isEqualTo(4);
	
	// 两者的码点数( code point count)却是相同的
	assertThat(normalStr.codePointCount(0, normalStr.length())).isEqualTo(3);
	assertThat(strContainNoneBMP.codePointCount(0, strContainNoneBMP.length())).isEqualTo(3);
}

继续阅读

Java 语言中一个字符占几个字节?

一个字符占几个字节? 很多人喜欢问这个问题, 遗憾的是他们没有意识到这其实是一个糟糕的问题, 因为它缺乏了必要的前提...

这是一个来自知乎上的问题, https://www.zhihu.com/question/27562173 , 提问者问:

Java 中理论说是一个字符(汉字 字母)占用两个字节. 但是在 UTF-8 的时候 new String("字").getBytes().length 返回的是 3 表示 3 个字节 小白求回答. .

严格地讲, 这个问题本身就是有问题的, 因为它缺少了前提, 在我的回答中我也强调了这一点, 回答具体如下:

首先, 你所谓的"字符"具体指什么呢? 如果你说的"字符"就是指 Java 中的 char, 那好, 那它就是 16 位, 2 字节.

如果你说的"字符"是指我们用眼睛看到的那些"抽象的字符", 那么, 谈论它占几个字节是没有意义的.

具体地讲, 脱离具体的编码谈某个字符占几个字节是没有意义的.

继续阅读

文本在内存中的编码(3)--String 的转换--乱码探源(6)

摘要: 探讨了 String 到 byte[] 的转换, 并结合之前的 new String 作了综合分析.

先讲个小故事, 虽然跟主题有点不太相关哈:

唐朝诗人李绅, 身为官员, 脾气暴躁, 瞧不起信教的, 尤其鄙视装逼之僧人, 动不动就对他们拳脚相加. 曾扬言: "我可以接见他们, 要能答出来还好, 要是答不出来, 我弄死他!" 有一回一个和尚来跟他宣传因果报应, 李绅问: "阿师从哪里来, 到哪里去呢?" 僧答: "贫僧从来处来, 到去处去." 李绅当时就急了, 撸起袖子, 亮出了手腕: "我去年买了个表!"

来自知乎问答"古人是如何「装逼」的? ", 略有改动.

String 到哪里去?

有了前面僧人的教训, 在这里就不故弄玄虚了, 应该说 String 的去处还是蛮确定的, 那就是到 byte[] 中去, 方式就是通过 getBytes 这一方法.

new String 与 getBytes

如果说 new String(byte[], encoding) 是从 byte[] 到 String 的过程, 那么 getBytes(encoding) 则正好与之相反: 它是从 String 到 byte[] 的过程.

string and getbytes conversion

或许我们应该说: 它从去处来, 又到来处去.

继续阅读