无忧启动论坛

 找回密码
 注册
搜索
最纯净的「微PE装机优盘」UEPON大师作品系统gho:最纯净好用系统下载站数据恢复、数据保护、视频编辑
Win To Go 极致利器(IXUNCIS固态U盘)无忧启动网成立20周年!广告联系 QQ:184822951 微信:wuyouceo
查看: 1853|回复: 58
打印 上一主题 下一主题

[原创] UTF8 二进制扩展(utf8 binary extension)

    [复制链接]
跳转到指定楼层
1#
发表于 2021-3-20 09:31:48 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 不点 于 2021-3-24 18:36 编辑

由于不知道要发在哪里,所以就发在这里了;有鉴于 Linux 对 UTF8 的支持比较完善,而 Windows 的 cmd 命令行对 UTF8 的支持目前还没有,将来有没有,还不好说。【更正:Win10 的控制台支持 UTF8;XP 和 Win7 的控制台不支持 UTF8】

又由于是“摸着石头过河”,不知道要写多少个帖子,所以,先占位前 30 个楼层。

标题的含义,大家可以这么理解:《关于 UTF8 的思考》或《UTF8 的改进、完善、补充》

发帖的形式是“无定形”,想到哪,写到哪。就好比是“随笔”、“日记”、“博客”。

今天准备搜集一些基础资料,温习基本概念,作为铺垫。

好的,先搜到这个: https://www.crockford.com/utf8.html

全文照搬过来:


2019-06-24

UTF-8


UTF-8 is one of the smartest things I've seen. It is a byte stream encoding for simple values (like Unicode characters) that can be bigger than bytes. UTF-8 has some wonderful properties:

  • ASCII is a proper subset, so all ASCII encoded streams are also UTF-8 streams.
  • The first byte of a multi-byte character tells the number of bytes.
  • Continuation bytes are easily distinguished from first bytes.
  • The sort order is preserved, not that matters for Unicode.


A first byte can contain between 2 and 7 bits of data. A first byte also determines the number of continuation bytes. Each continuation byte carries 6 bits of data.
UTF-8 has one unfortunate disadvantage, that many 16-bit characters are encoded in 3 bytes. This disadvantage is more than offset by its advantages, and by having a single, simple encoding that can work in all languages and contexts. The benefits range from greater reliability to better security. That is why JSON recommends UTF-8. UTF-8 is the good stuff. Thank you, Ken Thompson.
In my own work, I use a formulation that works well with 32-bit characters.

BinaryHexThruRangeThruContinuation
Bytes
Total
Data Bits
0xxxxxxx007F
00
7F
0
7
10xxxxxx80BF
continuation
6
110xxxxxC0DF
80
7FF
1
11
1110xxxxE0EF
800
FFFF
2
16
11110xxxF0F7
1 0000
1F FFFF
3
21
111110xxF8FB
20 0000
3FF FFFF
4
26
111111xxFCFF
400 0000
FFFF FFFF
5
32


印象中,UTF8 只处理最低的 31 位,最高的那一位是留待以后扩展的,目前不处理。所以,上述表格的最后一行是不太准确的。准确的似乎应该是这样:

1111110xFCFD
400 0000
7FFF FFFF
5
31


不过,这个细节无关紧要,因为现实中很少需要用那么大的代码点。

字节序 —— Byte Order Mark

字节序是一个特殊的 Unicode 字符,它的码点是 U+FEFF,不是 U+FFFE。它的 UTF8 表示是 EF BB BF。有时候,我们需要死记硬背。怎么样才能记住它?需要有一些联想或技巧。我们试着把 U+FFFE 转为 UTF8 字节串:它的十六进制表示是 EF BF BE,它的二进制表示是 11101111 10111111 10111110。它是个偶数,因此末尾是 0。它比 U+FFFF 只小 1,所以,除了末尾是 0,其他位都是 1,全都撑满了(除非按照 UTF8 规范某位只能为 0)。总结一下有下面这些特征,可以帮助记忆:

1、BOM(U+FEFF)是个奇数,不是偶数。其末尾是 F 不是 E。
2、BOM(U+FEFF)距离 16 位最大值 U+FFFF 较远,因此,它不是 U+FFFE。
3、U+FFFE 是noncharacter(非字符),也就是没有对它进行定义,或者说,它不是个正常的字符。因此,BOM 不是它。
4、位于 U+FFF0 至 U+FFFF 之间的 16 个字符,属于“特殊字符”范围,而 BOM (U+FEFF)位于此范围之外,而且距离较远。
5、BOM(U+FEFF)中的两个字节是 8 位整数中最大的两个字节 FF 和 FE,不会是 EF,因此,不要误记为 U+FFEF 或 U+EFFF 之类的。
6、BOM(U+FEFF)只能是 U+FEFF 和 U+FFFE 两者之一,而 U+FFFE 距离最大值U+FFFF 太近,予以排除。
7、BOM(U+FEFF)距离 U+FF00 较近: FEFF = FF00 - 1。
8、BOM(U+FEFF)恰好位于末尾的 256 个字符之外,也就是说,紧贴着末尾的 256 个字符。(此处末尾是指 BMP 的末尾)。

零宽不断行空格——Zero Width No-Break Space

历史上,BOM 曾经是唯一一个“零宽不断行空格”,现在新增了一个零宽不断行字符 U+2060(其正式名称叫做 word joiner,单词贴合器),而 BOM 就主要用作“字节序标记符”了。

非字符—— Non-Characters

在 17 个平面(Planes)中,每个平面结尾的 2 个码点,都是 non-character。这样就有了 34 个非字符。而在基本多语言平面(BMP)中,又定义了 32 个 non-characters:U+FDD0 ~ U+FDEF
所以,总共有 66 个非字符。这 66 个非字符是程序员可以私自使用的字符,不能用于公共交换的目的。

拉丁 1 补充字符 —— Latin-1 Supplement

在 ASCII 之外的所有字符中,码点 U+0080 ~ U+00FF 显然最重要,它们在码值上位于传统单字节字符的范围(有时称为“扩展的 ASCII 字符”),但不幸的是在 UTF8 的表示中需要占用两个字节。

unicode
utf8
hex
binary
binary
hex
80
10000000
11000010 10000000
C2  80
81
10000001
11000010 10000001
C2  81
82
10000010
11000010 10000010
C2  82
83
10000011
11000010 10000011
C2  83
84
10000100
11000010 10000100
C2  84
85
10000101
11000010 10000101
C2  85
86
10000110
11000010 10000110
C2  86
87
10000111
11000010 10000111
C2  87
88
10001000
11000010 10001000
C2  88
89
10001001
11000010 10001001
C2  89
8A10001010
11000010 10001010
C2  8A
8B10001011
11000010 10001011
C2  8B
8C10001100
11000010 10001100
C2  8C
8D10001101
11000010 10001101
C2  8D
8E10001110
11000010 10001110
C2  8E
8F10001111
11000010 10001111
C2  8F
90
10010000
11000010 10010000
C2  90
91
10010001
11000010 10010001
C2  91
92
10010010
11000010 10010010
C2  92
93
10010011
11000010 10010011
C2  93
94
10010100
11000010 10010100
C2  94
95
10010101
11000010 10010101
C2  95
96
10010110
11000010 10010110
C2  96
97
10010111
11000010 10010111
C2  97
98
10011000
11000010 10011000
C2  98
99
10011001
11000010 10011001
C2  99
9A10011010
11000010 10011010
C2  9A
9B10011011
11000010 10011011
C2  9B
9C10011100
11000010 10011100
C2  9C
9D10011101
11000010 10011101
C2  9D
9E10011110
11000010 10011110
C2  9E
9F10011111
11000010 10011111
C2  9F
A010100000
11000010 10100000
C2  A0
A110100001
11000010 10100001
C2  A1
A210100010
11000010 10100010
C2  A2
A310100011
11000010 10100011
C2  A3
A410100100
11000010 10100100
C2  A4
A510100101
11000010 10100101
C2  A5
A610100110
11000010 10100110
C2  A6
A710100111
11000010 10100111
C2  A7
A810101000
11000010 10101000
C2  A8
A910101001
11000010 10101001
C2  A9
AA10101010
11000010 10101010
C2  AA
AB10101011
11000010 10101011
C2  AB
AC10101100
11000010 10101100
C2  AC
AD10101101
11000010 10101101
C2  AD
AE10101110
11000010 10101110
C2  AE
AF10101111
11000010 10101111
C2  AF
B010110000
11000010 10110000
C2  B0
B110110001
11000010 10110001
C2  B1
B210110010
11000010 10110010
C2  B2
B310110011
11000010 10110011
C2  B3
B410110100
11000010 10110100
C2  B4
B510110101
11000010 10110101
C2  B5
B610110110
11000010 10110110
C2  B6
B710110111
11000010 10110111
C2  B7
B810111000
11000010 10111000
C2  B8
B910111001
11000010 10111001
C2  B9
BA10111010
11000010 10111010
C2  BA
BB10111011
11000010 10111011
C2  BB
BC10111100
11000010 10111100
C2  BC
BD10111101
11000010 10111101
C2  BD
BE10111110
11000010 10111110
C2  BE
BF10111111
11000010 10111111
C2  BF
C011000000
11000011 10000000
C3  80
C111000001
11000011 10000001
C3  81
C211000010
11000011 10000010
C3  82
C311000011
11000011 10000011
C3  83
C411000100
11000011 10000100
C3  84
C511000101
11000011 10000101
C3  85
C611000110
11000011 10000110
C3  86
C711000111
11000011 10000111
C3  87
C811001000
11000011 10001000
C3  88
C911001001
11000011 10001001
C3  89
CA11001010
11000011 10001010
C3  8A
CB11001011
11000011 10001011
C3  8B
CC11001100
11000011 10001100
C3  8C
CD11001101
11000011 10001101
C3  8D
CE11001110
11000011 10001110
C3  8E
CF11001111
11000011 10001111
C3  8F
D011010000
11000011 10010000
C3  90
D111010001
11000011 10010001
C3  91
D211010010
11000011 10010010
C3  92
D311010011
11000011 10010011
C3  93
D411010100
11000011 10010100
C3  94
D511010101
11000011 10010101
C3  95
D611010110
11000011 10010110
C3  96
D711010111
11000011 10010111
C3  97
D811011000
11000011 10011000
C3  98
D911011001
11000011 10011001
C3  99
DA11011010
11000011 10011010
C3  9A
DB11011011
11000011 10011011
C3  9B
DC11011100
11000011 10011100
C3  9C
DD11011101
11000011 10011101
C3  9D
DE11011110
11000011 10011110
C3  9E
DF11011111
11000011 10011111
C3  9F
E011100000
11000011 10100000
C3  A0
E111100001
11000011 10100001
C3  A1
E211100010
11000011 10100010
C3  A2
E311100011
11000011 10100011
C3  A3
E411100100
11000011 10100100
C3  A4
E511100101
11000011 10100101
C3  A5
E611100110
11000011 10100110
C3  A6
E711100111
11000011 10100111
C3  A7
E811101000
11000011 10101000
C3  A8
E911101001
11000011 10101001
C3  A9
EA11101010
11000011 10101010
C3  AA
EB11101011
11000011 10101011
C3  AB
EC11101100
11000011 10101100
C3  AC
ED11101101
11000011 10101101
C3  AD
EE11101110
11000011 10101110
C3  AE
EF11101111
11000011 10101111
C3  AF
F011110000
11000011 10110000
C3  B0
F111110001
11000011 10110001
C3  B1
F211110010
11000011 10110010
C3  B2
F311110011
11000011 10110011
C3  B3
F411110100
11000011 10110100
C3  B4
F511110101
11000011 10110101
C3  B5
F611110110
11000011 10110110
C3  B6
F711110111
11000011 10110111
C3  B7
F811111000
11000011 10111000
C3  B8
F911111001
11000011 10111001
C3  B9
FA11111010
11000011 10111010
C3  BA
FB11111011
11000011 10111011
C3  BB
FC11111100
11000011 10111100
C3  BC
FD11111101
11000011 10111101
C3  BD
FE11111110
11000011 10111110
C3  BE
FF11111111
11000011 10111111
C3  BF

位于 U+0000~U+00FF 这个范围的字符,有时还称为 binary 字符。这大概是因为,在传统上文件被粗略地分为“文本文件” 和 “非文本文件”。文本文件很可能粗略地认为是只含 ASCII 字符的文件(实际上文本文件很可能也不应该包含 00 以及其他一些控制字符),而非文本文件,也就粗略地认为是含有任意字符的文件(传统上的字符,就是字节;当 8 位字符不够用的时候,才有了 16 位字符和 32 位字符;字节始终是 8 位),也就是二进制文件。JavaScript 有 binary string 的概念,意思是“由 U+0000~U+00FF 这个范围中的字符所组成的字符串”。


unicode 扩展了字符的范围,然而,传统上“字节”这个概念,在 unicode 里面却无法体现。传统上,文件是以字节为单位来表示的,一个文件,可以由单一字节构成。unicode 是 4 字节的,没法处理这种情况。UTF8 虽然能处理单字节,但是位于 0x80 ~ 0xFF 的单字节,却是非法的 UTF8 字节串,没法处理。JavaScript 必须引入 ArrayBuffer 之类的东西,才能处理传统的字节空间。科技进步了,怎么问题反而多了,处理方法也复杂了? 有没有一个办法,让 UTF8 能够直接处理任意的字节空间?



2#
 楼主| 发表于 2021-3-20 09:32:20 | 只看该作者
本帖最后由 不点 于 2021-3-22 21:33 编辑

搜到一个很好的网页:

https://unicodebook.readthedocs.io/unicode_encodings.html

它介绍了一些关键的概念。

虽然 UTF8 支持 31 位的 unicode 码点,但目前只定义了 17 个 Planes,最大的码点是 U+10FFFF,这也是 UTF16 能支持的最大码点(顺便说,位于末尾的整整两个 Planes,从 U+F0000 到 U+10FFFF 都划归私用区 Private-Use,除了每个 Plane 最末的两个码点按照惯例被定义为 non-character 以外)。就是说,UTF8 支持的范围比 UTF16 还要大。目前的最大值 U+10FFFF 需要用 4 字节的 UTF8 字节串来表示:F0 AF BF BF,二进制表示为: 11110000 10101111 10111111 10111111。其 UTF16 表示,也占用 4 字节,是成对的 surrogate 字符:
{U+DBFF, U+DFFF},每个 surrogate 字符占用 2 字节。surrogate 区似乎是专门为 UTF16 设立的区域,可以理解为 UTF16 专用区。surrogate 区共有 2048 个码点,分为高低两部分,各占 1024 个码点:

surrogate高位区:U+D800~U+DBFF,对应着成对的 UTF16 表示中的高位部分
surrogate低位区:U+DC00~U+DFFF,对应着成对的 UTF16 表示中的低位部分

位于 U+0000~U+FFFF 范围(BMP)的字符,只需一个 UTF16 字符即可表示,因此只占用 2 字节。而位于 U+10000 ~ U+10FFFF 范围的字符,则需要成对的两个 UTF16 字符来表示,总共占用 4 字节;此范围若用 UTF8 表示,也需要 4 字节。UTF16 比 UTF8 强的地方,仅仅在 BMP 范围:UTF16 统一使用 2 字节来表示,而 UTF8 需要用 1 至 3 个字节来表示。

在整个 U+0000~U+10FFFF 范围,UTF16 需要 2 或 4 字节,UTF8 需要 1 至 4 字节。都是可变的字节数,UTF16 未能显示出优越性。这就是说,UTF16 发挥优势的区域,只在 BMP 范围。而 UTF8 属于中庸之道,各种场景都能照顾得比较好,左右逢源。

surrogate 是专门为 UTF16 设立的,总共有 2048 个码点之多。如果这 2048 个码点只能服务于 UTF16,那是不是有点浪费?能否将其用于其他目的?这是我们脑子里可能提出的一个问题。而我们注意到,surrogate 区的 UTF16 的高低字符是成对使用的!也就是说,假如不是成对使用,而是单独使用,那就不与 UTF16 的规范相冲突!换句话说,这个区域有可能被用作其它目的。

私用区——Private Use

位于末尾的整整两个 Planes (U+F0000~U+10FFFF)都划归私用区。而在 BMP 中,私用区的范围也很大:U+E000~U+F8FF,共 6400 个码点,跟常用汉字的个数差不多。

转码失真

当从一个编码向另一个编码转换时,如果出现目标编码不能解释的字节或字节组合,就会出现转码失败。转码失败,有时会导致程序崩溃,有时会导致运行结果错误。操作系统遇到这种情况,通常会用一个问号(?)之类的字符来取代转码失败的字符。虽然这种处理也是一个办法,但失真是必然的。一个完善的编码,应该有“失真保护”或者“避免失真”的设计。就拿 UTF8 举例,将别的字节串用 UTF8 来解释时,碰到不能解释的字节组合,怎么办?好的,这个组合的首字节肯定位于 ASCII 之外,也即位于 0x80 至 0xFF 之间。用某种方式,把它的值记录下来,而不是笼统地用问号(?)来作为转码的结果。怎么记录?记录的方法有很多,先看看 UTF8 规范里面有没有位置来记录。我们发现此路不通,UTF8 没有规范来照顾这个特殊情况。好的,我们自己想办法吧!例如,我们把这个字节转码成私用区 U+F880~U+F8FF 之间的某个字符,就大功告成了!比如说,

这个非法字节是 0x80,就转码成 U+F880
这个非法字节是 0x81,就转码成 U+F881
这个非法字节是 0x82,就转码成 U+F882
..................................................................
这个非法字节是 0xFF,就转码成 U+F8FF

只需消耗(或占用) 128 个私用区的码点,就可搞定!如果不想使用私用区,也可以考虑使用(即重复利用)前面提到的 surrogate 区域。

这样,转码就不会失真了,就是说,如果再 reverse 转回到原始编码,那是精确的,没有丢失任何信息。

不仅 UTF8 的规范里面没有失真保护,其它编码(例如各种国标码,各种 codepage)貌似也都没有失真保护。程序员们可能经常碰到这样的事情:一个字符是合法的 unicode 字符,但却不能在某个操作系统下处理它!原因大概就在于,该字符在处理的某个环节,需要转码,而转码的某个步骤,出现了失败,或失真,导致该字符无法处理,以失败而告终。如果编码方案以及转码逻辑设计成可逆的,那就完备了,不会出现失真或失败。

上面所说的处理转码失败的方法,具有一般性,适用于任意一种编码方案。ASCII 字符不会出现转码失败。转码失败的首字节一定位于 0x80 至 0xFF 的范围。将这个字节转码为与某个无用的 unicode 字符相对应的目标编码,就完成了转换。如果 unicode 规范中能够定义 128 个字符,专门用于处理转码失败,那就完美了。

假定 unicode 规范始终不定义这些转码失败字符,那就需要程序员自己来处理了。前面已经提到了两种处理方法:一种是采用私用区,一种是采用 surrogate 区。两者都是消耗 128 个码点。除此之外,也可以在 BMP 中寻找一些目前还没有定义的字符,不一定需要它们连成一块——零零散散的,凑够 128 个——就可以了。目前这种未定义的字符确实还有不少,很容易凑够 128 个。这个办法有点问题:那些没有定义的字符将来有可能被定义。不过,即便将来定义了,它们也属于不常用字符,影响不会太大。实在没办法了,也可以在 BMP 之外寻找空闲的空间。

还有一个办法是,把转码失败的字节,转换成一对 unicode 字符,这样就不需要 128 个了。有两种方案:


方案一:利用 BMP 中 32 个“非字符” 中的 24 个字符,即可做到。这 24 个字符,分为 8 + 16 两部分。转码失败的不同字节有 128 个,就是说,一个 7 位的数字的变化范围(2 的 7 次方)。8 个 unicode 字符用于确定高 3 位,另外 16 个 unicode 字符用于确定低 4 位。这就建立了 unicode 字符 pair 到失败字节的一一对应关系。


方案二:不必消耗额外的 unicode 码点空间。第一个字符,采用 U+FFFD,当然也可以采用别的任何一个没有太大用处的字符——用它的目的,仅仅表示“转义”,就是说,它后面的字符,具有特殊含义。第二个字符,可以从现有的字符中随便找一个,这就构成字符对(pair)。由于首字符是转义字符,程序会把第二个字符解释成与某个转码失败字节相对应。这就好比我们用反斜杠“\”来转义 “n”(俩字符的组合被解释成“换行符”)一样。
回复

使用道具 举报

3#
 楼主| 发表于 2021-3-20 09:32:49 | 只看该作者
本帖最后由 不点 于 2021-3-25 18:00 编辑

搜到一个关于 Windows findstr 命令的强帖:

https://stackoverflow.com/questions/8844868/what-are-the-undocumented-features-and-limitations-of-the-windows-findstr-comman


它虽然与 UTF8 没什么关系,但是却能对 “什么是文本文件” 这个问题给出一定的暗示。

FINDSTR on XP displays most non-printable control characters from matching lines as dots (periods) on the screen. The following control characters are exceptions; they display as themselves: 0x09 Tab, 0x0A LineFeed, 0x0B Vertical Tab, 0x0C Form Feed, 0x0D Carriage Return.XP FINDSTR also converts a number of extended ASCII characters to dots as well. The extended ASCII characters that display as dots on XP are the same as those that are transformed when supplied on the command line. See the "Character limits for command line parameters - Extended ASCII transformation" section, later in this post.


提到如下几个特殊字符, 我猜测这可能是微软文本文件中的合法字符。


0x09 Tab
0x0A LineFeed
0x0B Vertical Tab
0x0C Form Feed
0x0D Carriage Return


FINDSTR treats the following control characters as printable:
0x08  backspace
0x09  horizontal tab
0x0A  line feed
0x0B  vertical tab
0x0C  form feed
0x0D  carriage return
0x1A  substitute (end of text)


那么,这些字符对于文本文件来说,可能也都是合法的。



回复

使用道具 举报

4#
 楼主| 发表于 2021-3-20 09:33:02 | 只看该作者
本帖最后由 不点 于 2021-4-2 23:28 编辑

找到这样一个函数 wcwidth,它好像是韩国人写的。

在百度上敲 wcwidth 即可找到这个 project:

https://github.com/timoxley/wcwidth

wcwidth

Determine columns needed for a fixed-size wide-character string



wcwidth is a simple JavaScript port of wcwidth implemented in C by Markus Kuhn.
JavaScript port originally written by Woong Jun woong.jun@gmail.com (http://code.woong.org/)

Example

'한'.length    // => 1
wcwidth('한');   // => 2
'한글'.length    // => 2
wcwidth('한글'); // => 4

wcwidth() and its string version, wcswidth() are defined by IEEE Std1002.1-2001, a.k.a. POSIX.1-2001, and return the number of columns used to represent the given wide character and string.

Markus's implementation assumes the wide character given to thosefunctions to be encoded in ISO 10646, which is almost true for JavaScript's characters.
Further explaination here

从上述例子可以了解,这个函数是用来判定字符的显示宽度的。亚洲语言受汉语的影响较大,出现了宽字符,就是说,字符宽度是英文字符的两倍。此处,字符宽度是指它显示出来所占用的水平方向的长度,不是指某种编码所占用的字节数。


回复

使用道具 举报

5#
 楼主| 发表于 2021-3-20 09:33:22 | 只看该作者
5楼占位
回复

使用道具 举报

6#
 楼主| 发表于 2021-3-20 09:33:39 | 只看该作者
6楼占位
回复

使用道具 举报

7#
 楼主| 发表于 2021-3-20 09:34:02 | 只看该作者
7楼占位
回复

使用道具 举报

8#
 楼主| 发表于 2021-3-20 09:34:16 | 只看该作者
8楼占位
回复

使用道具 举报

9#
 楼主| 发表于 2021-3-20 09:34:37 | 只看该作者
9楼占位
回复

使用道具 举报

10#
 楼主| 发表于 2021-3-20 09:35:00 | 只看该作者
10楼占位
回复

使用道具 举报

11#
 楼主| 发表于 2021-3-20 09:35:40 | 只看该作者
11楼占位
回复

使用道具 举报

12#
 楼主| 发表于 2021-3-20 09:36:19 | 只看该作者
12楼占位
回复

使用道具 举报

13#
 楼主| 发表于 2021-3-20 09:36:43 | 只看该作者
13楼占位
回复

使用道具 举报

14#
 楼主| 发表于 2021-3-20 09:37:07 | 只看该作者
14楼占位
回复

使用道具 举报

15#
 楼主| 发表于 2021-3-20 09:37:28 | 只看该作者
15楼占位
回复

使用道具 举报

16#
 楼主| 发表于 2021-3-20 09:37:55 | 只看该作者
16楼占位
回复

使用道具 举报

17#
 楼主| 发表于 2021-3-20 09:38:30 | 只看该作者
17楼占位
回复

使用道具 举报

18#
 楼主| 发表于 2021-3-20 09:38:56 | 只看该作者
18楼占位
回复

使用道具 举报

19#
 楼主| 发表于 2021-3-20 09:39:20 | 只看该作者
19楼占位
回复

使用道具 举报

20#
 楼主| 发表于 2021-3-20 09:40:16 | 只看该作者
20楼占位
回复

使用道具 举报

21#
 楼主| 发表于 2021-3-20 09:40:44 | 只看该作者
21楼占位
回复

使用道具 举报

22#
 楼主| 发表于 2021-3-20 09:41:15 | 只看该作者
22楼占位
回复

使用道具 举报

23#
 楼主| 发表于 2021-3-20 09:41:36 | 只看该作者
23楼占位
回复

使用道具 举报

24#
 楼主| 发表于 2021-3-20 09:41:53 | 只看该作者
24楼占位
回复

使用道具 举报

25#
 楼主| 发表于 2021-3-20 09:42:14 | 只看该作者
25楼占位
回复

使用道具 举报

26#
 楼主| 发表于 2021-3-20 09:42:41 | 只看该作者
26楼占位
回复

使用道具 举报

27#
 楼主| 发表于 2021-3-20 09:43:04 | 只看该作者
27楼占位
回复

使用道具 举报

28#
 楼主| 发表于 2021-3-20 09:43:22 | 只看该作者
28楼占位
回复

使用道具 举报

29#
 楼主| 发表于 2021-3-20 09:43:48 | 只看该作者
29楼占位
回复

使用道具 举报

30#
 楼主| 发表于 2021-3-20 09:44:12 | 只看该作者
30楼占位
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1 )

闽公网安备 35020302032614号

GMT+8, 2021-4-22 11:21

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表