【问题标题】:Can I depend on the behavior of charCodeAt() and fromCharCode() to remain the same?我可以依靠 charCodeAt() 和 fromCharCode() 的行为保持不变吗?
【发布时间】:2011-09-08 16:30:44
【问题描述】:

我编写了一个个人网络应用程序,它使用charCodeAt()将用户输入的文本转换为相关的字符代码(例如转换为8839进行存储),然后发送到Perl,它将它们发送到 MySQL。为了检索输入文本,该应用使用fromCharCode() 将数字转换回文本。

我选择这样做是因为 Perl 的 unicode 支持很难正确处理。所以 Perl 和 MySQL 只看到数字,这让生活变得简单了很多。

我的问题是我可以依靠fromCharCode() 始终将像 8834 这样的数字转换为相关字符吗?我不知道它使用什么标准,但是假设它使用UTF-8,如果将来改为使用UTF-16,如果没有向后兼容性,这显然会破坏我的程序。

我知道我对这些概念的想法不是很清楚,因此如果我表现出误解,请注意澄清。

【问题讨论】:

  • 您也可以使用escape/unescapeencodeURIComponent/decodeURIComponent对这些数据进行编码和解码。

标签: javascript mysql perl unicode


【解决方案1】:

2018 年可以使用 String.codePointAt() 和 String.fromCodePoint()。

即使字符不在基本多语言平面 (BMP) 中,这些方法也有效。

【讨论】:

    【解决方案2】:

    正如其他答案中所指出的,fromCharCode()toCharCode() 处理基本多语言平面 (BMP) 中任何代码点的 Unicode 代码点。 JavaScript 中的字符串是 UCS-2 编码的,BMP 之外的任何代码点都表示为两个 JavaScript 字符。这些都不会改变。

    要在 JavaScript 端处理任何 Unicode 字符,可以使用以下函数,该函数将返回一个数字数组,表示指定字符串的 Unicode 代码点序列:

    var getStringCodePoints = (function() {
        function surrogatePairToCodePoint(charCode1, charCode2) {
            return ((charCode1 & 0x3FF) << 10) + (charCode2 & 0x3FF) + 0x10000;
        }
    
        // Read string in character by character and create an array of code points
        return function(str) {
            var codePoints = [], i = 0, charCode;
            while (i < str.length) {
                charCode = str.charCodeAt(i);
                if ((charCode & 0xF800) == 0xD800) {
                    codePoints.push(surrogatePairToCodePoint(charCode, str.charCodeAt(++i)));
                } else {
                    codePoints.push(charCode);
                }
                ++i;
            }
            return codePoints;
        }
    })();
    
    var str = "?";
    var codePoints = getStringCodePoints(s);
    
    console.log(str.length); // 2
    console.log(codePoints.length); // 1
    console.log(codePoints[0].toString(16)); // 1d306
    

    【讨论】:

    • 感谢您的回答。到目前为止,我还没有移位位的经验(在这种情况下或任何其他情况下),并且很想对它们有一个很好的理解,你能推荐任何处理这些技术的书籍/资源吗?
    【解决方案3】:

    我选择这样做是因为 Perl 的 unicode 支持很难正确处理。

    这是ɴᴏᴛ真的!

    Perl 拥有所有主要编程语言中最强大的 Unicode 支持。如果您使用 Perl,使用 Unicode 比使用 C、C++、Java、C 中的任何一种都容易, Python、Ruby、PHP 或 Javascript。这不是没有受过教育、盲目效忠的夸张和助长主义。这是基于十多年专业经验和学习的深思熟虑的评估。

    天真的用户遇到的问题几乎总是因为他们在 Unicode 是什么上自欺欺人。头号最糟糕的大脑错误是认为 Unicode 类似于 ASCII 但更大。这是绝对和完全错误的。正如我在其他地方所写:

    Uɴɪᴄᴏᴅᴇ 只是相对于 ᴀsᴄɪɪ 的一些扩大的字符集,这从根本上和批判性地说 不是真的。充其量,这仅适用于呆板的 ɪsᴏ‑10646。 Uɴɪᴄᴏᴅᴇ 包括更多,仅将数字分配给字形:整理和比较规则,三种形式的大小写,非字母大小写,多代码点大小写折叠,规范和兼容的组合和分解规范化形式、序列化形式、字素簇、分词和换行、脚本、数字等值、宽度、双向性、镜像、打印宽度、逻辑排序排除、字形变体、上下文行为、语言环境、正则表达式、组合类的多种形式、多个分解类型,成百上千非常有用的属性,还有更多‼

    是的,很多,但这与 Perl 无关。它与Unicode有关。当您使用 Unicode 时,Perl 允许您访问这些东西不是一个错误,而是一个特性。那些其他语言允许您完全访问 Unicode 绝不可以解释为对他们有利:相反,这些都是可能严重程度最高的主要错误,因为如果您无法工作如果 Unicode 在 21 世纪出现,那么这种语言是原始的、破碎的,根本无法满足现代文本处理的苛刻要求。

    Perl 不是。用 Perl 做这些事情要比用其他语言容易得多。在他们中的大多数人中,您甚至无法开始解决他们的设计缺陷。你简直是完蛋了。如果一种语言不提供完整的 Unicode 支持,则它不适合本世纪;丢弃它。

    Perl 使 Unicode 比那些不能正确使用 Unicode 的语言更容易做到。

    this answer 中,您会在前面找到在 Perl 中处理 Unicode 的七个简单步骤,在同一答案的底部,您会找到一些有用的样板代码。了解它,然后使用它。不要接受破碎。您必须先学习 Unicode,然后才能使用 Unicode。

    这就是为什么没有简单的答案。 Perl 使使用 Unicode 变得很容易,假设您了解 Unicode 的真正含义。而且,如果您要处理外部源,则必须安排该源使用某种编码。

    还阅读了我所说的关于 ?????? ?????????? 的所有内容。这些是你真正需要了解的事情。 Rule #49 的另一个损坏问题是 Javascript 损坏,因为它不会以完全相同的方式处理所有有效的 Unicode 代码点,而不管它们的平面如何。 Javascript 在几乎所有其他方面也被破坏了。它不适合 Unicode 工作。只需 规则 #34 就会杀死你,因为你无法让 Javascript 遵循关于 things like \wUnicode regexes 中定义的所需标准。

    令人惊讶的是,有多少种语言对 Unicode 完全没用。但是 Perl 绝对是不是其中之一!

    【讨论】:

    • 感谢您的回答。正是您引用的那个答案让我不想处理 Perl Unicode。对于我需要的东西(在数据库中保存偶尔的数学字符),将数据作为数字数组发送似乎更简单,而不是处理 Perl 和 MySQL 关于 Unicode 的复杂性。
    • 顺便说一下,Perl 是我最喜欢的语言之一。可以看到我的头像是Higher Order Perl的封面图片。 :)
    • 有点强硬,这个答案。我接受 JavaScript 对于 Unicode 工作来说并不理想,但对于客户端脚本并没有真正的替代方案,因此我们必须充分利用它。仍然 +1。
    【解决方案4】:

    在我看来,它不会崩溃。

    阅读 Joel Spolsky 在Unicode and character encoding 上的文章。文章相关部分引述如下:

    每个字母 字母表被分配了一个数字 Unicode 联盟是 像这样写:U+0639。这 数字称为代码点。 U+ 表示“Unicode”,数字是 十六进制。英文字母 A 会 是 U+0041。

    这个神奇的数字是用 utf-8 还是 utf-16 或任何其他编码编码都没有关系。这个数字还是一样的。

    【讨论】:

    【解决方案5】:

    fromCharCodetoCharCode 处理 Unicode 代码点,即 0 到 65535(0xffff) 之间的数字,假设所有字符都在基本多语言平面 (BMP) 中。 Unicode 和代码点是永久性的,因此您可以相信它们永远保持不变。

    UTF-8 和 UTF-16 等

    编码 采用代码点(数字)流并输出字节流。 JavaScript 有点奇怪,根据 UTF-16 规则,必须通过两次调用 toCharCode 来构造 BMP 之外的字符。但是,您遇到的几乎所有字符(包括中文、日文等)都在 BMP 中,因此即使您不处理这些情况,您的程序也能正常工作。

    您可以做的一件事是将数字转换回字节(大端 int16 格式),并将生成的文本解释为 UTF-16。 fromCharCodetoCharCode 的行为在当前的 JavaScript 实现中是固定的,永远不会改变。

    【讨论】:

    • 谢谢!如果用户输入的内容不在“基本多语言平面”中,会发生什么情况? toCharCode是不是对付不了?
    • @Hawramani 不,它只返回两个看起来很奇怪的字符,它们不是 Unicode 代码点(第一个在 0xd8000xdbff 之间,第二个在 0xdc000xdff 之间)。更新了答案。
    • 所以fromCharCodetoCharCode 显然不处理代码points,而是代码units。这意味着您必须处理单独的代码单元序列,即将它们转换为 JavaScript 或 Perl 端的标量值。
    • @Hawramani 是的,没错。您必须手动发出两个 UCS-2 代码点,而不是用一个 Unicode 字符编写 document.write(String.fromCharCode(0x1D49C)),当它们在另一个宽度上组合时,将成为正确的东西。例如,document.write(String.fromCharCode(0xD835,0xDC9C))。非常讨厌。
    【解决方案6】:

    JavaScript 字符串是 UTF-16,这不会改变。

    但不要忘记 UTF-16 是可变长度编码。

    【讨论】:

    • 可变长度编码是什么意思,它会影响我使用这两个函数来回转换字母的应用程序吗?
    • @Hawramani:这意味着每个标量值由可变数量的 16 位代码单元表示。是的,这是您必须处理的事情,因为您不再使用代码点,而是使用代码单元。不过没那么难,只需在 Perl 脚本中明确说明您有一个 UTF-16 代码单元序列,而不是 Unicode 代码点序列。
    • @Philipp:嗯。我的程序所做的是将输入中的值转换为数组。例如,如果用户输入单词“Programming”,它就变成了这个数组:[80,114,111,103,114,97,109,109,105,110,103],然后将其作为字符串发送到 Perl,Perl 将其发送到 MySQL 而不进行任何处理。 MySQL 也仅将其视为字符串。所有的 unicode 处理都是在 JavaScript 中完成的,Perl 和 MySQL 可以使用 ASCII,它仍然可以工作。在我看来,您提到的内容在这种情况下不会引起问题,对吗?
    • @Hawramani:如何将代码单元数组转换为 Perl 字符串?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-18
    • 2013-12-30
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多