【JavaScript】字符串處理函數集合

    var $string = {},
        toString,
        template,
        parseURL,
        buildURL,
        mapQuery,
        test,
        contains,
        trim,
        clean,
        camelCase,
        hyphenate,
        capitalize,
        escapeRegExp,
        toInt,
        toFloat,
        toSingleLine,
        toHtml,
        toTitle,
        toQueryPair,
        toQueryString,

        hexToRgb,
        rgbToHex,
        stripScripts,
        substitute,
        replaceAll,

        byteLength,
        cutRight,
        cutByBytes,
        isNumber,
        isEmail,

        encodeHtmlSimple,
        decodeHtmlSimple,
        decodeHtmlSimple2,
        encodeHtmlAttributeSimple,
        encodeHtmlAttribute,
        encodeHtml,
        encodeScript,
        encodeHrefScript,
        encodeRegExp,
        encodeUrl,
        encodeUriComponent,
        vaildURL,
        getCharWidth,
        cutByWidth;


    /**
     * 將任意變量轉換爲字符串的方法
     * @param o
     * @returns {string}
     */
    toString = function(o){
        return (o + "");
    };

    /**
     * 多行或單行字符串模板處理
     *
     * @method template
     * @memberOf string
     *
     * @return {String} 返回與數據對象合成後的字符串
     *
     * @example
     * <script type="text/html" id="user_tmpl">
     *   <% for ( var i = 0; i < users.length; i++ ) { %>
     *     <li><a href="<%=users[i].url%>"><%=users[i].name%></a></li>
     *   <% } %>
     * </script>
     *
     * Jx().$package(function(J){
     *  // 用 obj 對象的數據合併到字符串模板中
     *  template("Hello, {name}!", {
     *      name:"Beauty"
     *  });
     * };
     */

    template = (function(){
        var openTag = '<%',
            closeTag = '%>',
            retTag = '$return',
            vars = 'var ',
            varsInTpl,
            codeArr = ''.trim ?
                [retTag + ' = "";', retTag + ' +=', ';', retTag + ';', 'print=function(){' + retTag + '+=[].join.call(arguments,"")},'] :
                [retTag + ' = [];', retTag + '.push(', ')', retTag + '.join("");', 'print=function(){' + retTag + '.push.apply(arguments)},'],
            keys = ('break,case,catch,continue,debugger,default,delete,do,else,false,finally,for,function,if'
                + ',in,instanceof,new,null,return,switch,this,throw,true,try,typeof,var,void,while,with'
                // Reserved words
                + ',abstract,boolean,byte,char,class,const,double,enum,export,extends,final,float,goto'
                + ',implements,import,int,interface,long,native,package,private,protected,public,short'
                + ',static,super,synchronized,throws,transient,volatile'

                // ECMA 5 - use strict
                + ',arguments,let,yield').split(','),
            keyMap = {};

        for (var i = 0, len = keys.length; i < len; i++) {
            keyMap[keys[i]] = 1;
        }

        function _getCompileFn(source) {
            vars = 'var ';
            varsInTpl = {};
            varsInTpl[retTag] = 1;
            var openArr = source.split(openTag),
                tmpCode = '';

            for (var i = 0, len = openArr.length; i < len; i++) {
                var c = openArr[i],
                    cArr = c.split(closeTag);
                if (cArr.length == 1) {
                    tmpCode += _html(cArr[0]);
                } else {
                    tmpCode += _js(cArr[0]);
                    tmpCode += cArr[1] ? _html(cArr[1]) : '';
                }
            }

            var code = vars + codeArr[0] + tmpCode + 'return ' + codeArr[3];
            return new Function('$data', code);
        }

        function _html(s) {
            s = s
                .replace(/('|"|\\)/g, '\\$1')
                .replace(/\r/g, '\\r')
                .replace(/\n/g, '\\n');

            s = codeArr[1] + '"' + s + '"' + codeArr[2];

            return s + '\n';
        }

        function _js(s) {
            if (/^=/.test(s)) {
                s = codeArr[1] + s.substring(1).replace(/[\s;]*$/, '') + codeArr[2];
            }
            dealWithVars(s);

            return s + '\n';
        }

        function dealWithVars(s) {
            s = s.replace(/\/\*.*?\*\/|'[^']*'|"[^"]*"|\.[\$\w]+/g, '');
            var sArr = s.split(/[^\$\w\d]+/);
            for (var i = 0, len = sArr.length; i < len; i++) {
                var c = sArr[i];
                if (!c || keyMap[c] || /^\d/.test(c)) {
                    continue;
                }
                if (!varsInTpl[c]) {
                    if (c === 'print') {
                        vars += codeArr[4];
                    } else {
                        vars += (c + '=$data.hasOwnProperty("' + c + '")?$data.' + c + ':window.' + c + ',');
                    }
                    varsInTpl[c] = 1;
                }
            }
        }


        var cache = {};

        /**
         * @param {String} str 模板字符串
         * @param {Object} data 要套入的數據對象
         */
        return function (str, data) {
            // Figure out if we're getting a template, or if we need to
            // load the template - and be sure to cache the result.
            var fn = !/\W/.test(str) ?
                cache[str] || (cache[str] = _getCompileFn(document.getElementById(str).innerHTML)) :
                _getCompileFn(str);

            // Provide some basic currying to the user
            return data ? fn(data) : fn;
        };

    })();


    /**
     * 分解 URL 爲一個對象,成員爲:scheme, user, pass, host, port, path, query, fragment
     *
     * @method parseURL
     * @memberOf string
     *
     * @param {String} str URL 地址
     * @return {Object} 若是解析失敗則返回 null
     */
    parseURL = function(str) {
        var ret = null;

        if (null !== (ret = parseURL.RE.exec(str))) {
            var specObj = {};
            for (var i = 0, j = parseURL.SPEC.length; i < j ; i ++) {
                var curSpec = parseURL.SPEC[i];
                specObj[curSpec] = ret[i + 1];
            }
            ret = specObj;
            specObj = null;
        }

        return ret;
    };

    /**
     * 將一個對象(成員爲:scheme, user, pass, host, port, path, query, fragment)從新組成爲一個字符串
     *
     * @method buildURL
     * @memberOf string
     *
     * @param {Object} obj URl 對象
     * @return {String} 若是是可接受的 url 則返回 true
     */
    buildURL = function(obj) {
        var ret = '';

        // prefix & surffix
        var prefix = {},
            surffix = {};

        for (var i = 0, j = parseURL.SPEC.length; i < j ; i ++) {
            var curSpec = parseURL.SPEC[i];
            if (!obj[curSpec]) {
                continue;
            }
            switch (curSpec) {
                case 'scheme':
                    surffix[curSpec] = '://';
                    break;
                case 'pass':
                    prefix[curSpec] = ':';
                case 'user':
                    prefix['host'] = '@';
                    break;
                //case 'host':
                case 'port':
                    prefix[curSpec] = ':';
                    break;
                //case 'path':
                case 'query':
                    prefix[curSpec] = '?';
                    break;
                case 'fragment':
                    prefix[curSpec] = '#';
                    break;
            }

            // rebuild
            if (curSpec in prefix) {
                ret += prefix[curSpec];
            }
            if (curSpec in obj) {
                ret += obj[curSpec];
            }
            if (curSpec in surffix) {
                ret += surffix[curSpec];
            }
        }

        prefix = null;
        surffix = null;
        obj = null;

        return ret;
    };

    /**
     * @ignore
     */
    parseURL.SPEC = ['scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'];
    parseURL.RE = /^([^:]+):\/\/(?:([^:@]+):?([^@]*)@)?(?:([^/?#:]+):?(\d*))([^?#]*)(?:\?([^#]+))?(?:#(.+))?$/;

    /**
     * 將 uri 的查詢字符串參數映射成對象
     *
     * @method mapQuery
     * @memberOf string
     *
     * @param {String} uri 要映射的 uri
     * @return {Object} 按照 uri 映射成的對象
     *
     * @example
     * Jx().$package(function(J){
     *  var url = "http://web.qq.com/?qq=4765078&style=blue";
     *  // queryObj 則獲得一個{qq:"4765078", style:"blue"}的對象。
     *  var queryObj = mapQuery(url);
     * };
     */
    mapQuery = function(uri){
        //window.location.search
        uri = uri && uri.split('#')[0] || window.location.search; //remove hash
        var i,
            key,
            value,
            index = uri.indexOf("?"),
            pieces = uri.substring(index + 1).split("&"),
            params = {};
        if (index === -1) {//若是連?號都沒有,直接返回,再也不進行處理. az 2011/5/11
            return params;
        }

        for (i = 0; i < pieces.length; i++) {
            try {
                index = pieces[i].indexOf("=");
                key = pieces[i].substring(0, index);
                value = pieces[i].substring(index + 1);
                if (!(params[key] = unescape(value))) {
                    throw new Error("uri has wrong query string when run mapQuery.");
                }
            }
            catch (e) {
                //J.out("錯誤:[" + e.name + "] "+e.message+", " + e.fileName+", 行號:"+e.lineNumber+"; stack:"+typeof e.stack, 2);
            }
        }
        return params;
    };

    /**
     *
     * test的方法
     *
     * @memberOf string
     *
     * @param {String|RegExp} regex 正則表達式,或者正則表達式的字符串
     * @param {String} params 正則的參數
     * @return {Boolean} 返回結果
     */
    test = function(string, regex, params){
        return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(string);
    };

    /**
     * 判斷是否含有指定的字符串
     *
     * @memberOf string
     * @name contains
     * @function
     * @param {String} string 是否含有的字符串
     * @param {String} separator 分隔符,可選
     * @return {Boolean} 若是含有,返回 true,不然返回 false
     */
    contains = function(string1, string2, separator){
        return (separator) ? (separator + string1 + separator).indexOf(separator + string2 + separator) > -1 : string1.indexOf(string2) > -1;
    };

    /**
     * 清除字符串開頭和結尾的空格
     *
     * @memberOf string
     *
     * @return {String} 返回清除後的字符串
     */
    trim = function(string){
        return String(string).replace(/^\s+|\s+$/g, '');
    };

    /**
     * 清除字符串開頭和結尾的空格,並把字符串之間的多個空格轉換爲一個空格
     *
     * @memberOf string
     *
     * @return {String} 返回清除後的字符串
     */
    clean = function(string){
        return trim(string.replace(/\s+/g, ' '));
    };

    /**
     * 將「-」鏈接的字符串轉換成駝峯式寫法
     *
     * @memberOf string
     *
     * @return {String} 返回轉換後的字符串
     */
    camelCase = function(string){
        return string.replace(/-\D/g, function(match){
            return match.charAt(1).toUpperCase();
        });
    };

    /**
     * 將駝峯式寫法字符串轉換成「-」鏈接的
     *
     * @memberOf string
     *
     * @return {String} 返回轉換後的字符串
     */
    hyphenate = function(string){
        return string.replace(/[A-Z]/g, function(match){
            return ('-' + match.charAt(0).toLowerCase());
        });
    };

    /**
     * 將字符串轉換成全大寫字母
     *
     * @memberOf string
     *
     * @return {String} 返回轉換後的字符串
     */
    capitalize = function(string){
        return string.replace(/\b[a-z]/g, function(match){
            return match.toUpperCase();
        });
    };

    /**
     * 轉換 RegExp 正則表達式
     *
     * @memberOf string
     *
     * @return {String} 返回轉換後的字符串
     */
    escapeRegExp = function(string){
        return string.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
    };

    /**
     * 將字符串轉換成整數
     *
     * @memberOf string
     *
     * @return {Number} 返回轉換後的整數
     */
    toInt = function(string, base){
        return parseInt(string, base || 10);
    };

    /**
     * 將字符串轉換成浮點數
     *
     * @memberOf string
     * @param {String} string 要轉換的字符串
     * @return {Number} 返回轉換後的浮點數
     */
    toFloat = function(string){
        return parseFloat(string);
    };

    /**
     * 將帶換行符的字符串轉換成無換行符的字符串
     *
     * @memberOf string
     * @param {String} str 要轉換的字符串
     * @return {String} 返回轉換後的字符串
     */
    toSingleLine = function(str){
        return String(str).replace(/\r/gi,"")
            .replace(/\n/gi,"");
    };

    /**
     * 將字符串轉換成html源碼
     *
     * @memberOf string
     * @param {String} str 要轉換的字符串
     * @return {String} 返回轉換後的html代碼字符串
     */
    toHtml = function(str){
        return String(str).replace(/&/gi,"&")
            .replace(/\\/gi,"\")
            .replace(/\'/gi,"'")
            .replace(/\"/gi,""")
            .replace (/</gi,"<")
            .replace(/>/gi,">")
            .replace(/ /gi," ")
            .replace(/\r\n/g,"<br />")
            .replace(/\n\r/g,"<br />")
            .replace(/\n/g,"<br />")
            .replace(/\r/g,"<br />");
    };

    /**
     * 將字符串轉換成用於title的字符串
     *
     * @memberOf string
     * @param {String} str 要轉換的字符串
     * @return {Number} 返回轉換後的in title字符串
     */
    toTitle = function(str){
        return String(str).replace(/\\/gi,"\\")
            .replace(/\'/gi,"\'")
            .replace(/\"/gi,"\'");
    };

    /**
     * 將顏色 Hex 寫法轉換成 RGB 寫法
     *
     * @memberOf string
     * @return {String} 返回轉換後的字符串
     * @author rewrite by dmyang
     */
    hexToRgb = function(string){
        var hex = string.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
        var _convert = function(array) {
            var length = array.length;
            if (length !== 3) return null;
            for(var i=0, value; i<length; i++) {
                value = array[i];
                if(value.length === 1) value += value;
                array[i] = parseInt(value, 16);
            }
            return 'rgb(' + array + ')';
        };
        return (hex) ? _convert(hex.slice(1)) : null;
    };

    /**
     * 將顏色 RGB 寫法轉換成 Hex 寫法
     *
     * @memberOf string
     * @return {String} 返回轉換後的字符串
     * @author rewrite by dmyang
     */
    rgbToHex = function(string){
        var r = string.match(/\d{1,3}/g);
        return (r) ? '#' + ((1 << 24) + ((r[0] << 0) << 16) + ((r[1] << 0) << 8) + (r[2] << 0)).toString(16).slice(1) : null;
    };

    /**
     * 脫去script標籤
     *
     * @memberOf string
     * @return {String} 返回轉換後的字符串
     */
    stripScripts = function(string, option){
        var scripts = '';
        var text = string.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
            scripts += arguments[1] + '\n';
            return '';
        });
        if (option === true){
            $exec(scripts);
        }else if($type(option) == 'function'){
            option(scripts, text);
        }
        return text;
    };

    /**
     * 。。。。
     *
     * @memberOf string
     * @param {Object} obj 要轉換成查詢字符串的對象
     * @return {String} 返回轉換後的查詢字符串
     */
    toQueryPair = function(key, value) {
        return encodeURIComponent(String(key)) + "=" + encodeURIComponent(String(value));
    };

    /**
     * 。。。。
     *
     * @memberOf string
     * @param {Object} obj 要轉換成查詢字符串的對象
     * @return {String} 返回轉換後的查詢字符串
     */
    toQueryString = function(obj){
        var result=[];
        for(var key in obj){
            result.push(toQueryPair(key, obj[key]));
        }
        return result.join("&");
    };

    /**
     * 。。。。
     *
     * @memberOf string
     * @return {String} 返回轉換後的字符串
     */
    substitute = function(string, object, regexp){
        return string.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
            if (match.charAt(0) == '\\') return match.slice(1);
            return (object[name] != undefined) ? object[name] : '';
        });
    };

    /**
     * 全局替換指定的字符串
     *
     * @memberOf string
     * @return {String} 返回替換後的字符串
     */
    replaceAll = function(string, reallyDo, replaceWith, ignoreCase) {
        if (!RegExp.prototype.isPrototypeOf(reallyDo)) {
            return string.replace(new RegExp(reallyDo, (ignoreCase ? "gi": "g")), replaceWith);
        } else {
            return string.replace(reallyDo, replaceWith);
        }
    };

    /**
     * 計算字符串的字節長度
     *
     * @memberOf string
     * @param {String} string
     * @param {Number} n 指定一箇中文的字節數, 默認爲2
     * @return {Number} 返回本身長度
     */
    byteLength = function(string,n){
        n= n||2;
        return string.replace(/[^\x00-\xff]/g,({2:"aa",3:"aaa"})[n]).length;
    };
    /**
     * 按字符按給定長度裁剪給定字符串
     * @memberOf string
     * @param {String} string
     * @param {Number} n
     * @return {String}
     */
    cutRight = function(string, n){
        return string.substring(0, (string.length - n));
    };
    /**
     * 按字節按給定長度裁剪給定字符串
     * @memberOf string
     * @param {String} string
     * @param {Number} n
     * @return {String}
     */
    cutByBytes = function(string,n) {
        var s= string;
        while(byteLength(s)>n) {
            s= cutRight(s,1);
        }
        return s;
    };
    /**
     * 判斷給定字符串是不是數字
     * @memberOf string
     * @name isNumber
     * @function
     *
     * @param {String} string
     * @param {Number} n
     * @return {String}
     */
    isNumber = function(string){
        if (string.search(/^\d+$/) !== -1){
            return true;
        }
        else{
            return false;
        }
    };
    /**
     * 判斷一個字符串是不是郵箱格式
     * @memberOf string
     * @param {String} emailStr
     * @return {Boolean}
     */
    isEmail = function(emailStr){
        if (emailStr.search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/) !== -1){
            return true;
        }
        else{
            return false;
        }
    };

    /*
     JS安全API v1.1
     Created By Web Application Security Group of TSC
     UpDate: 2007-12-08
     */

    /**
     * html正文編碼, 對須要出如今HTML正文裏(除了HTML屬性外)的不信任輸入進行編碼
     * @memberOf string
     * @param {String} sStr
     * @return {String}
     */
     encodeHtmlSimple = function(sStr){
        sStr = sStr.replace(/&/g,"&");
        sStr = sStr.replace(/>/g,">");
        sStr = sStr.replace(/</g,"<");
        sStr = sStr.replace(/"/g,""");
        sStr = sStr.replace(/'/g,"'");
        return sStr;
    };

    /**
     * html正文解碼, 對HtmlEncode函數的結果進行解碼
     * @memberOf string
     * @param {String} sStr
     * @return {String}
     */
     decodeHtmlSimple = function(sStr){
        sStr = sStr.replace(/&/g,"&");
        sStr = sStr.replace(/>/g,">");
        sStr = sStr.replace(/</g,"<");
        sStr = sStr.replace(/"/g,'"');
        sStr = sStr.replace(/'/g,"'");
        return sStr;
    };

     decodeHtmlSimple2 = function(sStr){
        sStr = sStr.replace(/&/g,"&");
        sStr = sStr.replace(/>/g,">");
        sStr = sStr.replace(/</g,"<");
        sStr = sStr.replace(/\\\\"/g,'"');
        sStr = sStr.replace(/\\\\'/g,"'");
        return sStr;
    };

    /**
     * html屬性編碼:對須要出如今HTML屬性裏的不信任輸入進行編碼
     注意:
     (1)該函數不適用於屬性爲一個URL地址的編碼.這些標記包括:a/img/frame/iframe/script/xml/embed/object...
     屬性包括:href/src/lowsrc/dynsrc/background/...
     (2)該函數不適用於屬性名爲 style="[Un-trusted input]" 的編碼
     * @memberOf string
     * @param {String} sStr
     * @return {String}
     */
     encodeHtmlAttributeSimple = function(sStr){
        sStr = sStr.replace(/&/g,"&");
        sStr = sStr.replace(/>/g,">");
        sStr = sStr.replace(/</g,"<");
        sStr = sStr.replace(/"/g,""");
        sStr = sStr.replace(/'/g,"'");
        sStr = sStr.replace(/=/g,"=");
        sStr = sStr.replace(/`/g,"`");
        return sStr;
    };

    /**
     * 用作過濾直接放到HTML裏的
     * @memberOf string
     * @param {String} sStr
     * @return {String}
     */
     encodeHtml = function(sStr) {
        return sStr.replace(/[&'"<>\/\\\-\x00-\x09\x0b-\x0c\x1f\x80-\xff]/g, function(r){
            return "&#"+r.charCodeAt(0)+";";
        }).replace(/ /g, " ").replace(/\r\n/g, "<br />").replace(/\n/g, "<br />").replace(/\r/g, "<br />");
    };

    /**
     * 用作過濾HTML標籤裏面的東東 好比這個例子裏的<input value="XXXX">  XXXX就是要過濾的
     * @memberOf string
     * @param {String} sStr
     * @return {String}
     */
     encodeHtmlAttribute = function(sStr) {
        return sStr.replace(/[&'"<>\/\\\-\x00-\x1f\x80-\xff]/g, function(r){
            return "&#"+r.charCodeAt(0)+";";
        });
    };

    /**
     * 用作過濾直接放到HTML裏js中的
     * @memberOf string
     * @param {String} sStr
     * @return {String}
     */
     encodeScript = function(sStr) {
        sStr+="";//確保爲String
        return sStr.replace(/[\\"']/g, function(r){
            return "\\"+r;
        }).replace(/%/g, "\\x25").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\x01/g, "\\x01");
    };

    /**
     * 用作過濾直接放到<a href="javascript:XXXX">中的
     * @memberOf string
     * @param {String} sStr
     * @return {String}
     */
     encodeHrefScript = function(sStr) {
        return encodeHtml(encodeUrl(escScript(sStr)));
    };

    /**
     * 用作過濾直接放到正則表達式中的
     * @memberOf string
     * @param {String} sStr
     * @return {String}
     */
     encodeRegExp = function(sStr) {
        return sStr.replace(/[\\\^\$\*\+\?\{\}\.\(\)\[\]]/g, function(a,b){
            return "\\"+a;
        });
    };

    /**
     * 用作過濾直接URL參數裏的  好比 http://show8.qq.com/abc_cgi?a=XXX  XXX就是要過濾的
     * @memberOf string
     * @param {String} sStr
     * @return {String}
     */
     encodeUrl = function(sStr) {
        return escape(sStr).replace(/\+/g, "%2B");
    };

    /**
     對須要出如今一個URI的一部分的不信任輸入進行編碼
     例如:
     <a href="http://search.msn.com/results.aspx?q1=[Un-trusted-input]& q2=[Un-trusted-input]">Click Here!</a>
     如下字符將會被編碼:
     除[a-zA-Z0-9.-_]之外的字符都會被替換成URL編碼
     *
     * @memberOf string
     * @param {String} sStr
     * @return {String}
     */
     encodeUriComponent = function(sStr){
        sStr = encodeURIComponent(sStr);
        sStr = sStr.replace(/~/g,"%7E");
        sStr = sStr.replace(/!/g,"%21");
        sStr = sStr.replace(/\*/g,"%2A");
        sStr = sStr.replace(/\(/g,"%28");
        sStr = sStr.replace(/\)/g,"%29");
        sStr = sStr.replace(/'/g,"%27");
        sStr = sStr.replace(/\?/g,"%3F");
        sStr = sStr.replace(/;/g,"%3B");
        return sStr;
    };


    /**
     * 驗證給定字符串是不是url, 若是是url 則返回正常的url
     *
     * @memberOf string
     * @param {String} url
     * @return {String}
     */
     vaildURL = function(url){
         url=encodeURI(url).replace(/(^\s*)|(\s*$)/g, ''),
            protocolReg=/(^[a-zA-Z0-9]+[^.]):/,
            domainReg=/^[\S.]+\.[\S.]+$/,
            domainendReg=/[\w.]+\/(\S*)/,
            jsReg=/;$/,
            jpReg=/^[\s*]*javascript[\s*]*:/;

        if((!protocolReg.test(url)) && (!domainReg.test(url))){
            url="";
        }else{
            if(!protocolReg.test(url)){
                url="http://"+url;
            }
            if(!domainendReg.test(url)){
                url=url+"/";

            }
            //若是是js爲協議就清空
            if(jpReg.test(url)){
                url="";
            }
        }

        return url;
    };

    /**
     * 獲取字符實際寬度
     * @memberOf string
     * @param {String} str 須要計算的字符串
     * @param {Number} fontSize 字體大小,能夠不填
     * @return {Number}
     */
    getCharWidth = function(str,fontSize) {
        var d= document.createElement("div");
        d.style.visibility= "hidden";
        d.style.width= "auto";
        if(fontSize) {
            d.style.fontSize= fontSize + "px";
        }
        d.style.position= "absolute";
        d.innerHTML= encodeHtmlSimple(str);
        document.body.appendChild(d);
        var width= d.offsetWidth;
        document.body.removeChild(d);
        return width;
    };

    /**
     * 按給定寬度裁剪字符串
     * @memberOf string
     * @param {String} str
     * @param {Number} fontsize 字體大小
     * @param {Number} width 限定的寬度
     * @return {Number}
     */
    cutByWidth = function(str,fontsize,width) {
        for(var i=str.length;i>=0;--i)
        {
            str=str.substring(0, i);
            if(getCharWidth(str, fontsize)<width)
            {
                return str;
            }
        }
        return '';
    };

    $string.cutByWidth = cutByWidth;
    $string.toString = toString;
    $string.template = template;
    $string.parseURL = parseURL;
    $string.buildURL = buildURL;
    $string.mapQuery = mapQuery;
    $string.test = test;
    $string.contains = contains;
    $string.trim = trim;
    $string.clean = clean;
    $string.camelCase = camelCase;
    $string.hyphenate = hyphenate;
    $string.capitalize = capitalize;
    $string.escapeRegExp = escapeRegExp;
    $string.toInt = toInt;
    $string.toFloat = toFloat;
    $string.toSingleLine = toSingleLine;

    $string.toHtml = toHtml;
    $string.toTitle = toTitle;
    $string.toQueryPair = toQueryPair;
    $string.toQueryString = toQueryString;

    $string.hexToRgb = hexToRgb;
    $string.rgbToHex = rgbToHex;
    $string.stripScripts = stripScripts;
    $string.substitute = substitute;
    $string.replaceAll = replaceAll;

    $string.byteLength = byteLength;
    $string.cutRight = cutRight;

    $string.isNumber = isNumber;
    $string.isEmail = isEmail;

    $string.cutByBytes = cutByBytes;

    //html正文編碼:對須要出如今HTML正文裏(除了HTML屬性外)的不信任輸入進行編碼
    $string.encodeHtmlSimple = encodeHtmlSimple;

    //html正文解碼:對HtmlEncode函數的結果進行解碼
    $string.decodeHtmlSimple = decodeHtmlSimple;
    $string.decodeHtmlSimple2 = decodeHtmlSimple2;

    /*
     html屬性編碼:對須要出如今HTML屬性裏的不信任輸入進行編碼
     注意:
     (1)該函數不適用於屬性爲一個URL地址的編碼.這些標記包括:a/img/frame/iframe/script/xml/embed/object...
     屬性包括:href/src/lowsrc/dynsrc/background/...
     (2)該函數不適用於屬性名爲 style="[Un-trusted input]" 的編碼
     */
    $string.encodeHtmlAttributeSimple = encodeHtmlAttributeSimple;

    //用作過濾HTML標籤裏面的東東 好比這個例子裏的<input value="XXXX">  XXXX就是要過濾的
    $string.encodeHtmlAttribute = encodeHtmlAttribute;

    //用作過濾直接放到HTML裏的
    $string.encodeHtml = encodeHtml;

    //用作過濾直接放到HTML裏js中的
    $string.encodeScript = encodeScript;

    //用作過濾直接放到<a href="javascript:XXXX">中的
    $string.encodeHrefScript = encodeHrefScript;

    //用作過濾直接放到正則表達式中的
    $string.encodeRegExp = encodeRegExp;

    //用作過濾直接URL參數裏的  好比 http://show8.qq.com/abc_cgi?a=XXX  XXX就是要過濾的
    $string.encodeUrl = encodeUrl;

    /*
     對須要出如今一個URI的一部分的不信任輸入進行編碼
     例如:
     <a href="http://search.msn.com/results.aspx?q1=[Un-trusted-input]& q2=[Un-trusted-input]">Click Here!</a>
     如下字符將會被編碼:
     除[a-zA-Z0-9.-_]之外的字符都會被替換成URL編碼
     */
    $string.encodeUriComponent = encodeUriComponent;

    $string.vaildURL = vaildURL;

    $string.getCharWidth = getCharWidth;



    /**
     * underscore.string.js
     */
    var underscore_string=(function(){



        // Defining helper functions.

        var nativeTrim = String.prototype.trim;
        var nativeTrimRight = String.prototype.trimRight;
        var nativeTrimLeft = String.prototype.trimLeft;

        var parseNumber = function (source) {
            return source * 1 || 0;
        };

        var strRepeat = function (str, qty) {
            if (qty < 1) return '';
            var result = '';
            while (qty > 0) {
                if (qty & 1) result += str;
                qty >>= 1, str += str;
            }
            return result;
        };

        var slice = [].slice;

        var defaultToWhiteSpace = function (characters) {
            if (characters == null)
                return '\\s';
            else if (characters.source)
                return characters.source;
            else
                return '[' + _s.escapeRegExp(characters) + ']';
        };

        var escapeChars = {
            lt: '<',
            gt: '>',
            quot: '"',
            apos: "'",
            amp: '&'
        };

        var reversedEscapeChars = {};
        for (var key in escapeChars) {
            reversedEscapeChars[escapeChars[key]] = key;
        }

        // sprintf() for JavaScript 0.7-beta1
        // http://www.diveintojavascript.com/projects/javascript-sprintf
        //
        // Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
        // All rights reserved.

        var sprintf = (function () {
            function get_type(variable) {
                return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
            }

            var str_repeat = strRepeat;

            var str_format = function () {
                if (!str_format.cache.hasOwnProperty(arguments[0])) {
                    str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
                }
                return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
            };

            str_format.format = function (parse_tree, argv) {
                var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
                for (i = 0; i < tree_length; i++) {
                    node_type = get_type(parse_tree[i]);
                    if (node_type === 'string') {
                        output.push(parse_tree[i]);
                    }
                    else if (node_type === 'array') {
                        match = parse_tree[i]; // convenience purposes only
                        if (match[2]) { // keyword argument
                            arg = argv[cursor];
                            for (k = 0; k < match[2].length; k++) {
                                if (!arg.hasOwnProperty(match[2][k])) {
                                    throw new Error(sprintf('[_.sprintf] property "%s" does not exist', match[2][k]));
                                }
                                arg = arg[match[2][k]];
                            }
                        } else if (match[1]) { // positional argument (explicit)
                            arg = argv[match[1]];
                        }
                        else { // positional argument (implicit)
                            arg = argv[cursor++];
                        }

                        if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
                            throw new Error(sprintf('[_.sprintf] expecting number but found %s', get_type(arg)));
                        }
                        switch (match[8]) {
                            case 'b':
                                arg = arg.toString(2);
                                break;
                            case 'c':
                                arg = String.fromCharCode(arg);
                                break;
                            case 'd':
                                arg = parseInt(arg, 10);
                                break;
                            case 'e':
                                arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential();
                                break;
                            case 'f':
                                arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg);
                                break;
                            case 'o':
                                arg = arg.toString(8);
                                break;
                            case 's':
                                arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg);
                                break;
                            case 'u':
                                arg = Math.abs(arg);
                                break;
                            case 'x':
                                arg = arg.toString(16);
                                break;
                            case 'X':
                                arg = arg.toString(16).toUpperCase();
                                break;
                        }
                        arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+' + arg : arg);
                        pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
                        pad_length = match[6] - String(arg).length;
                        pad = match[6] ? str_repeat(pad_character, pad_length) : '';
                        output.push(match[5] ? arg + pad : pad + arg);
                    }
                }
                return output.join('');
            };

            str_format.cache = {};

            str_format.parse = function (fmt) {
                var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
                while (_fmt) {
                    if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
                        parse_tree.push(match[0]);
                    }
                    else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
                        parse_tree.push('%');
                    }
                    else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
                        if (match[2]) {
                            arg_names |= 1;
                            var field_list = [], replacement_field = match[2], field_match = [];
                            if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
                                field_list.push(field_match[1]);
                                while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
                                    if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
                                        field_list.push(field_match[1]);
                                    }
                                    else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
                                        field_list.push(field_match[1]);
                                    }
                                    else {
                                        throw new Error('[_.sprintf] huh?');
                                    }
                                }
                            }
                            else {
                                throw new Error('[_.sprintf] huh?');
                            }
                            match[2] = field_list;
                        }
                        else {
                            arg_names |= 2;
                        }
                        if (arg_names === 3) {
                            throw new Error('[_.sprintf] mixing positional and named placeholders is not (yet) supported');
                        }
                        parse_tree.push(match);
                    }
                    else {
                        throw new Error('[_.sprintf] huh?');
                    }
                    _fmt = _fmt.substring(match[0].length);
                }
                return parse_tree;
            };

            return str_format;
        })();

        // Defining underscore.string

        var _s = {

            isBlank: function (str) {
                if (str == null) str = '';
                return (/^\s*$/).test(str);
            },

            stripTags: function (str) {
                if (str == null) return '';
                return String(str).replace(/<\/?[^>]+>/g, '');
            },

            capitalize: function (str) {
                str = str == null ? '' : String(str);
                return str.charAt(0).toUpperCase() + str.slice(1);
            },

            chop: function (str, step) {
                if (str == null) return [];
                str = String(str);
                step = ~~step;
                return step > 0 ? str.match(new RegExp('.{1,' + step + '}', 'g')) : [str];
            },

            clean: function (str) {
                return _s.strip(str).replace(/\s+/g, ' ');
            },

            count: function (str, substr) {
                if (str == null || substr == null) return 0;
                return String(str).split(substr).length - 1;
            },

            chars: function (str) {
                if (str == null) return [];
                return String(str).split('');
            },

            swapCase: function (str) {
                if (str == null) return '';
                return String(str).replace(/\S/g, function (c) {
                    return c === c.toUpperCase() ? c.toLowerCase() : c.toUpperCase();
                });
            },

            escapeHTML: function (str) {
                if (str == null) return '';
                return String(str).replace(/[&<>"']/g, function (m) {
                    return '&' + reversedEscapeChars[m] + ';';
                });
            },

            unescapeHTML: function (str) {
                if (str == null) return '';
                return String(str).replace(/\&([^;]+);/g, function (entity, entityCode) {
                    var match;

                    if (entityCode in escapeChars) {
                        return escapeChars[entityCode];
                    } else if (match = entityCode.match(/^#x([\da-fA-F]+)$/)) {
                        return String.fromCharCode(parseInt(match[1], 16));
                    } else if (match = entityCode.match(/^#(\d+)$/)) {
                        return String.fromCharCode(~~match[1]);
                    } else {
                        return entity;
                    }
                });
            },

            escapeRegExp: function (str) {
                if (str == null) return '';
                return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
            },

            splice: function (str, i, howmany, substr) {
                var arr = _s.chars(str);
                arr.splice(~~i, ~~howmany, substr);
                return arr.join('');
            },

            insert: function (str, i, substr) {
                return _s.splice(str, i, 0, substr);
            },

            include: function (str, needle) {
                if (needle === '') return true;
                if (str == null) return false;
                return String(str).indexOf(needle) !== -1;
            },

            join: function () {
                var args = slice.call(arguments),
                    separator = args.shift();

                if (separator == null) separator = '';

                return args.join(separator);
            },

            lines: function (str) {
                if (str == null) return [];
                return String(str).split("\n");
            },

            reverse: function (str) {
                return _s.chars(str).reverse().join('');
            },

            startsWith: function (str, starts) {
                if (starts === '') return true;
                if (str == null || starts == null) return false;
                str = String(str);
                starts = String(starts);
                return str.length >= starts.length && str.slice(0, starts.length) === starts;
            },

            endsWith: function (str, ends) {
                if (ends === '') return true;
                if (str == null || ends == null) return false;
                str = String(str);
                ends = String(ends);
                return str.length >= ends.length && str.slice(str.length - ends.length) === ends;
            },

            succ: function (str) {
                if (str == null) return '';
                str = String(str);
                return str.slice(0, -1) + String.fromCharCode(str.charCodeAt(str.length - 1) + 1);
            },

            titleize: function (str) {
                if (str == null) return '';
                return String(str).replace(/(?:^|\s)\S/g, function (c) {
                    return c.toUpperCase();
                });
            },

            camelize: function (str) {
                return _s.trim(str).replace(/[-_\s]+(.)?/g, function (match, c) {
                    return c.toUpperCase();
                });
            },

            underscored: function (str) {
                return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/[-\s]+/g, '_').toLowerCase();
            },

            dasherize: function (str) {
                return _s.trim(str).replace(/([A-Z])/g, '-$1').replace(/[-_\s]+/g, '-').toLowerCase();
            },

            classify: function (str) {
                return _s.titleize(String(str).replace(/_/g, ' ')).replace(/\s/g, '');
            },

            humanize: function (str) {
                return _s.capitalize(_s.underscored(str).replace(/_id$/, '').replace(/_/g, ' '));
            },

            trim: function (str, characters) {
                if (str == null) return '';
                if (!characters && nativeTrim) return nativeTrim.call(str);
                characters = defaultToWhiteSpace(characters);
                return String(str).replace(new RegExp('\^' + characters + '+|' + characters + '+$', 'g'), '');
            },

            ltrim: function (str, characters) {
                if (str == null) return '';
                if (!characters && nativeTrimLeft) return nativeTrimLeft.call(str);
                characters = defaultToWhiteSpace(characters);
                return String(str).replace(new RegExp('^' + characters + '+'), '');
            },

            rtrim: function (str, characters) {
                if (str == null) return '';
                if (!characters && nativeTrimRight) return nativeTrimRight.call(str);
                characters = defaultToWhiteSpace(characters);
                return String(str).replace(new RegExp(characters + '+$'), '');
            },

            truncate: function (str, length, truncateStr) {
                if (str == null) return '';
                str = String(str);
                truncateStr = truncateStr || '...';
                length = ~~length;
                return str.length > length ? str.slice(0, length) + truncateStr : str;
            },

            /**
             * _s.prune: a more elegant version of truncate
             * prune extra chars, never leaving a half-chopped word.
             * @author github.com/rwz
             */
            prune: function (str, length, pruneStr) {
                if (str == null) return '';

                str = String(str);
                length = ~~length;
                pruneStr = pruneStr != null ? String(pruneStr) : '...';

                if (str.length <= length) return str;

                var tmpl = function (c) {
                        return c.toUpperCase() !== c.toLowerCase() ? 'A' : ' ';
                    },
                    template = str.slice(0, length + 1).replace(/.(?=\W*\w*$)/g, tmpl); // 'Hello, world' -> 'HellAA AAAAA'

                if (template.slice(template.length - 2).match(/\w\w/))
                    template = template.replace(/\s*\S+$/, '');
                else
                    template = _s.rtrim(template.slice(0, template.length - 1));

                return (template + pruneStr).length > str.length ? str : str.slice(0, template.length) + pruneStr;
            },

            words: function (str, delimiter) {
                if (_s.isBlank(str)) return [];
                return _s.trim(str, delimiter).split(delimiter || /\s+/);
            },

            pad: function (str, length, padStr, type) {
                str = str == null ? '' : String(str);
                length = ~~length;

                var padlen = 0;

                if (!padStr)
                    padStr = ' ';
                else if (padStr.length > 1)
                    padStr = padStr.charAt(0);

                switch (type) {
                    case 'right':
                        padlen = length - str.length;
                        return str + strRepeat(padStr, padlen);
                    case 'both':
                        padlen = length - str.length;
                        return strRepeat(padStr, Math.ceil(padlen / 2)) + str
                            + strRepeat(padStr, Math.floor(padlen / 2));
                    default: // 'left'
                        padlen = length - str.length;
                        return strRepeat(padStr, padlen) + str;
                }
            },

            lpad: function (str, length, padStr) {
                return _s.pad(str, length, padStr);
            },

            rpad: function (str, length, padStr) {
                return _s.pad(str, length, padStr, 'right');
            },

            lrpad: function (str, length, padStr) {
                return _s.pad(str, length, padStr, 'both');
            },

            sprintf: sprintf,

            vsprintf: function (fmt, argv) {
                argv.unshift(fmt);
                return sprintf.apply(null, argv);
            },

            toNumber: function (str, decimals) {
                if (str == null || str == '') return 0;
                str = String(str);
                var num = parseNumber(parseNumber(str).toFixed(~~decimals));
                return num === 0 && !str.match(/^0+$/) ? Number.NaN : num;
            },

            numberFormat: function (number, dec, dsep, tsep) {
                if (isNaN(number) || number == null) return '';

                number = number.toFixed(~~dec);
                tsep = tsep || ',';

                var parts = number.split('.'), fnums = parts[0],
                    decimals = parts[1] ? (dsep || '.') + parts[1] : '';

                return fnums.replace(/(\d)(?=(?:\d{3})+$)/g, '$1' + tsep) + decimals;
            },

            strRight: function (str, sep) {
                if (str == null) return '';
                str = String(str);
                sep = sep != null ? String(sep) : sep;
                var pos = !sep ? -1 : str.indexOf(sep);
                return ~pos ? str.slice(pos + sep.length, str.length) : str;
            },

            strRightBack: function (str, sep) {
                if (str == null) return '';
                str = String(str);
                sep = sep != null ? String(sep) : sep;
                var pos = !sep ? -1 : str.lastIndexOf(sep);
                return ~pos ? str.slice(pos + sep.length, str.length) : str;
            },

            strLeft: function (str, sep) {
                if (str == null) return '';
                str = String(str);
                sep = sep != null ? String(sep) : sep;
                var pos = !sep ? -1 : str.indexOf(sep);
                return ~pos ? str.slice(0, pos) : str;
            },

            strLeftBack: function (str, sep) {
                if (str == null) return '';
                str += '';
                sep = sep != null ? '' + sep : sep;
                var pos = str.lastIndexOf(sep);
                return ~pos ? str.slice(0, pos) : str;
            },

            toSentence: function (array, separator, lastSeparator, serial) {
                separator = separator || ', '
                lastSeparator = lastSeparator || ' and '
                var a = array.slice(), lastMember = a.pop();

                if (array.length > 2 && serial) lastSeparator = _s.rtrim(separator) + lastSeparator;

                return a.length ? a.join(separator) + lastSeparator + lastMember : lastMember;
            },

            toSentenceSerial: function () {
                var args = slice.call(arguments);
                args[3] = true;
                return _s.toSentence.apply(_s, args);
            },

            slugify: function (str) {
                if (str == null) return '';

                var from = "ąàáäâãåæćęèéëêìíïîłńòóöôõøùúüûñçżź",
                    to = "aaaaaaaaceeeeeiiiilnoooooouuuunczz",
                    regex = new RegExp(defaultToWhiteSpace(from), 'g');

                str = String(str).toLowerCase().replace(regex, function (c) {
                    var index = from.indexOf(c);
                    return to.charAt(index) || '-';
                });

                return _s.dasherize(str.replace(/[^\w\s-]/g, ''));
            },

            surround: function (str, wrapper) {
                return [wrapper, str, wrapper].join('');
            },

            quote: function (str) {
                return _s.surround(str, '"');
            },

            exports: function () {
                var result = {};

                for (var prop in this) {
                    if (!this.hasOwnProperty(prop) || prop.match(/^(?:include|contains|reverse)$/)) continue;
                    result[prop] = this[prop];
                }

                return result;
            },

            repeat: function (str, qty, separator) {
                if (str == null) return '';

                qty = ~~qty;

                // using faster implementation if separator is not needed;
                if (separator == null) return strRepeat(String(str), qty);

                // this one is about 300x slower in Google Chrome
                for (var repeat = []; qty > 0; repeat[--qty] = str) {
                }
                return repeat.join(separator);
            },

            levenshtein: function (str1, str2) {
                if (str1 == null && str2 == null) return 0;
                if (str1 == null) return String(str2).length;
                if (str2 == null) return String(str1).length;

                str1 = String(str1);
                str2 = String(str2);

                var current = [], prev, value;

                for (var i = 0; i <= str2.length; i++)
                    for (var j = 0; j <= str1.length; j++) {
                        if (i && j)
                            if (str1.charAt(j - 1) === str2.charAt(i - 1))
                                value = prev;
                            else
                                value = Math.min(current[j], current[j - 1], prev) + 1;
                        else
                            value = i + j;

                        prev = current[j];
                        current[j] = value;
                    }

                return current.pop();
            }
        };

        // Aliases
        _s.strip = _s.trim;
        _s.lstrip = _s.ltrim;
        _s.rstrip = _s.rtrim;
        _s.center = _s.lrpad;
        _s.rjust = _s.lpad;
        _s.ljust = _s.rpad;
        _s.contains = _s.include;
        return _s;
    })();

    _.extend($string,underscore_string);


相關文章
相關標籤/搜索