C#实现中文域名搜索引擎编码/解码-PunyCode编码与解码
大家都知道白底收录 的中文域名为转为为xn--开头的字符串。
这个是怎么实现 的呢,我们先来分析一下原理
先来科普个知识
[C#] 纯文本查看 复制代码 Punycode是一个根据RFC 3492标准而制定的编码系统,主要用於把域名从地方语言所采用的Unicode编码转换成为可用於DNS系统的编码。Punycode可以防止IDN欺骗。
国际化域名IDNs
早期的DNS(Domain Name System)是只支持英文域名解析。在IDNs(国际化域名Internationalized Domain Names)推出以后,
为了保证兼容以前的DNS,所以,对IDNs进行punycode转码,转码后的punycode就由26个字母+10个数字,还有“-”组成。
浏览器对punycode的支持
目前,因为操作系统的核心都是英文组成,DNS服务器的解析也是由英文代码交换,所以DNS服务器上并不支持直接的中文域名解析,
所有中文域名的解析都需要转成punycode码,然后由DNS解析punycode码。其实目前所说和各种浏览器完美支持中文域名,
只是浏览器软里面主动加入了中文域名自动转码,不需要原来的再次安装中文域名转码控件来完成整个流程。
完全免费,双向转换 中文域名转码就是将中文字符串转成punycode标准编码的字符串。
本服务目前支持GBK,GB2312编码和punycode编码的相互转换。
域名串不允许有除“-”以外的标点符号,包括空格。 可以夹杂中文和英文。 可以输入全角英文字母,全角字母不区分大小写。
具体怎么实现呢,大家直接看帮助类
[C#] 纯文本查看 复制代码 public class PunyCodeHelper
{
/* Punycode parameters */
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 = '-';
public static string EncodingDomain(string domain)
{
domain = domain.Replace("。", ".");
string[] domainArray = domain.Split(new string[] { "." }, StringSplitOptions.None);
string result = "";
foreach (string item in domainArray)
{
if (item == "")
{
result += ".";
continue;
}
result += "xn--" + Encode(item) + ".";
}
if (result[result.Length - 1] == '.') result = result.Substring(0, result.Length - 1);
return result;
}
public static string DecodingDomain(string domain)
{
domain = domain.Replace("。", ".");
string[] domainArray = domain.Split(new string[] { "." }, StringSplitOptions.None);
string result = "";
foreach (string item in domainArray)
{
if (item == "")
{
result += ".";
continue;
}
string item2 = item;
if (item2.Length > 4 && item2.Substring(0, 4) == "xn--")
{
result += Decode(item2.Substring(4, item2.Length - 4)) + ".";
}
}
if (result[result.Length - 1] == '.') result = result.Substring(0, result.Length - 1);
return result;
}
public static string Encode(string input)
{
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[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 = int.MaxValue;
// Find the minimum code point >= n
for (int i = 0; i < input.Length; i++)
{
int c = input[i];
if (c >= n && c < m)
{
m = c;
}
}
if (m - n > (int.MaxValue - 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[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();
}
public static string Decode(string input)
{
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[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[d++];
int digit = codepoint2digit(c);
if (digit > (int.MaxValue - 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) > int.MaxValue - 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();
}
private static int adapt(int delta, int numpoints, bool 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);
}
private static bool isBasic(char c)
{
return c < 0x80;
}
private static int digit2codepoint(int d)
{
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");
}
}
private static int codepoint2digit(int c)
{
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");
}
}
}
然后直接在页面下这样写即可
[C#] 纯文本查看 复制代码 //e是编码,d是解码
type = InputHelper.GetInputString(Request["type"]).Trim();
//传过来的数据
key = InputHelper.GetInputString(Request["key"]).Trim();
if (type == "e")
{
html = key;
foreach (Match item in Regex.Matches(html, "([\u4e00-\u9fa5]+)", RegexOptions.IgnoreCase | RegexOptions.Compiled))
{
html = Regex.Replace(html, item.Groups[1].Value.Trim(), PunyCodeHelper.EncodingDomain(item.Groups[1].Value.Trim()), RegexOptions.IgnoreCase | RegexOptions.Compiled);
}
}
else if (type == "d")
{
html = key;
foreach (Match item in Regex.Matches(html, "(xn--\\w+)", RegexOptions.IgnoreCase | RegexOptions.Compiled))
{
html = Regex.Replace(html, item.Groups[1].Value.Trim(), PunyCodeHelper.DecodingDomain(item.Groups[1].Value.Trim()), RegexOptions.IgnoreCase | RegexOptions.Compiled);
}
}
在线测试效果。https://seo.ruituoyun.com/punycode
|