6 min to read
Unicode中的那些奇技淫巧
真是太有趣了!快来看看!

什么是Unicode
其实就是使用unicode编码的字符。
你网页中看到的一个个字,计算机是认不出来的,它只能认出来二进制数。于是就有人想到将一堆二进制数与我们常见的字一一匹配,这就是”编码“。先告诉计算机这个一一对应的顺序,再告诉计算机我想要100111000101101
,于是计算机便知道要渲染出”中”这个字到显示器上。
但是,不同的国家有不同的语言文字和符号系统,形成了不同的编码规则,比如中文GBK编码,对泰文等束手无策,产生了很多麻烦事。于是便有人想到搞一套全世界通用的编码规则,Unicode应运而生。
国际标准化组织(ISO),他们于1984年创建了工作组,试图制定一份“通用字符集”(Universal Character Set,简称UCS),并制定了ISO 10646标准。统一码联盟,由Xerox、Apple等软件制造商于1988年成立,并且开发了Unicode标准(The Unicode Standard)。
比如”中”字,在unicode编码中是”U+4E2D
“。可以发现其中出现了两个英文字母”E
”,”D
“,不难猜到”4E2D
“是16进制形式,转换成二进制便是上文的100111000101101
。
如何告诉计算机用什么编码系统呢?
网页HTML源码中总可以看到这么一行:
<!DOCTYPE html>
<html>
<head>
<metacharset="utf-8">
python文件第一行:
# -*- coding:utf-8 -*-
意思就是使用 Unicode 传输格式 8 (UTF-8)
只要使用了Unicode编码标准,网页/应用都能显示文章中提及的Unicode字符。但是在不同平台,尤其是字体不同的情况下,unicode字符的显示会有很大出入。因为字体决定了unicode码值是如何转变成看到的图案的。
说了那么多,如何实操玩玩unicode呢?如果你在用网页版知乎,请按F12
键,以Firefox为例,F12
后:
我们尝试输入”4E2D”(上文的“中”字)【注意,这里的引号必须使用英文输入法的引号】,输出还是”4E2D”,为什么不是“中”呢?是因为没有告诉计算机要用unicode编码吗?不,而是因为计算机把它当成4个字母而不是一个字符处理了。
告诉计算机这是一个字符的办法很简单,使用转义字符”",不知道啥是转义字符没关系,只需要知道应该这样改:
这里的 u
当然是unicode的缩写。
Unicode工具发布
当然你也可以通过下图进入
Unicode表示方法
Unicode 码值通常使用 U+N(16 进制N 代表码值),比如 A 的码值为 U+0041。 在 HTML 中 Unicode 可以使用 &#N;(十进制,N 代表码值)表示。A为A 在 各编程语言(包括python JavaScript等)中 Unicode 中需要使用\uN(16 进制N 代表码值)表示。A为\u0041
以下进入正文,让Unicode变得好玩起来。
Unicode中的特殊字符
1. 组合字符
我们来看看这个字符:é
,是”鹅”的拼音?他的 unicode 是 \u00e9
, 但是也可以用 e + \u0301
实现é
。
前者的长度是 1,后者的长度是2。
\u0301
在这里起到了语调符的作用,那如果继续加\u0301
呢?我们在ICER233’S BLOG-Unicode Tools中试试看!
把它复制到这里来:é́́́́́ 不知道显示的出来不。
当然我们也可以一直加高,这里不做演示,大家可以试试。
\u0301
属于 Mn 类,详情参考unicode官方unicode字符分类表格
这里解释了 Mn 其实是 a nonspacing combining mark (zero advance width) 。谷歌翻译:一个非空格组合标志(零超前宽度)。我称之为附加字符,这种类型的字符可以与基础字符结合起来。有些附加字符会占据额外的宽度,有些则不占据。但不占据宽度的附加组合字符作用于基础字符后,可能会使字符的宽度增加,比如, î
会比i
稍宽一点。多个附加字符可以叠加到一个基础字符上。
那我不禁要问了,还有那些组合用附加字符呢?
组合用附加字符在 Unicode 统一码中存于多个区块,编码范围主要有:
- 修饰字母的变音组合符(Combining Diacritical Marks):从 U+0300 到 U+036F共80个。它常与字母组合,修饰字母的读音。但其实它的定义比较宽泛,不但包括了拉丁、希腊及西里尔系文字中的变音记号,也包括那些不是变音但不占据宽度的附加标记。
- 补充组合变音符(Combining Diacritical Marks Supplement):从 U+1DC0到U+1DFF共64个 。
- 修饰符号的变音组合符(Combining Diacritical Marks for Symbols):从U+20D0到U+20FF共 48 个。它常与一些符号组合,用于渲染和修饰符号。
- 组合用半形符号(Combining Half Marks):从U+FE20到U+FE2F共16个。
看不懂?来看看这张表格
我们只看80个修饰字母的变音组合符,其余的大家感兴趣也可以试试看,都可以在表格中查到。
\u0300\u0301\u0302\u0303\u0304\u0305\u0306\u0307\u0308
\u0309\u030A\u030B\u030C\u030D\u030E\u030F\u0310\u0311
\u0312\u0313\u0314\u0315\u0316\u0317\u0318\u0319\u031A
\u031B\u031C\u031D\u031E\u031F\u0320\u0321\u0322\u0323
\u0324\u0325\u0326\u0327\u0328\u0329\u032A\u032B\u032C
\u032D\u032E\u032F\u0330\u0331\u0332\u0333\u0334\u0335
\u0336\u0337\u0338\u0339\u033A\u033B\u033C\u033D\u033E
\u033F\u0340\u0341\u0342\u0343\u0344\u0345\u0346\u0347
\u0348\u0349\u034A\u034B\u034C\u034D\u034E\u034F\u0350
\u0351\u0352\u0353\u0354\u0355\u0356\u0357\u0358\u0359
\u035A\u035B\u035C\u035D\u035E\u035F\u0360\u0361\u0362
\u0363\u0364\u0365\u0366\u0367\u0368\u0369\u036A\u036B
\u036C\u036D\u036E\u036F
把它们全粘贴在unicode工具中:这 s 上下都突破天际了。。。
组合用附加字符可以用来恶搞和装\u0042。只要你脑洞够大,任何小技巧都可以变得非常奇葩。
比如在qq聊天中,如果有人发了一堆组合字符,看上去就像是加密通话:
也可以用来污染眼睛,把字藏起来:
更有甚者,用这堆字符骗到对方的QQ截图,从而知道自己被备注的昵称是什么。。。
附赠原文字:(一下子字数爆炸了)
[ ̝̦̬̤͖̗͕͎͊̐̊͊̏ͦ̈́̒͆́ͬ̂̕͠ ̛̛̾̒̊̈̈̇ͭ̾҉̱̹͙ ̪̖̠̱ͧͬͤͯ̄ͣͨ̚̚͘͠ ̵̸̶̶̸̨̼̜͕͍͈͔̪̘̣̮̖̥̗̪̬͓̠̲̟̻̞̤̳͔͖̥̻͉̮͓̬͓̤̩͉̻̩̘͕̠͍̳̳͔̣̬̰̤̺̹͉̞͚̖̲͈̻̪̜̹͇̭̥̼̹ͮͫ͐̄͐ͯ̑͊ͤͩͬ͛͛̆̐̐͗́̔̊͋̈̐ͥͪ̽ͣͪ̒́̀ͤͬ̃̄̆̈́ͭͣ̇̓̊ͦ̍ͭ͂̽͑ͫ́̽͒̇̾͊ͮͪ̑͑̄̕̕͘͜͢͟͞͝͝͡ͅͅ.̢̬̜͇̳̣̮̩̗͈̝̪̭̲̓̆̄̒̈̊ͧ̈́̋ͥͬ̏͑ͨ͗̿ͨ̃ͧ͒͑̈̚̚҉͖̭̦̲̣͎̗̳̾̓̉̂͑͛ͧ̾̕͞ ͆̆̏̋̄ͤ͏̧̨̧̡̛̳͙͙͚̮̥̙̖̞͈̜͖̱̻̪̗̱̠̼͈̠͔̯̺̳̥͔̱̟̱̥̣͎̫̰̣͕͆̀̈̓̃͋̐̓ͥ̀̐̐̽̑ͦ͑͗͑̄ͥ͒̀̚͟͜͜͡͞͞ͅͅ.̷͎̱̫̗̗̹̥̟̬̲̲͉͇͉̦̼̞͆̾͑̓͛̀̒͆͆͑ͯ͋ͭͬͤ̏ͬͮͤ͘͠͏̸͏̵̬̰̹̬̘͍͖̤̮̮̣͇̥͉̹̝̰͕̼̫̣͔͙̫̋ͬ̇̅ͤ̀̚ͅ҉̷̸̷̨͍̺̟̳͔̞̙̳̳͕͖̬̮̳̥͇͚̝̘̞̯̦͂̿͆ͯ̋̒̇ͨ́͋̄̃͌̉̈ͮ̿̾ͬ̋̌̂͑ͤ̓ͭ̀͒̌̑̒̎͊͆ͬͬ͟͠҉̶̴̩̥͎͖̻̜̰̪̙̝̺͕͓̹̱͚̪ͦͣ͐́͆̀̀ͪ̍ͫ͂̇ͬ̑̉̓̍̋ͦ͗̌̌̊͊̊́̚͞.̢͔̮̖̠͇̝̳̪̩̩̥͎͔̞̳̣̻͓̜͍͍̐̊̔́̀͛̎̑͌̓͑̿́̏ͭͫ̀͋͋̐̍ͦͦ̀̄̕̚ͅͅ ̷̷̨̦̖̘̤̱̮̘̪̘̘̦͖̪̟̱̥̟͓̇ͣ̿͗͆̓͆̈́ͨ̓ͫ̆̓ͯ̿̔̑ͧ͛̽ͅ͏̡͇͎̳̣̹̀ͭ̿̂ͩ͑̇̕͟҉̨̠͈̼̲̣̣͖̠͓̞̞̄̾.̵̥͈̝͚̘̣̘͍̘͎̟̳̺̗̬̰̤̪̮̞̝̯̣̖̂̿ͫͣ̊̔ͯ́̋̍͞͠҉̴̧̡̛̲̗̭̫͈̺̗̗̭̮͎̗̫̫͉͉͇͚͎͓̦͊ͤ͋͐́̋̃͛̔͒̒ͥ̇͂̽̌̈̎̀͆͑͆ͨͬ̽͌̍̀̚͘͘͡͡ͅ͏̶̢̘͈̪̗̙̩͚̜̳̘̖͇̲̓̐͂͆ͬͧ́̅͋̍́́́͡ͅ.̡̲̤̯͇̟ͯͪ̽̿ͯ̍ͤ̀҉̷̸̨͍̺̟̳͔̞̙̳̳͕͖̬̮̳̥͖͕͂̿͆ͯ̋̒̇ͨ́͋̄̃͌̉̈ͮ̿͟͠ ̷͇͚̝̘̞̯̦̾ͬ̋̌̂͑ͤ̓ͭ̀͒̌̑̒̎͊͆ͬͬ҉̶̴̩̥͎͖̻̜̰̪̙̝̺͕͓̹̱͚̪̱ͦͣ͐́͆̀̀ͪ̍ͫ͂̇ͬ̑̉̓̍̋ͦ͗̌̌̊͊̊́̚͞.̢͔̮̖̠͇̝̳̪̩̩̥͎͔̞̳̣̻͓̜͍͍̐̊̔́̀͛̎̑͌̓͑̿́̏ͭͫ̀͋͋̐̍ͦͦ̀̄̕̚ͅͅ ̷̷̨̦̖̘̤̱̮̘̪̘̘̦͖̪̟̱̇ͣ̿͗͆̓͆̈́ͨ̓ͫ̆̓ͅ[ ̝̦̬̤͖̗͕͎͊̐̊͊̏ͦ̈́̒͆́ͬ̂̕͠ ̛̛̾̒̊̈̈̇ͭ̾҉̱̹͙ ̪̖̠̱ͧͬͤͯ̄ͣͨ̚̚͘͠ ̵̸̶̶̸̨̼̜͕͍͈͔̪̘̣̮̖̥̗̪̬͓̠̲̟̻̞̤̳͔͖̥̻͉̮͓̬͓̤̩͉̻̩̘͕̠͍̳̳͔̣̬̰̤̺̹͉̞͚̖̲͈̻̪̜̹͇̭̥̼̹ͮͫ͐̄͐ͯ̑͊ͤͩͬ͛͛̆̐̐͗́̔̊͋̈̐ͥͪ̽ͣͪ̒́̀ͤͬ̃̄̆̈́ͭͣ̇̓̊ͦ̍ͭ͂̽͑ͫ́̽͒̇̾͊ͮͪ̑͑̄̕̕͘͜͢͟͞͝͝͡ͅͅ.̢̬̜͇̳̣̮̩̗͈̝̪̭̲̓̆̄̒̈̊ͧ̈́̋ͥͬ̏͑ͨ͗̿ͨ̃ͧ͒͑̈̚̚҉͖̭̦̲̣͎̗̳̾̓̉̂͑͛ͧ̾̕͞ ͆̆̏̋̄ͤ͏̧̨̧̡̛̳͙͙͚̮̥̙̖̞͈̜͖̱̻̪̗̱̠̼͈̠͔̯̺̳̥͔̱̟̱̥̣͎̫̰̣͕͆̀̈̓̃͋̐̓ͥ̀̐̐̽̑ͦ͑͗͑̄ͥ͒̀̚͟͜͜͡͞͞ͅͅ.̷͎̱̫̗̗̹̥̟̬̲̲͉͇͉̦̼̞͆̾͑̓͛̀̒͆͆͑ͯ͋ͭͬͤ̏ͬͮͤ͘͠͏̸͏̵̬̰̹̬̘͍͖̤̮̮̣͇̥͉̹̝̰͕̼̫̣͔͙̫̋ͬ̇̅ͤ̀̚ͅ҉̷̸̷̨͍̺̟̳͔̞̙̳̳͕͖̬̮̳̥͇͚̝̘̞̯̦͂̿͆ͯ̋̒̇ͨ́͋̄̃͌̉̈ͮ̿̾ͬ̋̌̂͑ͤ̓ͭ̀͒̌̑̒̎͊͆ͬͬ͟͠҉̶̴̩̥͎͖̻̜̰̪̙̝̺͕͓̹̱͚̪ͦͣ͐́͆̀̀ͪ̍ͫ͂̇ͬ̑̉̓̍̋ͦ͗̌̌̊͊̊́̚͞.̢͔̮̖̠͇̝̳̪̩̩̥͎͔̞̳̣̻͓̜͍͍̐̊̔́̀͛̎̑͌̓͑̿́̏ͭͫ̀͋͋̐̍ͦͦ̀̄̕̚ͅͅ ̷̷̨̦̖̘̤̱̮̘̪̘̘̦͖̪̟̱̥̟͓̇ͣ̿͗͆̓͆̈́ͨ̓ͫ̆̓ͯ̿̔̑ͧ͛̽ͅ͏̡͇͎̳̣̹̀ͭ̿̂ͩ͑̇̕͟҉̨̠͈̼̲̣̣͖̠͓̞̞̄̾.̵̥͈̝͚̘̣̘͍̘͎̟̳̺̗̬̰̤̪̮̞̝̯̣̖̂̿ͫͣ̊̔ͯ́̋̍͞͠҉̴̧̡̛̲̗̭̫͈̺̗̗̭̮͎̗̫̫͉͉͇͚͎͓̦͊ͤ͋͐́̋̃͛̔͒̒ͥ̇͂̽̌̈̎̀͆͑͆ͨͬ̽͌̍̀̚͘͘͡͡ͅ͏̶̢̘͈̪̗̙̩͚̜̳̘̖͇̲̓̐͂͆ͬͧ́̅͋̍́́́͡ͅ.̡̲̤̯͇̟ͯͪ̽̿ͯ̍ͤ̀҉̷̸̨͍̺̟̳͔̞̙̳̳͕͖̬̮̳̥͖͕͂̿͆ͯ̋̒̇ͨ́͋̄̃͌̉̈ͮ̿͟͠ ̷͇͚̝̘̞̯̦̾ͬ̋̌̂͑ͤ̓ͭ̀͒̌̑̒̎͊͆ͬͬ҉̶̴̩̥͎͖̻̜̰̪̙̝̺͕͓̹̱͚̪̱ͦͣ͐́͆̀̀ͪ̍ͫ͂̇ͬ̑̉̓̍̋ͦ͗̌̌̊͊̊́̚͞.̢͔̮̖̠͇̝̳̪̩̩̥͎͔̞̳̣̻͓̜͍͍̐̊̔́̀͛̎̑͌̓͑̿́̏ͭͫ̀͋͋̐̍ͦͦ̀̄̕̚ͅͅ ̷̷̨̦̖̘̤̱̮̘̪̘̘̦͖̪̟̱̇ͣ̿͗͆̓͆̈́ͨ̓ͫ̆̓ͅ[ ̝̦̬̤͖̗͕͎͊̐̊͊̏ͦ̈́̒͆́ͬ̂̕͠ ̛̛̾̒̊̈̈̇ͭ̾҉̱̹͙ ̪̖̠̱ͧͬͤͯ̄ͣͨ̚̚͘͠ ̵̸̶̶̸̨̼̜͕͍͈͔̪̘̣̮̖̥̗̪̬͓̠̲̟̻̞̤̳͔͖̥̻͉̮͓̬͓̤̩͉̻̩̘͕̠͍̳̳͔̣̬̰̤̺̹͉̞͚̖̲͈̻̪̜̹͇̭̥̼̹ͮͫ͐̄͐ͯ̑͊ͤͩͬ͛͛̆̐̐͗́̔̊͋̈̐ͥͪ̽ͣͪ̒́̀ͤͬ̃̄̆̈́ͭͣ̇̓̊ͦ̍ͭ͂̽͑ͫ́̽͒̇̾͊ͮͪ̑͑̄̕̕͘͜͢͟͞͝͝͡ͅͅ.̢̬̜͇̳̣̮̩̗͈̝̪̭̲̓̆̄̒̈̊ͧ̈́̋ͥͬ̏͑ͨ͗̿ͨ̃ͧ͒͑̈̚̚҉͖̭̦̲̣͎̗̳̾̓̉̂͑͛ͧ̾̕͞ ͆̆̏̋̄ͤ͏̧̨̧̡̛̳͙͙͚̮̥̙̖̞͈̜͖̱̻̪̗̱̠̼͈̠͔̯̺̳̥͔̱̟̱̥̣͎̫̰̣͕͆̀̈̓̃͋̐̓ͥ̀̐̐̽̑ͦ͑͗͑̄ͥ͒̀̚͟͜͜͡͞͞ͅͅ.̷͎̱̫̗̗̹̥̟̬̲̲͉͇͉̦̼̞͆̾͑̓͛̀̒͆͆͑ͯ͋ͭͬͤ̏ͬͮͤ͘͠͏̸͏̵̬̰̹̬̘͍͖̤̮̮̣͇̥͉̹̝̰͕̼̫̣͔͙̫̋ͬ̇̅ͤ̀̚ͅ҉̷̸̷̨͍̺̟̳͔̞̙̳̳͕͖̬̮̳̥͇͚̝̘̞̯̦͂̿͆ͯ̋̒̇ͨ́͋̄̃͌̉̈ͮ̿̾ͬ̋̌̂͑ͤ̓ͭ̀͒̌̑̒̎͊͆ͬͬ͟͠҉̶̴̩̥͎͖̻̜̰̪̙̝̺͕͓̹̱͚̪ͦͣ͐́͆̀̀ͪ̍ͫ͂̇ͬ̑̉̓̍̋ͦ͗̌̌̊͊̊́̚͞.̢͔̮̖̠͇̝̳̪̩̩̥͎͔̞̳̣̻͓̜͍͍̐̊̔́̀͛̎̑͌̓͑̿́̏ͭͫ̀͋͋̐̍ͦͦ̀̄̕̚ͅͅ ̷̷̨̦̖̘̤̱̮̘̪̘̘̦͖̪̟̱̥̟͓̇ͣ̿͗͆̓͆̈́ͨ̓ͫ̆̓ͯ̿̔̑ͧ͛̽ͅ͏̡͇͎̳̣̹̀ͭ̿̂ͩ͑̇̕͟҉̨̠͈̼̲̣̣͖̠͓̞̞̄̾.̵̥͈̝͚̘̣̘͍̘͎̟̳̺̗̬̰̤̪̮̞̝̯̣̖̂̿ͫͣ̊̔ͯ́̋̍͞͠҉̴̧̡̛̲̗̭̫͈̺̗̗̭̮͎̗̫̫͉͉͇͚͎͓̦͊ͤ͋͐́̋̃͛̔͒̒ͥ̇͂̽̌̈̎̀͆͑͆ͨͬ̽͌̍̀̚͘͘͡͡ͅ͏̶̢̘͈̪̗̙̩͚̜̳̘̖͇̲̓̐͂͆ͬͧ́̅͋̍́́́͡ͅ.̡̲̤̯͇̟ͯͪ̽̿ͯ̍ͤ̀҉̷̸̨͍̺̟̳͔̞̙̳̳͕͖̬̮̳̥͖͕͂̿͆ͯ̋̒̇ͨ́͋̄̃͌̉̈ͮ̿͟͠ ̷͇͚̝̘̞̯̦̾ͬ̋̌̂͑ͤ̓ͭ̀͒̌̑̒̎͊͆ͬͬ҉̶̴̩̥͎͖̻̜̰̪̙̝̺͕͓̹̱͚̪̱ͦͣ͐́͆̀̀ͪ̍ͫ͂̇ͬ̑̉̓̍̋ͦ͗̌̌̊͊̊́̚͞.̢͔̮̖̠͇̝̳̪̩̩̥͎͔̞̳̣̻͓̜͍͍̐̊̔́̀͛̎̑͌̓͑̿́̏ͭͫ̀͋͋̐̍ͦͦ̀̄̕̚ͅͅ ̷̷̨̦̖̘̤̱̮̘̪̘̘̦͖̪̟̱̇ͣ̿͗͆̓͆̈́ͨ̓ͫ̆̓ͅ[ ̝̦̬̤͖̗͕͎͊̐̊͊̏ͦ̈́̒͆́ͬ̂̕͠ ̛̛̾̒̊̈̈̇ͭ̾҉̱̹͙ ̪̖̠̱ͧͬͤͯ̄ͣͨ̚̚͘͠ ̵̸̶̶̸̨̼̜͕͍͈͔̪̘̣̮̖̥̗̪̬͓̠̲̟̻̞̤̳͔͖̥̻͉̮͓̬͓̤̩͉̻̩̘͕̠͍̳̳͔̣̬̰̤̺̹͉̞͚̖̲͈̻̪̜̹͇̭̥̼̹ͮͫ͐̄͐ͯ̑͊ͤͩͬ͛͛̆̐̐͗́̔̊͋̈̐ͥͪ̽ͣͪ̒́̀ͤͬ̃̄̆̈́ͭͣ̇̓̊ͦ̍ͭ͂̽͑ͫ́̽͒̇̾͊ͮͪ̑͑̄̕̕͘͜͢͟͞͝͝͡ͅͅ.̢̬̜͇̳̣̮̩̗͈̝̪̭̲̓̆̄̒̈̊ͧ̈́̋ͥͬ̏͑ͨ͗̿ͨ̃ͧ͒͑̈̚̚҉͖̭̦̲̣͎̗̳̾̓̉̂͑͛ͧ̾̕͞ ͆̆̏̋̄ͤ͏̧̨̧̡̛̳͙͙͚̮̥̙̖̞͈̜͖̱̻̪̗̱̠̼͈̠͔̯̺̳̥͔̱̟̱̥̣͎̫̰̣͕͆̀̈̓̃͋̐̓ͥ̀̐̐̽̑ͦ͑͗͑̄ͥ͒̀̚͟͜͜͡͞͞ͅͅ.̷͎̱̫̗̗̹̥̟̬̲̲͉͇͉̦̼̞͆̾͑̓͛̀̒͆͆͑ͯ͋ͭͬͤ̏ͬͮͤ͘͠͏̸͏̵̬̰̹̬̘͍͖̤̮̮̣͇̥͉̹̝̰͕̼̫̣͔͙̫̋ͬ̇̅ͤ̀̚ͅ҉̷̸̷̨͍̺̟̳͔̞̙̳̳͕͖̬̮̳̥͇͚̝̘̞̯̦͂̿͆ͯ̋̒̇ͨ́͋̄̃͌̉̈ͮ̿̾ͬ̋̌̂͑ͤ̓ͭ̀͒̌̑̒̎͊͆ͬͬ͟͠҉̶̴̩̥͎͖̻̜̰̪̙̝̺͕͓̹̱͚̪ͦͣ͐́͆̀̀ͪ̍ͫ͂̇ͬ̑̉̓̍̋ͦ͗̌̌̊͊̊́̚͞.̢͔̮̖̠͇̝̳̪̩̩̥͎͔̞̳̣̻͓̜͍͍̐̊̔́̀͛̎̑͌̓͑̿́̏ͭͫ̀͋͋̐̍ͦͦ̀̄̕̚ͅͅ ̷̷̨̦̖̘̤̱̮̘̪̘̘̦͖̪̟̱̥̟͓̇ͣ̿͗͆̓͆̈́ͨ̓ͫ̆̓ͯ̿̔̑ͧ͛̽ͅ͏̡͇͎̳̣̹̀ͭ̿̂ͩ͑̇̕͟҉̨̠͈̼̲̣̣͖̠͓̞̞̄̾.̵̥͈̝͚̘̣̘͍̘͎̟̳̺̗̬̰̤̪̮̞̝̯̣̖̂̿ͫͣ̊̔ͯ́̋̍͞͠҉̴̧̡̛̲̗̭̫͈̺̗̗̭̮͎̗̫̫͉͉͇͚͎͓̦͊ͤ͋͐́̋̃͛̔͒̒ͥ̇͂̽̌̈̎̀͆͑͆ͨͬ̽͌̍̀̚͘͘͡͡ͅ͏̶̢̘͈̪̗̙̩͚̜̳̘̖͇̲̓̐͂͆ͬͧ́̅͋̍́́́͡ͅ.̡̲̤̯͇̟ͯͪ̽̿ͯ̍ͤ̀҉̷̸̨͍̺̟̳͔̞̙̳̳͕͖̬̮̳̥͖͕͂̿͆ͯ̋̒̇ͨ́͋̄̃͌̉̈ͮ̿͟͠ ̷͇͚̝̘̞̯̦̾ͬ̋̌̂͑ͤ̓ͭ̀͒̌̑̒̎͊͆ͬͬ҉̶̴̩̥͎͖̻̜̰̪̙̝̺͕͓̹̱͚̪̱ͦͣ͐́͆̀̀ͪ̍ͫ͂̇ͬ̑̉̓̍̋ͦ͗̌̌̊͊̊́̚͞.̢͔̮̖̠͇̝̳̪̩̩̥͎͔̞̳̣̻͓̜͍͍̐̊̔́̀͛̎̑͌̓͑̿́̏ͭͫ̀͋͋̐̍ͦͦ̀̄̕̚ͅͅ ̷̷̨̦̖̘̤̱̮̘̪̘̘̦͖̪̟̱̇ͣ̿͗͆̓͆̈́ͨ̓ͫ̆̓ͅ
还可以做出一些令人忍俊不禁的文案。
比如:
\u70ed\u0488\u7684\u0488\u5b57\u0488\u90fd\u0488\u51fa\u0488\u6c57\u0488\u4e86\u0488
其中\u0488
就是 ҈
这个字符的编码,它是一个组合用的西里尔文百千符号。
它在大部分常用字体里,都有错位问题;而其他一些字体,比如 Courier New 字体,则是分开的展示。
至于你把它跟其他语言组合在一起时,我们要么看到错位,要么看到分离的展示。而且国际上并没有一个组织,去规定要怎么展示。事实上文字这么多,根本也管不过来,所以这也是混乱的原因。
2. 控制字符
unicode中控制字符很多,这里只介绍一个:\u202e
Unicode-控制字符
‎LRM
‏RLM
‍ZWJ
‌ZWNJ
‪LRE
‫RLE
‭LRO
‮RLO
‬PDF
NADS
NODS
ASS
ISS
AAFS
IAFS
RS
US
当然,也可以用16进制表示。
如让文本实现反向排列的RLO对应的‮
;等同于\u202E
;
让前面运算法则结束的字符PDF是‬
;等于\u202C
;
左到右标记 (LRM)
操作时很象从左到右字符,只是它不显示。LRM 没有任何其它语义效果。
从右到左标记 (RLM)
操作时很象从右到左字符,只是它不显示。RLM 没有任何其它语义效果。
零宽度联接器 (ZWJ)
防止连续字符在输出上联接。
零宽度非联接器 (ZWNJ) 在两个字符间添加非联接器,防止这两个字符在映射时连接草率。
启动从左到右的嵌套 (LRE)
表示将从左到右嵌套一些文本。例如, 阿拉伯句子中间的英文引用语可被标记为从左到右的嵌套文本。(LRE 影响单词顺序,不影响字符顺序。)
启动从右到左的嵌套 (RLE)
表示将从右到左嵌套一些文本。例如,英语引用语中间的希伯来短语可被标记为从右到左的嵌套文本。(RLE 影响单词顺序,不影响字符顺序。)
启动从左到右的优先 (LRO)
当需要用于特殊情况(例如,用于部件编号)时,优先于双向字符类型。LRO 强制字符成为从左到右的字符。
启动从右到左的优先 (RLO)
当需要用于特殊情况(例如,用于部件编号)时,优先于双向字符类型。RLO 强制字符成为从右到左的字符。
直接格式化 (PDF)
终止上一个显式代码的效果(嵌套或优先),并将双向状态恢复到在上一个 LRE、RLE、RLO 或 LRO 控制字符之前的状态。
国家(地区)数字形状替代 (NADS)
使用国家(地区)数字形状显示 U+0030-U+0039(ASCII 数字)。国家(地区)数字形状由当前用户的区域设置决定。
名义(欧洲)数字形状 (NODS)
使用名义数字形状显示 U+0030-U+0039(ASCII 数字)。名义数字形状是欧洲数字。
激活对称交换 (ASS)
表示是否应该将成对的字符名中的 LEFT 或 RIGHT 分别解释为有意义的打开或关闭。(默认状态是激活。)
禁止对称交换 (ISS)
关闭象圆括号这样的字符的对称交换,这样其左边和右边能继续表明向左和向右的朝向,与打开对称交换时的打开和关闭状态相反。
激活阿拉伯成形 (AAFS)
控制阿拉伯兼容性字符的成形行为。在显示过程中,某些字母形式可能以草率的连接或者连字狐线的方式联接起来。成形选择器代码表示用于获得显示效果的字符形状确定(glyph 选择)过程是处于激活还是禁止状态。(默认状态为禁止。)
禁止阿拉伯成形 (IAFS)
禁止字符成形确定过程, 这样字符不会根据位置而成形。
记录分隔符(块分隔符) (RS)
在每个行分隔符后开始新的行。
US Unit Separator (Segment Separator) 每个段分隔符后开始新的段。
可以看到\u202e
是让文本实现反向排列的控制字符。来试试看!
在我的Unicode工具页面我专门添加了一个“反转字符”按钮,按一下就在文本后面加上\u202e
:
这都可以有有趣玩法,比如在qq昵称后跟\u202e
,可以使别人@你的时候发出去的文字全是反着的,而且你撤回时会显示:
xxx息消条一了回撤。
*但是不幸的是,qq在2022年初禁止这个字符了,现在改群昵称无法包含\u202e字符*
幸运的是,钉钉目前为止仍然可以使用\u202e字符。
依然幸运的是,QQ截止7/22日并没有禁止其他控制字符,如\u202b(从右到左的嵌套),效果不是很好,当且仅当别人@你,且发至少两个数字时见效。
举个例子:
你可以在你的qq昵称后面加入:
\u2067后缀 \u2067\u202d
或者
\u2067后缀\u2066
注意第一个后缀后面必须加个空格而第二个不用,使得这个后缀始终在消息最后
3. 零宽度字符
终于到了本文重头戏——零宽字符了,什么是零宽字符?顾名思义,就是宽度为0,也就是你看不到的字符,又叫不可见字符。
也许你已经见过它们了,因为有些零宽字符也是控制字符,比如前面提到的\u202e
,\u202b
等等。零宽字符主要有以下6个:
1. 零宽度空格符 (zero-width space) U+200B : 用于较长单词的换行分隔
2. 零宽度非断空格符 (zero width no-break space) U+FEFF : 用于阻止特定位置的换行分隔
3. 零宽度连字符 (zero-width joiner) U+200D : 用于阿拉伯文与印度语系等文字中,使不会发生连字的字符间产生连字效果
4. 零宽度断字符 (zero-width non-joiner) U+200C : 用于阿拉伯文,德文,印度语系等文字中,阻止会发生连字的字符间的连字效果
5. 左至右符 (left-to-right mark) U+200E : 用于在混合文字方向的多种语言文本中(例:混合左至右书写的英语与右至左书写的希伯来语),规定排版文字书写方向为左至右
6. 右至左符 (right-to-left mark) U+200F : 用于在混合文字方向的多种语言文本中,规定排版文字书写方向为右
零宽字符有啥用?可以说比前面提到的任何字符类型都有用。
作用一:空白评论
众所周知,知乎的评论区无法发送空白评论,如果我只打一个空格点击【发送】的话,会告诉我「内容不能为空」
但是如果发送一个零宽字符的话,系统就会把它当成有效字符看待,就能发出去的,但由于零宽字符是看不见的,别人就只能看到你啥都没写。
同理,你可以借此发空白微博,发空白朋友圈,某些游戏中的空白用户名。
甚至在一些社交平台上,你想要的用户名已经被占用了,可以通过后面追加一个\u200b
解决,虽然B站没法用,因为用户名中不允许特殊字符。
作用二:网络上互喷
这不最近很多人在骂百度贴吧把「傻逼」替换成「傻宝」这事嘛,但如果我在傻逼中间插入一堆零宽字符呢?贴吧这人工智障就不可能搜索到我骂脏话了。
那我一大段文本这么多文字,难道还要一个个插入零宽字符吗?当然可以省去这个步骤,因为我也顺便写了一个小工具供大家使用:
唯一的缺点是,生成的文字往往比原段落长几倍(虽然看上去一模一样)。有些平台的输入框可能有字数限制,这时建议还是在敏感词汇中手动插入零宽字符。
作用三:文本加密
这个就厉害了,当初受zero-width-web项目的启发,打算也写一个加密/解密方法一致的网页,于是就有了:
原来在第一个字符和第二个之间应藏着一堆零宽字符。那加密的原理是什么呢?我将每个字符的unicode码值转换为5进制,其中0对应\u200e
, 1对应\u200f
, 2对应\u200c
, 3对应\u200d
, 4对应\ufeff
,字符之间用\u200b
隔开,这样所有的6个零宽字符都用上了。
作用四:文字隐形水印
发文字真的没法打水印吗?
不然。
通过了解上面的文本加密办法,可以想到把文字加密成零宽字符串,不影响正常阅读的同时,也做到了给文字加水印的效果。
就比如我这篇文章中许多地方加上了「南瓜瓜」的水印,谁复制了就可以告他。(然而我也有很多地方是抄别的文章的
同样的,水印可以防止网页爬虫。将零宽度字符插入关键词文本中,使得匹配关键字时不能正确匹配。
作用五:短网址
我们可以利用零宽字符也可以实现短网址的效果,,比如下面这个网站,就可以生成这类短网址。
Zero Width Shortener(还能用)
零宽短网址与二维码生成器(已失效)
可以看到这个短网址后面看不到任何字符,实际上这后面跟着一串零宽字符。当浏览器访问该短网址时,后端程序只要反解密的后面零宽字符,拿到相应的网址,然后在做跳转就可以到指定的网站。
作用六:压缩代码/代码加密/代码混淆
大家看下面这几行python代码:
平平无奇是吧?(代码不方便在这贴,贴上去怕字数爆炸)
然而运行出来的效果是——
顺便送上将代码加密的方法:
注:这里的加密方式与上文提到的加密方式不完全相同,由于我想把加密/解密的代码压缩到一行,不方便搞太复杂的代码。所以这里只用到3个零宽字符。
XXXX = """
print("Hello World")
"""
exec(XXXX) # exec运行字符串 XXXX
# 加密 XXXX 变成零宽字符串
encoded = '\u200b'.join([bin(ord(i))[2:].replace('0','\u200c').replace('1','\u200d') for i in XXXX])
print(encoded)
# 解密零宽字符串变回 XXXX
decoded = "".join([chr(int(i.replace('\u200c', '0').replace('\u200d', '1'), 2)) for i in encoded.split('\u200b')])
exec(decoded)
结语
Unicode字符:U+202E、U+2066、U+2069 (记录) - konglong - 博客园 (cnblogs.com)
↑这篇文章也介绍了一些控制字符的实际应用,供大家参考学习
附录
Unicode码表
0000-007F:C0控制符及基本拉丁文 (C0 Control and Basic Latin)
0080-00FF:C1控制符及拉丁文补充-1 (C1 Control and Latin 1 Supplement)
0100-017F:拉丁文扩展-A (Latin Extended-A)
0180-024F:拉丁文扩展-B (Latin Extended-B)
0250-02AF:国际音标扩展 (IPA Extensions)
02B0-02FF:空白修饰字母 (Spacing Modifiers)
0300-036F:结合用读音符号 (Combining Diacritics Marks)
0370-03FF:希腊文及科普特文 (Greek and Coptic)
0400-04FF:西里尔字母 (Cyrillic)
0500-052F:西里尔字母补充 (Cyrillic Supplement)
0530-058F:亚美尼亚语 (Armenian)
0590-05FF:希伯来文 (Hebrew)
0600-06FF:阿拉伯文 (Arabic)
0700-074F:叙利亚文 (Syriac)
0750-077F:阿拉伯文补充 (Arabic Supplement)
0780-07BF:马尔代夫语 (Thaana)
07C0-077F:西非書面語言 (N’Ko)
0800-085F:阿维斯塔语及巴列维语 (Avestan and Pahlavi)
0860-087F:Mandaic
0880-08AF:撒马利亚语 (Samaritan)
0900-097F:天城文书 (Devanagari)
0980-09FF:孟加拉语 (Bengali)
0A00-0A7F:锡克教文 (Gurmukhi)
0A80-0AFF:古吉拉特文 (Gujarati)
0B00-0B7F:奥里亚文 (Oriya)
0B80-0BFF:泰米尔文 (Tamil)
0C00-0C7F:泰卢固文 (Telugu)
0C80-0CFF:卡纳达文 (Kannada)
0D00-0D7F:德拉维族语 (Malayalam)
0D80-0DFF:僧伽罗语 (Sinhala)
0E00-0E7F:泰文 (Thai)
0E80-0EFF:老挝文 (Lao)
0F00-0FFF:藏文 (Tibetan)
1000-109F:缅甸语 (Myanmar)
10A0-10FF:格鲁吉亚语 (Georgian)
1100-11FF:朝鲜文 (Hangul Jamo)
1200-137F:埃塞俄比亚语 (Ethiopic)
1380-139F:埃塞俄比亚语补充 (Ethiopic Supplement)
13A0-13FF:切罗基语 (Cherokee)
1400-167F:统一加拿大土著语音节 (Unified Canadian Aboriginal Syllabics)
1680-169F:欧甘字母 (Ogham)
16A0-16FF:如尼文 (Runic)
1700-171F:塔加拉语 (Tagalog)
1720-173F:Hanunóo
1740-175F:Buhid
1760-177F:Tagbanwa
1780-17FF:高棉语 (Khmer)
1800-18AF:蒙古文 (Mongolian)
18B0-18FF:Cham
1900-194F:Limbu
1950-197F:德宏泰语 (Tai Le)
1980-19DF:新傣仂语 (New Tai Lue)
19E0-19FF:高棉语记号 (Kmer Symbols)
1A00-1A1F:Buginese
1A20-1A5F:Batak
1A80-1AEF:Lanna
1B00-1B7F:巴厘语 (Balinese)
1B80-1BB0:巽他语 (Sundanese)
1BC0-1BFF:Pahawh Hmong
1C00-1C4F:雷布查语(Lepcha)
1C50-1C7F:Ol Chiki
1C80-1CDF:曼尼普尔语 (Meithei/Manipuri)
1D00-1D7F:语音学扩展 (Phonetic Extensions)
1D80-1DBF:语音学扩展补充 (Phonetic Extensions Supplement)
1DC0-1DFF:结合用读音符号补充 (Combining Diacritics Marks Supplement)
1E00-1EFF:拉丁文扩充附加 (Latin Extended Additional)
1F00-1FFF:希腊语扩充 (Greek Extended)
2000-206F:常用标点 (General Punctuation)
2070-209F:上标及下标 (Superscripts and Subscripts)
20A0-20CF:货币符号 (Currency Symbols)
20D0-20FF:组合用记号 (Combining Diacritics Marks for Symbols)
2100-214F:字母式符号 (Letterlike Symbols)
2150-218F:数字形式 (Number Form)
2190-21FF:箭头 (Arrows)
2200-22FF:数学运算符 (Mathematical Operator)
2300-23FF:杂项工业符号 (Miscellaneous Technical)
2400-243F:控制图片 (Control Pictures)
2440-245F:光学识别符 (Optical Character Recognition)
2460-24FF:封闭式字母数字 (Enclosed Alphanumerics)
2500-257F:制表符 (Box Drawing)
2580-259F:方块元素 (Block Element)
25A0-25FF:几何图形 (Geometric Shapes)
2600-26FF:杂项符号 (Miscellaneous Symbols)
2700-27BF:印刷符号 (Dingbats)
27C0-27EF:杂项数学符号-A (Miscellaneous Mathematical Symbols-A)
27F0-27FF:追加箭头-A (Supplemental Arrows-A)
2800-28FF:盲文点字模型 (Braille Patterns)
2900-297F:追加箭头-B (Supplemental Arrows-B)
2980-29FF:杂项数学符号-B (Miscellaneous Mathematical Symbols-B)
2A00-2AFF:追加数学运算符 (Supplemental Mathematical Operator)
2B00-2BFF:杂项符号和箭头 (Miscellaneous Symbols and Arrows)
2C00-2C5F:格拉哥里字母 (Glagolitic)
2C60-2C7F:拉丁文扩展-C (Latin Extended-C)
2C80-2CFF:古埃及语 (Coptic)
2D00-2D2F:格鲁吉亚语补充 (Georgian Supplement)
2D30-2D7F:提非纳文 (Tifinagh)
2D80-2DDF:埃塞俄比亚语扩展 (Ethiopic Extended)
2E00-2E7F:追加标点 (Supplemental Punctuation)
2E80-2EFF:CJK 部首补充 (CJK Radicals Supplement)
2F00-2FDF:康熙字典部首 (Kangxi Radicals)
2FF0-2FFF:表意文字描述符 (Ideographic Description Characters)
3000-303F:CJK 符号和标点 (CJK Symbols and Punctuation)
3040-309F:日文平假名 (Hiragana)
30A0-30FF:日文片假名 (Katakana)
3100-312F:注音字母 (Bopomofo)
3130-318F:朝鲜文兼容字母 (Hangul Compatibility Jamo)
3190-319F:象形字注释标志 (Kanbun)
31A0-31BF:注音字母扩展 (Bopomofo Extended)
31C0-31EF:CJK 笔画 (CJK Strokes)
31F0-31FF:日文片假名语音扩展 (Katakana Phonetic Extensions)
3200-32FF:封闭式 CJK 文字和月份 (Enclosed CJK Letters and Months)
3300-33FF:CJK 兼容 (CJK Compatibility)
3400-4DBF:CJK 统一表意符号扩展 A (CJK Unified Ideographs Extension A)
4DC0-4DFF:易经六十四卦符号 (Yijing Hexagrams Symbols)
4E00-9FBF:CJK 统一表意符号 (CJK Unified Ideographs)
A000-A48F:彝文音节 (Yi Syllables)
A490-A4CF:彝文字根 (Yi Radicals)
A500-A61F:Vai
A660-A6FF:统一加拿大土著语音节补充 (Unified Canadian Aboriginal Syllabics Supplement)
A700-A71F:声调修饰字母 (Modifier Tone Letters)
A720-A7FF:拉丁文扩展-D (Latin Extended-D)
A800-A82F:Syloti Nagri
A840-A87F:八思巴字 (Phags-pa)
A880-A8DF:Saurashtra
A900-A97F:爪哇语 (Javanese)
A980-A9DF:Chakma
AA00-AA3F:Varang Kshiti
AA40-AA6F:Sorang Sompeng
AA80-AADF:Newari
AB00-AB5F:越南傣语 (Vi?t Thái)
AB80-ABA0:Kayah Li
AC00-D7AF:朝鲜文音节 (Hangul Syllables)
D800-DBFF:High-half zone of UTF-16
DC00-DFFF:Low-half zone of UTF-16
E000-F8FF:自行使用區域 (Private Use Zone)
F900-FAFF:CJK 兼容象形文字 (CJK Compatibility Ideographs)
FB00-FB4F:字母表達形式 (Alphabetic Presentation Form)
FB50-FDFF:阿拉伯表達形式A (Arabic Presentation Form-A)
FE00-FE0F:变量选择符 (Variation Selector)
FE10-FE1F:竖排形式 (Vertical Forms)
FE20-FE2F:组合用半符号 (Combining Half Marks)
FE30-FE4F:CJK 兼容形式 (CJK Compatibility Forms)
FE50-FE6F:小型变体形式 (Small Form Variants)
FE70-FEFF:阿拉伯表達形式B (Arabic Presentation Form-B)
FF00-FFEF:半型及全型形式 (Halfwidth and Fullwidth Form)
FFF0-FFFF:特殊 (Specials)
评论