punycode
This tag converts Punycode
Created by: hackvertor
Installed 1 times
Category: Convert
Created on: Wednesday, November 27, 2024 at 9:00:11 AM
Updated on: Tuesday, December 3, 2024 at 11:12:53 PM
Tag arguments
[]
Code
class punycode {
encode(input) {
return this.toPunycode(input);
}
decode(input) {
return this.fromPunycode(input);
}
matches(input) {
const punycodeRegex = /^xn--[a-z0-9-]+$/i;
const result = punycodeRegex.exec(input);
return result ? result : null;
}
toPunycode(input) {
const delimiter = "-";
const base = 36;
const tMin = 1;
const tMax = 26;
const skew = 38;
const damp = 700;
const initialBias = 72;
const initialN = 128;
const prefix = "xn--";
let n = initialN;
let delta = 0;
let bias = initialBias;
let output = "";
const basicChars = Array.from(input).filter(
(char) => char.charCodeAt(0) < 128,
);
output += basicChars.join("");
const handledCPCount = basicChars.length;
if (handledCPCount) {
output += delimiter;
}
let inputCodePoints = Array.from(input).map((char) => char.charCodeAt(0));
let handledCPIndex = handledCPCount;
while (handledCPIndex < inputCodePoints.length) {
let minCodePoint = Math.min(...inputCodePoints.filter((cp) => cp >= n));
delta += (minCodePoint - n) * (handledCPIndex + 1);
n = minCodePoint;
for (let cp of inputCodePoints) {
if (cp < n) {
delta++;
} else if (cp === n) {
let q = delta;
for (let k = base; ; k += base) {
let t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
if (q < t) {
break;
}
output += String.fromCharCode(
this.digitToBasic(t + ((q - t) % (base - t)), false),
);
q = Math.floor((q - t) / (base - t));
}
output += String.fromCharCode(this.digitToBasic(q, false));
bias = this.adapt(
delta,
handledCPIndex + 1,
handledCPIndex === handledCPCount,
);
delta = 0;
handledCPIndex++;
}
}
delta++;
n++;
}
return prefix + output;
}
fromPunycode(input) {
const base = 36;
const tMin = 1;
const tMax = 26;
const initialN = 128;
const initialBias = 72;
const delimiter = "-";
if (!input.startsWith("xn--")) {
throw new Error("Not a valid Punycode string");
}
input = input.slice(4);
let n = initialN;
let i = 0;
let bias = initialBias;
let output = [];
const delimiterIndex = input.lastIndexOf(delimiter);
if (delimiterIndex > -1) {
output = Array.from(input.slice(0, delimiterIndex)).map((char) =>
char.charCodeAt(0),
);
input = input.slice(delimiterIndex + 1);
}
let inputIndex = 0;
while (inputIndex < input.length) {
let oldi = i;
let w = 1;
for (let k = base; ; k += base) {
const digit = this.basicToDigit(input.charCodeAt(inputIndex++));
i += digit * w;
const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
if (digit < t) {
break;
}
w *= base - t;
}
bias = this.adapt(i - oldi, output.length + 1, oldi === 0);
n += Math.floor(i / (output.length + 1));
i %= output.length + 1;
output.splice(i++, 0, n);
}
return String.fromCodePoint(...output);
}
basicToDigit(codePoint) {
if (codePoint - 48 < 10) {
return codePoint - 22;
}
if (codePoint - 65 < 26) {
return codePoint - 65;
}
if (codePoint - 97 < 26) {
return codePoint - 97;
}
return base;
}
digitToBasic(digit, flag) {
return digit + 22 + 75 * (digit < 26) - ((flag ? 1 : 0) << 5);
}
adapt(delta, numPoints, firstTime) {
const base = 36;
const tMin = 1;
const tMax = 26;
const skew = 38;
const damp = 700;
delta = firstTime ? Math.floor(delta / damp) : delta >> 1;
delta += Math.floor(delta / numPoints);
let k = 0;
while (delta > ((base - tMin) * tMax) >> 1) {
delta = Math.floor(delta / (base - tMin));
k += base;
}
return k + Math.floor(((base - tMin + 1) * delta) / (delta + skew));
}
}