给定长度的 NFA-for 字符串的最长 UTF 8 表示形式是什么?
What is the longest UTF8 representation of an NFC-form string of a given length?
上下文。
我正在将 C 写入 iCal (RFC 5545) 规范。它指定定界线的最大长度为 75 个八位字节,不包括定界符。鲁棒性原则和 W3C 字符模型都使我倾向于将以 UTF8 编码的输入字符串规范化为 NFC 形式(参见 Unicode Normalization Forms)。
读取输入行时,我想读入静态分配的缓冲区。但是,即使 NFC 格式小于 75,一行的 UTF8 表示也可能超过 75 个八位字节。因此,此缓冲区需要大于 75 个八位字节。我的问题是有多少。
问题。
NFC 格式最多为 75 个八位字节的 UTF8 字符串的最大八位字节长度是多少? (奖励积分:其 NFC 形式最多为 N 个八位字节。)
此外,这是有保证的和永久的,还是当前 Unicode 的未指定结果并且可能会更改?
这里有一些 Javascript 代码试图找到其 UTF-8 表示形式在转换为 NFD 并返回到 NFC 时缩小最多的 Unicode 代码点。似乎没有代码点缩小超过三倍。据我了解 Unicode 规范化算法,只有单个代码点必须以这种方式检查。
我认为,至少在理论上,这可能会在未来的 Unicode 版本中改变。但是有一个 stability policy regarding expansion of strings when normalizing to NFC (also see Can Unicode NFC normalization increase the length of a string?),所以我认为这不太可能改变:
Canonical mappings (Decomposition_Mapping property values) are always limited so that no string when normalized to NFC expands to more than 3× in length (measured in code units).
因此,分配一个比最大行长度大三倍的初始缓冲区似乎是一个合理的选择。
var maxRatio = 2;
var codePoints = [];
for (var i=0; i<0x110000; i++) {
// Exclude surrogates
if (i >= 0xD800 && i <= 0xDFFF) continue;
var nfd = String.fromCodePoint(i).normalize('NFD');
var nfc = nfd.normalize('NFC');
var nfdu8 = unescape(encodeURIComponent(nfd));
var nfcu8 = unescape(encodeURIComponent(nfc));
var ratio = nfdu8.length / nfcu8.length;
if (ratio > maxRatio) {
maxRatio = ratio;
codePoints = [ i ];
}
else if (ratio == maxRatio) {
codePoints.push(i);
}
}
console.log(`Max ratio: ${maxRatio}`);
for (codePoint of codePoints) {
// Exclude Hangul syllables
if (codePoint >= 0xAC00 && codePoint <= 0xD7AF) continue;
var nfd = String.fromCodePoint(codePoint).normalize('NFD');
var nfc = nfd.normalize('NFC');
console.log(
codePoint.toString(16).toUpperCase(),
encodeURIComponent(nfd),
encodeURIComponent(nfc)
);
}
上下文。
我正在将 C 写入 iCal (RFC 5545) 规范。它指定定界线的最大长度为 75 个八位字节,不包括定界符。鲁棒性原则和 W3C 字符模型都使我倾向于将以 UTF8 编码的输入字符串规范化为 NFC 形式(参见 Unicode Normalization Forms)。
读取输入行时,我想读入静态分配的缓冲区。但是,即使 NFC 格式小于 75,一行的 UTF8 表示也可能超过 75 个八位字节。因此,此缓冲区需要大于 75 个八位字节。我的问题是有多少。
问题。
NFC 格式最多为 75 个八位字节的 UTF8 字符串的最大八位字节长度是多少? (奖励积分:其 NFC 形式最多为 N 个八位字节。)
此外,这是有保证的和永久的,还是当前 Unicode 的未指定结果并且可能会更改?
这里有一些 Javascript 代码试图找到其 UTF-8 表示形式在转换为 NFD 并返回到 NFC 时缩小最多的 Unicode 代码点。似乎没有代码点缩小超过三倍。据我了解 Unicode 规范化算法,只有单个代码点必须以这种方式检查。
我认为,至少在理论上,这可能会在未来的 Unicode 版本中改变。但是有一个 stability policy regarding expansion of strings when normalizing to NFC (also see Can Unicode NFC normalization increase the length of a string?),所以我认为这不太可能改变:
Canonical mappings (Decomposition_Mapping property values) are always limited so that no string when normalized to NFC expands to more than 3× in length (measured in code units).
因此,分配一个比最大行长度大三倍的初始缓冲区似乎是一个合理的选择。
var maxRatio = 2;
var codePoints = [];
for (var i=0; i<0x110000; i++) {
// Exclude surrogates
if (i >= 0xD800 && i <= 0xDFFF) continue;
var nfd = String.fromCodePoint(i).normalize('NFD');
var nfc = nfd.normalize('NFC');
var nfdu8 = unescape(encodeURIComponent(nfd));
var nfcu8 = unescape(encodeURIComponent(nfc));
var ratio = nfdu8.length / nfcu8.length;
if (ratio > maxRatio) {
maxRatio = ratio;
codePoints = [ i ];
}
else if (ratio == maxRatio) {
codePoints.push(i);
}
}
console.log(`Max ratio: ${maxRatio}`);
for (codePoint of codePoints) {
// Exclude Hangul syllables
if (codePoint >= 0xAC00 && codePoint <= 0xD7AF) continue;
var nfd = String.fromCodePoint(codePoint).normalize('NFD');
var nfc = nfd.normalize('NFC');
console.log(
codePoint.toString(16).toUpperCase(),
encodeURIComponent(nfd),
encodeURIComponent(nfc)
);
}