Punycode是一个根据RFC 3492标准而制定的编码系统,主要用于把域名从地方语言所采用的Unicode编码转换成为可用于DNS系统的编码
“中文域名”不被标准的解析服务器支持,需转化为Punycode码进行解析,例如“百度.中国”的转码为: xn--wxTr44c.xn--fiqs8S
目前,因为操作系统的核心都是英文组成,DNS服务器的解析也是由英文代码交换,所以DNS服务器上并不支持直接的中文域名解析,所有中文域名的解析都需要转成Punycode码,然后由DNS解析Punycode码

其实目前所说的各种浏览器完美支持中文域名,只是浏览器中主动加入了中文域名自动转码,不需要再次安装中文域名转码控件来完成整个流程

如在浏览器中输入"北京大学.com”,然后通过wireshark抓包

GET http://xn--1lq90ic7fzpc.com/ HTTP/1.1
 
将原作者的.Net版本修改为了Java版本,这里感谢下原作者
public class CharsetTool {
static int TMIN = 1;
static int TMAX = 26;
static int BASE = 36;
static int INITIAL_N = 128;
static int INITIAL_BIAS = 72;
static int DAMP = 700;
static int SKEW = 38;
static char DELIMITER = '-'; /**
* Punycodes a unicode string.
*
* @param input
* Unicode string.
*
* @return Punycoded string.
*/
public static String encode(String input) throws Exception {
int n = INITIAL_N;
int delta = 0;
int bias = INITIAL_BIAS;
StringBuilder output = new StringBuilder();
// Copy all basic code points to the output
int b = 0;
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (isBasic(c)) {
output.append(c);
b++;
}
}
// Append delimiter
if (b > 0) {
output.append(DELIMITER);
}
int h = b;
while (h < input.length()) {
int m = Integer.MAX_VALUE;
// Find the minimum code point >= n
for (int i = 0; i < input.length(); i++) {
int c = input.charAt(i);
if (c >= n && c < m) {
m = c;
}
}
if (m - n > (Integer.MAX_VALUE - delta) / (h + 1)) {
throw new Exception("OVERFLOW");
}
delta = delta + (m - n) * (h + 1);
n = m;
for (int j = 0; j < input.length(); j++) {
int c = input.charAt(j);
if (c < n) {
delta++;
if (0 == delta) {
throw new Exception("OVERFLOW");
}
}
if (c == n) {
int q = delta;
for (int k = BASE;; k += BASE) {
int t;
if (k <= bias) {
t = TMIN;
} else if (k >= bias + TMAX) {
t = TMAX;
} else {
t = k - bias;
}
if (q < t) {
break;
}
output.append((char) digit2codepoint(t + (q - t)
% (BASE - t)));
q = (q - t) / (BASE - t);
}
output.append((char) digit2codepoint(q));
bias = adapt(delta, h + 1, h == b);
delta = 0;
h++;
}
}
delta++;
n++;
}
return output.toString();
} /**
* Decode a punycoded string.
*
* @param input
* Punycode string
*
* @return Unicode string.
*/
public static String decode(String input) throws Exception {
int n = INITIAL_N;
int i = 0;
int bias = INITIAL_BIAS;
StringBuilder output = new StringBuilder();
int d = input.lastIndexOf(DELIMITER);
if (d > 0) {
for (int j = 0; j < d; j++) {
char c = input.charAt(j);
if (!isBasic(c)) {
throw new Exception("BAD_INPUT");
}
output.append(c);
}
d++;
} else {
d = 0;
}
while (d < input.length()) {
int oldi = i;
int w = 1;
for (int k = BASE;; k += BASE) {
if (d == input.length()) {
throw new Exception("BAD_INPUT");
}
int c = input.charAt(d++);
int digit = codepoint2digit(c);
if (digit > (Integer.MAX_VALUE - i) / w) {
throw new Exception("OVERFLOW");
}
i = i + digit * w;
int t;
if (k <= bias) {
t = TMIN;
} else if (k >= bias + TMAX) {
t = TMAX;
} else {
t = k - bias;
}
if (digit < t) {
break;
}
w = w * (BASE - t);
}
bias = adapt(i - oldi, output.length() + 1, oldi == 0);
if (i / (output.length() + 1) > Integer.MAX_VALUE - n) {
throw new Exception("OVERFLOW");
}
n = n + i / (output.length() + 1);
i = i % (output.length() + 1);
output.insert(i, (char) n);
i++;
}
return output.toString();
} public static int adapt(int delta, int numpoints, boolean first) {
if (first) {
delta = delta / DAMP;
} else {
delta = delta / 2;
}
delta = delta + (delta / numpoints);
int k = 0;
while (delta > ((BASE - TMIN) * TMAX) / 2) {
delta = delta / (BASE - TMIN);
k = k + BASE;
}
return k + ((BASE - TMIN + 1) * delta) / (delta + SKEW);
} public static boolean isBasic(char c) {
return c < 0x80;
} public static int digit2codepoint(int d) throws Exception {
if (d < 26) {
// 0..25 : 'a'..'z'
return d + 'a';
} else if (d < 36) {
// 26..35 : '0'..'9';
return d - 26 + '0';
} else {
throw new Exception("BAD_INPUT");
}
} public static int codepoint2digit(int c) throws Exception {
if (c - '0' < 10) {
// '0'..'9' : 26..35
return c - '0' + 26;
} else if (c - 'a' < 26) {
// 'a'..'z' : 0..25
return c - 'a';
} else {
throw new Exception("BAD_INPUT");
}
} public static void main(String[] args) throws Exception {
String strPunycode ="xn--"+ CharsetTool.encode("北京大学");
System.out.println(strPunycode);
String strChinese = CharsetTool.decode("1lq90ic7fzpc");
System.out.println(strChinese);
}
}
运行结果为:
xn--1lq90ic7fzpc
北京大学
可以使用在线Punycode转码工具验证转码的正确性
遗憾的是并不支持“百度.中国”这种带有特殊字符“.”以及“中123国”这种混杂有数字的字符串转码

Punycode与中文互转的更多相关文章

  1. Unicode编码与中文互转

    /** * unicode编码转换为汉字 * @param unicodeStr 待转化的编码 * @return 返回转化后的汉子 */ public static String UnicodeTo ...

  2. c#unicode,中文互转

    /// <summary> /// 中文转unicode /// </summary> /// <returns></returns> public s ...

  3. Punycode转中文

    package cn.cnnic.ops.udf; public class GetChineseFromPunycode { static int TMIN = 1; static int TMAX ...

  4. JS 实现 unicode 中文互转

    // 转为unicode 编码 function encodeUnicode(str) { var res = []; for ( var i=0; i<str.length; i++ ) { ...

  5. RGB与16进制色互转

      点击进入新版 <前端在线工具站> CSS, JavaScript 压缩YUI compressor, JSPacker...HTML特殊符号对照表PNG,GIF,JPG... Base ...

  6. 个人永久性免费-Excel催化剂功能第29波-追加中国特色的中文相关自定义函数

    中文世界里,有那么几个需求在原生Excel里没提供,例如财务部的数字转大写金额,文字转拼音等,在其他插件里,大部分是以功能区菜单按钮的方式提供.Excel催化剂认为,最佳的使用方式乃是自定义函数的方式 ...

  7. C#设计模式总结

    一.引言 经过这段时间对设计模式的学习,自己的感触还是很多的,因为我现在在写代码的时候,经常会想想这里能不能用什么设计模式来进行重构.所以,学完设计模式之后,感觉它会慢慢地影响到你写代码的思维方式.这 ...

  8. jni数据传递——会不断的更新,测试没有问题,再整理进来。

    工作中遇到了ndk编程,其实核心就是java和本地的数据交互.现把所有数据类型的传递写成demo. 1,ini数组传递  我们实现传递8个数值过去,然后本地将八个数值放到数组,返回. java代码: ...

  9. C#设计模式总结(转)

    一.引言 经过这段时间对设计模式的学习,自己的感触还是很多的,因为我现在在写代码的时候,经常会想想这里能不能用什么设计模式来进行重构.所以,学完设计模式之后,感觉它会慢慢地影响到你写代码的思维方式.这 ...

随机推荐

  1. dom操作之开关灯

    <!DOCTYPE html> <html> <meta http-equiv="Content-Type" content="text/h ...

  2. cocos2d-x 2.2 wp8 开发手记

    最近有朋友问我有没有搞过  wp8 的cocos2dx开发 回复:额,没有.(感觉超没面子对方是妹子 = = ) 本着帮妹子试试的态度  就开始了 今天工作 第一我印象中wp8 开发必须要用 vs20 ...

  3. gif压缩

    保存选择颜色值小点会小很多

  4. apache开源项目--gora

    Gora 是一个应用于 NoSQL 数据库的 ORM 框架,支持包括:Apache HBase/Apache Cassandra

  5. wildfly9 配置SSL单向认证/https

    D:\>keytool -genkey -keystore cdi-init.keystore -alias cdi-init -keyalg RSA -keysize 2048 -validi ...

  6. Linux中的syslog 入门学习教程

    syslog是linux系统中默认的日志守护进程,默认的syslog配置文件是/etc/syslog.conf文件.程序.守护进程和内核提供了访问系统的日志信息.任何希望生成日志信息的程序都可以向sy ...

  7. uniq linux下去除重复行命令

    一,uniq干什么用的 文本中的重复行,基本上不是我们所要的,所以就要去除掉.linux下有其他命令可以去除重复行,但是我觉得uniq还是比较方便的一个.使用uniq的时候要注意以下二点 1,对文本操 ...

  8. lua package.path的使用

    需要用lua写一个工具,c++调用lua,然后这个lua要require其他lua脚本,在主lua里面设置package.path,但一直都失败,甚至lua都无法编译通过. project_path ...

  9. 从微信推送看Android Service的创建和销毁

    启动服务是有两组参数影响服务的状态. 1.在onStartCommand(Intent intent, int flags, int startId) 接口中返回值,例如 START_STICKY;  ...

  10. Spring_Springmvc_mybatis一般配置

    web.xml配置 <?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi=&quo ...