使用jQuery计算字符/短信数量

12

我使用 NobleCount 和以下代码计算字符数:

$('#message').NobleCount('#messageInfo',{
            max_chars: getMaxChars(),
            on_negative: function(t_obj, char_area, c_settings, char_rem){

            }
});
我希望有一个功能可以计算短信数量,如果达到限制,下一个160个字符就属于第二条短信以此类推。我可以使用像on_update、on_positive、on_negative和block_negative这样的参数。
我尝试过使用模运算但是它不起作用,有什么想法吗?

你想使用这个插件的解决方案,还是更通用的jQuery解决方案?单独实现这个并不难,但将其融入一个未知的插件可能会更困难! - lonesomeday
我刚刚发现了这个用于计算字符数的插件,但我还需要计算短信数量,所以我会感激任何解决方案。 - DarkLeafyGreen
11个回答

46
请注意,短信比你所表述的要复杂得多。
标准的“160个字符”短信使用奇怪的7位编码,覆盖了大多数ASCII、一些欧洲重音、各种符号如€、一些希腊大写字母(那些不像罗马字符的字母)。
如果您的消息使用其他字符,则可以使用UCS-2(类似于UTF-16但仅限BMP)将其编码为Unicode,限制为70个字符。实际上,规范指出UCS-2,但是表情符号(非BMP Unicode)可以通过短信发送,这意味着UTF-16正在被使用,在这种情况下,每个表情符号必须“使用”70个字符中的2个字符。
但是,一些语言可以使用“国家语言转换表”,这使用备用 7位编码。最明显的是土耳其语,但还有西班牙语、葡萄牙语和十种印度次大陆语言。这些都是标准的相对较新的添加项。
即使在7位编码中,也有一些字符被“转义”,这意味着它们“使用”了2个字符。在默认的7位编码中,它们是:{}[]\|^~€
如果您的消息超过160个字符,它可以使用“连接短信”,但是每条消息都会添加一个小标题,这意味着每个片段只有大约153个字符的空间。有两个不同版本的标题,大小不同,因此可能不是153个字符,而是152个(从记忆中)。对于Unicode连接的短信也是如此,小标题使每个片段为67个字符。
祝你好运!

2
function getSmsLength(v) { return v.replace(/([{}\[\]\\|\^~€])/g, "\\$1").replace(/\n/g, "--").length } - Andreas Louv

31

首先,字符计数非常容易。您只需要在字符串上使用length属性即可。要计算所需的短信数量,您需要除以160并向上取整(因为161个字符需要2条短信)。您的代码应该是这样的:

HTML:

<textarea name="message" value="" id="message"></textarea>
<p>
    <span id="remaining">160 characters remaining</span>
    <span id="messages">1 message(s)</span>
</p>

jQuery:

$(document).ready(function(){
    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)');
    });
});

查看 jsFiddle 示例。


酷脚本 @lonesomeday。如果您需要包括“主题”文本框的字符计数,该脚本会是什么样子?160个字符的短信限制还考虑了主题。另外,是否有一种方法可以防止在达到160个字符限制后在文本区域中输入,而不是让它溢出成第二条消息? - H. Ferrence
4
@lonesomeday的脚本不错。我发现如果你清空文本框,剩余字符数和消息数量都会被设置为0。为了克服这个问题,在设置剩余和消息文本属性之前,我加入了以下代码: if (chars == 0) { remaining = 160; messages = 1; } - Washburn
如果您的消息使用其他字符,可以使用UCS-2进行编码(类似于UTF-16但仅限于BMP),限制为70个字符。我该如何做到这一点? - nikli
4
除以160是错误的:对于连接的短信,6个字节的负载被标题占用(允许消息以正确顺序重新组装等)。由于负载总共只有140个字节,每个字符需要7位,这意味着在连接时每个短信只能发送153个字符。此页面解释了详细信息。 - psmears

16

这里有一个小插件,是我编写的第一个jQuery插件,我免费提供给你使用 ;) 你只需要使用以下代码来启动它:

Here is small plugin for you. It is my first jQuery plugin i give it for free ;) you just need to start it with:

$('#smsText').smsArea();

HTML:

 <b id="smsCount"></b> SMS (<b id="smsLength"></b>) Characters left
 <textarea id="smsText"></textarea>

JavaScript(更新于2014年8月18日):

(function($){
    $.fn.smsArea = function(options){

    var
    e = this,
    cutStrLength = 0,

    s = $.extend({

        cut: true,
        maxSmsNum: 3,
        interval: 400,

        counters: {
            message: $('#smsCount'),
            character: $('#smsLength')
        },

        lengths: {
            ascii: [160, 306, 459],
            unicode: [70, 134, 201]
        }
    }, options);


    e.keyup(function(){

        clearTimeout(this.timeout);
        this.timeout = setTimeout(function(){

            var
            smsType,
            smsLength = 0,
            smsCount = -1,
            charsLeft = 0,
            text = e.val(),
            isUnicode = false;

            for(var charPos = 0; charPos < text.length; charPos++){
                switch(text[charPos]){
                    case "\n": 
                    case "[":
                    case "]":
                    case "\\":
                    case "^":
                    case "{":
                    case "}":
                    case "|":
                    case "€":
                        smsLength += 2;
                    break;

                    default:
                        smsLength += 1;
                }


                if(text.charCodeAt(charPos) > 127 && text[charPos] != "€") isUnicode = true;
            }

            if(isUnicode){
                smsType = s.lengths.unicode;

            }else{
                smsType = s.lengths.ascii;
            }

            for(var sCount = 0; sCount < s.maxSmsNum; sCount++){

                cutStrLength = smsType[sCount];
                if(smsLength <= smsType[sCount]){

                    smsCount = sCount + 1;
                    charsLeft = smsType[sCount] - smsLength;
                    break
                }
            }

            if(s.cut) e.val(text.substring(0, cutStrLength));
            smsCount == -1 && (smsCount = s.maxSmsNum, charsLeft = 0);

            s.counters.message.html(smsCount);
            s.counters.character.html(charsLeft);

        }, s.interval)
    }).keyup()
}}(jQuery));

演示:http://jsfiddle.net/t32h0gj4/1/

注:这里有一些基本选项。

$('#smsText').smsArea({cut:false}); //Do not cut the SMS
$('#smsText').smsArea({maxSmsNum:2}); //2 SMS Max

1
这太棒了。谢谢分享!正是我在寻找的。请注意:“smsCount == -1 && (smsCount = 3, charsLeft = 0);”这行是多余的... - Andrew Plank
如果您在选项中使用cut:false,您将看到为什么存在这行代码。 - sulest
我对“asp textarea”不是很熟悉,你能查一下这个文本区支持哪些事件吗? - sulest
“£”被计算为92个字符。此外,脚本中似乎还有其他错误。但这是一个很好的基础可以继续建立。 - Onimusha
£不被计算为92个字符,它是一个Unicode字符。因此,1条短信=70个字符,剩余的68个字符将被正确计算。顺便说一句,@sulest的插件非常出色。 - Yaxhpal
显示剩余2条评论

3

一旦消息被解码,如Craig McQueen在这个帖子中所述,并且您拥有实际字符计数,为了计算所需的短信数量,只需要执行以下操作:

function cntsms(len){ return len<=0? 0: (len>160? Math.ceil(len/153): 1); }

我非常喜欢一行代码解决问题的方法。


非常棒的函数!但是,要考虑到第一条短信的长度为160个字符(而不是153个),以便在计算第2、3...条短信时使用以下代码:function cntsms(len){ return len<=0? 0: (len>160? Math.ceil((len-7)/153): 1); }(无法正确显示代码格式。反引号或缩进四个空格均不起作用...) - aanders77
@aanders77 警告:当消息超过160个7位字符的限制时,每个消息段的最大长度为153个7位字符,因为7个字符保留用于连接在160个字符之外。因此,第一个段也是153个字符长,使我发布的函数有效。这里提供参考。 - Niki Romagnoli

2
我认为以下脚本可以更准确地计算短信部分:
//field: a text box that contains the SMS Text
//cntField: a text box that will contain the remaining count of characters for each part
//smsCntfield: a text box that will contain the count of parts
//lang: 0 for English, 2 for Arabic
//maxLimit: Maximum count of characters to limit the TextBox, (ex: for 5 SMS in Arabic 331, in English 762
function textCounter(field, cntfield, smsCntfield, lang, maxlimit) {

    part1Count = 0;
    part2Count = 0;
    part3Count = 0;
    part4Count = 0;
    part5Count = 0;
    if (lang == 2) {
        // Arabic
        part1Count = 70;
        part2Count = 63;
        part3Count = 66;
        part4Count = 66;
        part5Count = 66;
    } else if (lang == 0) {
        // English
        part1Count = 160;
        part2Count = 145;
        part3Count = 152;
        part4Count = 152;
        part5Count = 152;
    }

    smsCount = 0;
    smsCharCnt = 0;
    smsTotalCount = 0;

    if (field.value.length <= part1Count) {
        smsCount = 1;
        smsCharCnt = part1Count;
        smsTotalCount = part1Count;
    } else if (field.value.length <= (part1Count + part2Count)) { 
        smsCount = 2;
        smsCharCnt = part2Count;
        smsTotalCount = (part1Count+part2Count);
    } else if (field.value.length <= (part1Count+part2Count+part3Count)) {
        smsCount = 3;
        smsCharCnt = part3Count;
        smsTotalCount = (part1Count+part2Count+part3Count);
    } else if (field.value.length <= (part1Count+part2Count+part3Count+part4Count)) { 
        smsCount = 4;
        smsCharCnt = part4Count;
        smsTotalCount = (part1Count+part2Count+part3Count+part4Count);
    } else if (field.value.length <= (part1Count+part2Count+part3Count+part4Count+part5Count)) { 
        smsCount = 5;
        smsCharCnt = part5Count;
        smsTotalCount = (part1Count+part2Count+part3Count+part4Count+part5Count);
    }

    if (field.value.length > maxlimit) {
        // if too long...trim it!
        field.value = field.value.substring(0, maxlimit);
    } else {
        cntfield.value = smsTotalCount - field.value.length;
        smsCntfield.value = smsCount;
    }

}

示例使用:

<html:textarea cols="30" rows="5" property="textEn"
                                                    title="Text English"
                                                    onkeydown="textCounter(document.form.textEn,document.form.remLen2,document.form.smsCount2,0,762)"
                                                    onkeyup="textCounter(document.form.textEn,document.form.remLen2,document.form.smsCount2,0,762)" />
                                                                                                <br>
                                                <input type="text" readonly="readonly" name="remLen2"
                                                    size="3" maxlength="3" value="160"
                                                    title="Char Count">

                                                (
                                                <input type="text" readonly="readonly" name="smsCount2"
                                                    size="1" maxlength="1" value="1"
                                                    title="SMS Parts' />">
                                                )

2
每个扩展表中的字符(GSM扩展字母表)由两个字符表示,实际最大长度动态计算为:160-k,其中k是消息中使用的扩展字符数量。
当使用8位参考号连接消息时,还必须考虑消息长度为153个字符。
Unicode长度为70个字符,而连接的长度为63个字符。

1

根据这里的问题,我尝试编写更好的解决方案。参考了几个最佳答案。

Javascript

<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script>
$(document).ready(function(){

    part1Count = 160;
    part2Count = 145;
    part3Count = 152;

    $('#message').keyup(function(){
        var chars = $(this).val().length;
            messages = 0;
            remaining = 0;
            total = 0;
        if (chars <= part1Count) {
            messages = 1;
            remaining = part1Count - chars;
        } else if (chars <= (part1Count + part2Count)) { 
            messages = 2;
            remaining = part1Count + part2Count - chars;
        } else if (chars > (part1Count + part2Count)) { 
            moreM = Math.ceil((chars - part1Count - part2Count) / part3Count) ;
            remaining = part1Count + part2Count + (moreM * part3Count) - chars;
            messages = 2 + moreM;
        }
        $('#remaining').text(remaining);
        $('#messages').text(messages);
        $('#total').text(chars);
        if (remaining > 1) $('.cplural').show();
            else $('.cplural').hide();
        if (messages > 1) $('.mplural').show();
            else $('.mplural').hide();
        if (chars > 1) $('.tplural').show();
            else $('.tplural').hide();
    });
    $('#message').keyup();
});
</script>

HTML

<textarea name="message" value="" id="message"></textarea>
<div>
    <div><span id="remaining">160</span>&nbsp;Character<span class="cplural">s</span> Remaining</div>
    <div>Total&nbsp;<span id="messages">1</span>&nbsp;Message<span class="mplural">s</span>&nbsp;<span id="total">0</span>&nbsp;Character<span class="tplural">s</span></div>
</div>

您可以在这里获取代码 http://www.mindrestingplace.com/2012/07/18/sms-character-counter/

希望这能解决您的问题。 谢谢


0

我更新了脚本(为了我的目的),也将主题包括在计数中。这是我想出来的:

$(document).ready(function(){
var $remaining = $('#remaining'),
    $messages = $remaining.next();

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

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

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

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

});

我测试过了,它可以正常工作。我还稍微修改了一下HTML:

<p>
<span id="remaining">160</span> characters remaining
<!--<span id="messages">1 message(s)</span>-->
</p>

现在我想找到一种方法,在表单中输入160个字符后防止按键。欢迎提出任何想法。 - H. Ferrence

0

虽然已经晚了一点,但这是我目前正在整理的内容。

字符限制设置为459,以允许连接的消息(由我的服务提供商设置),每160个字符使用一个文本单位。请注意,由于消息头等原因,每个初始单元之后的单元都包含少于160个字符模板。我还没有得到来自供应商的确切细分。

该脚本的关键区别在于字符计数对非标准GSM字符敏感,它们的ascii值在包括的数组中指定。如果输入了非标准字符,则计数为2,否则为1。

$('#sms-message').keyup(function(){
var     chars = $(this).val(),
        arr_chars = chars.split(''),
        remaining = $('#remaining'),
        messages = $('#messages'),
        count = 0;

    $.each(arr_chars, function(i, l){
        var     ascii = l.charCodeAt(0),
                ascii_val = parseInt(ascii),
                //array of special chars
                arr = [13, 47, 92, 123, 124, 125, 126, 128];

        if($.inArray(ascii_val, arr) !== -1) { count = count + 2; }
        else { count = count + 1; }
    });

            //inaccurate count, will have to be finetuned to provider specs
    var     units = Math.ceil(count / 160),
            remaining_chars = 459 - count;

        remaining.text(remaining_chars + ' characters remaining');
        messages.text(units + ' text unit(s)');

        if(remaining_chars < 0) {
            $(remaining).css('color', 'red');
        }
        else {
            $(remaining).css('color', 'black');
        }
});

1
我知道这个评论已经有点老了,但是我刚刚重构了一些旧代码并且抽出了一些非常类似于您这里的 JavaScript。希望您不介意,它已经被扩展了一些,并打包成了一个 jQuery 插件在 https://github.com/texh/jquery-smscharcount 很高兴给予归属/信用,如果您愿意的话,我也可以撤下它。 - nahanil
@晴天 终于成名了 :) - Eamonn

0
  $(function() {        
          $('#message').keydown(function() {
                  var mychars = $('#message').val().length; 
                  var mysms = Math.ceil(mychars / 160);

                           console.log (mysms); 
                           console.log (mychars +'' + ' characters'); 
           });
      });

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