国际短信字符计数

4

我发现了使用jQuery计算字符/短信数量,但它不支持中文、日文、泰文等国际字符。

var $remaining = $('#remaining'),
    $messages = $remaining.next();

$('#message').keyup(function(){
    var chars = this.value.length,
        messages = Math.ceil(chars / 160),
        remaining = messages * 160 - (chars % (messages * 160) || messages * 160);

    $remaining.text(remaining + ' characters remaining');
    $messages.text(messages + ' message(s)');
});

以下是一些错误的字符计数示例:

您好,請問你吃飯了嗎?<< 11个字符

สวัสดีคุณกินหรือ?<< 17个字符

こんにちは、あなたは食べていますか?<< 18个字符

안녕하세요, 당신이 먹는 거죠?<< 17个字符

हैलो, आप खाते हैं?<< 18个字符

Добры дзень, вы ясьце?<< 22个字符

如何与非ASCII字符配合使用?

大部分情况下似乎计算得很好。您好,请问你吃饭了吗?的长度为11个字符,日语、韩语和俄语的数字也没问题。您期望的是哪些数字呢?只有泰语和印地语可能会有偏差,但我不知道那里如何计算字符数。 - deceze
是的,正如你所说,泰语和印地语是不同的,ดี已经是2个字符了,所以,就像我找到的上面的jQuery一样,如何使它支持国际中文、泰语、日语、韩语、印地语、俄语。 - Ironman
2
是的,但是“您”是一个UTF-8字符。显然,您想要计算字节,而不是字符? - deceze
1个回答

10
你不能在这里真正地以“字符”计数。根据维基百科上的SMS文章,短信使用了三种不同的编码方式(7位GSM、8位GSM和UTF-16)。因此,首先你需要知道/决定要使用哪种编码方式。
如果你知道你将始终使用UTF-16,则可以计算字符串将占用多少16位代码单元。标准SMS可以由70个16位代码单元组成。但是这也将限制拉丁字符的消息长度为70。因此,如果你想对拉丁字符使用完整的160个字符(使用7位编码)或140个字符(使用8位编码),则需要区分这三种情况。
计算UTF-16 16位代码单元的示例:
var message = "您好,請問你吃飯了嗎?";

var utf16codeUnits = 0;

for (var i = 0, len = message.length; i < len; i++) {
  utf16codeUnits += message.charCodeAt(i) < 0x10000 ? 1 : 2;
}

顺便说一下,这个将会生成与您发布的“不正确”的数字相同的结果,因此您需要解释为什么您认为它们是错误的。


编辑

尽管已经被接受,但我快速编写了一个函数,可以正确(据我所知)计算短信消息的GSM 7位(如果可能)和UTF-16大小:http://jsfiddle.net/puKJb/


1
@Gumbo:我认为这里不适用。 GSM 7和8位编码不是基于Unicode代码点(charCodeAt返回的)。 - RoToRa
我认为SMS标准规定的是UCS-2而不是UTF-16。因此,只有两个字节的字符,没有BMP之外的字符。 - Craig McQueen
在 jsfiddle 代码中, gsm7bitUnits 不适用于带重音符号的字符(如西班牙语中常见的 "á")。 - kzfabi
@RoToRa 刚刚进行了更深入的调查,发现像 "á" 这样的字符是非 GSM 字符,因此包含它们的短信消息的最大长度为 70,并且这些字符被计算为 1 个单位。 - kzfabi
1
@adsun UTF-16编码将字符编码为一个单元(= 2字节= 16位)或两个单元(= 4字节= 32位)。所有代码点小于0x10000的字符使用一个单元,而所有其他具有更高代码点的字符使用两个单元。 - RoToRa
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接