1 /** 
  2  * JET (Javascript Extension Tools) 
  3  * Copyright (c) 2009, KDV.cn, All rights reserved.
  4  * Code licensed under the BSD License:
  5  * http://developer.kdv.cn/jet/license.txt
  6  *
  7  * @fileOverview Jx!
  8  * @version 1.0
  9  * @author  Kinvix(<a href="mailto:Kinvix@gmail.com">Kinvix@gmail.com</a>)
 10  * @description 
 11  * 
 12  */
 13 
 14 /** 
 15  * @description
 16  * Package: Jx.string
 17  * 
 18  * Need package:
 19  * Jx.core.js
 20  * 
 21  */
 22 
 23 
 24 /**
 25  * 3.[Javascript core]: String 字符串处理
 26  */
 27 Jx().$package(function(J){
 28     
 29     /**
 30      * string 名字空间
 31      * 
 32      * @namespace
 33      * @name string
 34      */
 35     J.string = J.string || {};
 36     var $S = J.string,
 37         toString,
 38         template,
 39         isURL,
 40         parseURL,
 41         buildURL,
 42         mapQuery,
 43         test,
 44         contains,
 45         trim,
 46         clean,
 47         camelCase,
 48         hyphenate,
 49         capitalize,
 50         escapeRegExp,
 51         toInt,
 52         toFloat,
 53         toSingleLine,
 54         toHtml,
 55         toTitle,
 56         toQueryPair,
 57         toQueryString,
 58         
 59         hexToRgb,
 60         rgbToHex,
 61         stripScripts,
 62         substitute,
 63         replaceAll,
 64         
 65         byteLength,
 66         cutRight,
 67         cutByBytes,
 68         isNumber,
 69         isEmail,
 70         
 71         encodeHtmlSimple,
 72         decodeHtmlSimple,
 73         decodeHtmlSimple2,
 74         encodeHtmlAttributeSimple,
 75         encodeHtmlAttribute,
 76         encodeHtml,
 77         encodeScript,
 78         encodeHrefScript,
 79         encodeRegExp,
 80         encodeUrl,
 81         encodeUriComponent,
 82         vaildTencentUrl,
 83         vaildUrl,
 84         getCharWidth;
 85         
 86     
 87     /**
 88      * 将任意变量转换为字符串的方法
 89      * 
 90      * @method toString
 91      * @memberOf string
 92      * 
 93      * @param {Mixed} o 任意变量
 94      * @return {String} 返回转换后的字符串
 95      */
 96     toString = function(o){
 97         return (o + "");
 98     };
 99     
100     /**
101      * 多行或单行字符串模板处理
102      * 
103      * @method template
104      * @memberOf string
105      * 
106      * @param {String} str 模板字符串
107      * @param {Object} obj 要套入的数据对象
108      * @return {String} 返回与数据对象合成后的字符串
109      * 
110      * @example
111      * <script type="text/html" id="user_tmpl">
112      *   <% for ( var i = 0; i < users.length; i++ ) { %>
113      *     <li><a href="<%=users[i].url%>"><%=users[i].name%></a></li>
114      *   <% } %>
115      * </script>
116      * 
117      * Jx().$package(function(J){
118      *  // 用 obj 对象的数据合并到字符串模板中
119      *  J.template("Hello, {name}!", {
120      *      name:"Kinvix"
121      *  });
122      * };
123      */
124     template = function(str, data){
125         /*!
126           * jstemplate: a light & fast js tamplate engine
127           * License MIT (c) 岑安
128           * 
129           * Modify by azrael @ 2012/9/28
130           */
131         var //global = typeof window != 'undefined' ? window : {},
132             openTag = '<%',
133             closeTag = '%>',
134             retTag = '$return',
135             vars = 'var ',
136             varsInTpl,
137             codeArr = ''.trim ?
138                 [retTag + ' = "";', retTag + ' +=', ';', retTag + ';', 'print=function(){' + retTag + '+=[].join.call(arguments,"")},'] :
139                 [retTag + ' = [];', retTag + '.push(', ')', retTag + '.join("");', 'print=function(){' + retTag + '.push.apply(arguments)},'],
140             keys = ('break,case,catch,continue,debugger,default,delete,do,else,false,finally,for,function,if'
141                 + ',in,instanceof,new,null,return,switch,this,throw,true,try,typeof,var,void,while,with'
142                 // Reserved words
143                 + ',abstract,boolean,byte,char,class,const,double,enum,export,extends,final,float,goto'
144                 + ',implements,import,int,interface,long,native,package,private,protected,public,short'
145                 + ',static,super,synchronized,throws,transient,volatile'
146                 
147                 // ECMA 5 - use strict
148                 + ',arguments,let,yield').split(','),
149             keyMap = {};
150             
151         for (var i = 0, len = keys.length; i < len; i ++) {
152             keyMap[keys[i]] = 1;
153         }
154             
155         function _getCompileFn (source) {
156             vars = 'var ';
157             varsInTpl = {};
158             varsInTpl[retTag] = 1; 
159             var openArr = source.split(openTag),
160                 tmpCode = '';
161                 
162             for (var i = 0, len = openArr.length; i < len; i ++) {
163                 var c = openArr[i],
164                     cArr = c.split(closeTag);
165                 if (cArr.length == 1) {
166                     tmpCode += _html(cArr[0]);
167                 } else {
168                     tmpCode += _js(cArr[0]);
169                     tmpCode += cArr[1] ? _html(cArr[1]) : '';
170                 }
171             }
172         
173             var code = vars + codeArr[0] + tmpCode + 'return ' + codeArr[3];
174             var fn = new Function('$data', code);
175             
176             return fn;
177         }
178         
179         function _html (s) {
180             s = s
181             .replace(/('|"|\\)/g, '\\$1')
182             .replace(/\r/g, '\\r')
183             .replace(/\n/g, '\\n');
184             
185             s = codeArr[1] + '"' + s + '"' + codeArr[2];
186             
187             return s + '\n';
188         }
189         
190         function _js (s) {
191             if (/^=/.test(s)) {
192                 s = codeArr[1] + s.substring(1).replace(/[\s;]*$/, '') + codeArr[2];
193             }
194             dealWithVars(s);
195             
196             return s + '\n';
197         }
198         
199         function dealWithVars (s) {
200             s = s.replace(/\/\*.*?\*\/|'[^']*'|"[^"]*"|\.[\$\w]+/g, '');
201             var sarr = s.split(/[^\$\w\d]+/);
202             for (var i = 0, len = sarr.length; i < len; i ++) {
203                 var c = sarr[i];
204                 if (!c || keyMap[c] || /^\d/.test(c)) {
205                     continue;
206                 }
207                 if (!varsInTpl[c]) {
208                     if (c === 'print') {
209                         vars += codeArr[4];
210                     } else {
211                         vars += (c + '=$data.hasOwnProperty("'+c+'")?$data.' + c + ':window.' + c + ',');
212                     }
213                     varsInTpl[c] = 1;
214                 }
215             }
216         }
217         
218         // function getValue (v, $data){
219         //     return $data.hasOwnProperty(v) ? $data[v] : global[v];
220         // }
221 
222         // function jstemplate (id, source, data) {
223         //     if (typeof arguments[1] == 'object' && arguments[2] == undefined) {
224         //         data = source;
225         //         source = id;
226         //         id = null;
227         //     }
228         //     return (id && _cache[id]) ? _cache[id](data, getValue) : jstemplate.compile(id, source, data);
229         // }
230         
231         // jstemplate.compile = function (id, source, data) {
232         //     vars = 'var ';
233         //     varsInTpl = {};
234             
235         //     var compileFn = _getCompileFn(source);
236         //     if (id) { 
237         //         _cache[id] = compileFn;
238         //     }
239         //     //console.log(compileFn)
240         //     return compileFn(data, getValue);
241         // }
242         
243         // jstemplate.openTag = '<%';
244         // jstemplate.closeTag = '%>';
245         
246         var cache = {};
247         return function(str, data){
248             // Figure out if we're getting a template, or if we need to
249             // load the template - and be sure to cache the result.
250             var fn = !/\W/.test(str) ?
251                 cache[str] || (cache[str] = _getCompileFn(document.getElementById(str).innerHTML)) :
252                 _getCompileFn(str);
253             
254             // Provide some basic currying to the user
255             return data ? fn(data) : fn;
256         };
257     }();
258 
259     /**
260      * 判断是否是一个可接受的 url 串
261      * 
262      * @method isURL
263      * @memberOf string
264      * 
265      * @param {String} str 要检测的字符串
266      * @return {Boolean} 如果是可接受的 url 则返回 true
267      */
268     isURL = function(str) {
269         return isURL.RE.test(str);
270     };
271         
272     /**
273      * @ignore
274      */
275     isURL.RE = /^(?:ht|f)tp(?:s)?\:\/\/(?:[\w\-\.]+)\.\w+/i;
276 
277 
278     /**
279      * 分解 URL 为一个对象,成员为:scheme, user, pass, host, port, path, query, fragment
280      * 
281      * @method parseURL
282      * @memberOf string
283      * 
284      * @param {String} str URL 地址
285      * @return {Object} 如果解析失败则返回 null
286      */
287     parseURL = function(str) {
288         var ret = null;
289 
290         if (null !== (ret = parseURL.RE.exec(str))) {
291             var specObj = {};
292             for (var i = 0, j = parseURL.SPEC.length; i < j ; i ++) {
293                 var curSpec = parseURL.SPEC[i];
294                 specObj[curSpec] = ret[i + 1];
295             }
296             ret = specObj;
297             specObj = null;
298         }
299 
300         return ret;
301     };
302 
303 
304     /**
305      * 将一个对象(成员为:scheme, user, pass, host, port, path, query, fragment)重新组成为一个字符串
306      * 
307      * @method buildURL
308      * @memberOf string
309      * 
310      * @param {Object} obj URl 对象
311      * @return {String} 如果是可接受的 url 则返回 true
312      */
313     buildURL = function(obj) {
314         var ret = '';
315 
316         // prefix & surffix
317         var prefix = {},
318             surffix = {};
319 
320         for (var i = 0, j = parseURL.SPEC.length; i < j ; i ++) {
321             var curSpec = parseURL.SPEC[i];
322             if (!obj[curSpec]) {
323                 continue;
324             }
325             switch (curSpec) {
326             case 'scheme':
327                 surffix[curSpec] = '://';
328                 break;
329             case 'pass':
330                 prefix[curSpec] = ':';
331             case 'user':
332                 prefix['host'] = '@';
333                 break;
334             //case 'host':
335             case 'port':
336                 prefix[curSpec] = ':';
337                 break;
338             //case 'path':
339             case 'query':
340                 prefix[curSpec] = '?';
341                 break;
342             case 'fragment':
343                 prefix[curSpec] = '#';
344                 break;
345             }
346 
347             // rebuild
348             if (curSpec in prefix) {
349                 ret += prefix[curSpec];
350             }
351             if (curSpec in obj) {
352                 ret += obj[curSpec];
353             }
354             if (curSpec in surffix) {
355                 ret += surffix[curSpec];
356             }
357         }
358 
359         prefix = null;
360         surffix = null;
361         obj = null;
362 
363         return ret;
364     };
365     
366     /**
367      * @ignore
368      */
369     parseURL.SPEC = ['scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'];
370     parseURL.RE = /^([^:]+):\/\/(?:([^:@]+):?([^@]*)@)?(?:([^/?#:]+):?(\d*))([^?#]*)(?:\?([^#]+))?(?:#(.+))?$/;
371     
372     /**
373      * 将 uri 的查询字符串参数映射成对象
374      * 
375      * @method mapQuery
376      * @memberOf string
377      * 
378      * @param {String} uri 要映射的 uri
379      * @return {Object} 按照 uri 映射成的对象
380      * 
381      * @example
382      * Jx().$package(function(J){
383      *  var url = "http://web.qq.com/?qq=4765078&style=blue";
384      *  // queryObj 则得到一个{qq:"4765078", style:"blue"}的对象。
385      *  var queryObj = J.mapQuery(url);
386      * };
387      */
388     mapQuery = function(uri){
389         //window.location.search
390         var i,
391             key,
392             value,
393             uri = uri && uri.split('#')[0] || window.location.search, //remove hash
394             index = uri.indexOf("?"),
395             pieces = uri.substring(index + 1).split("&"),
396             params = {};
397         if(index === -1){//如果连?号都没有,直接返回,不再进行处理. az 2011/5/11
398             return params;
399         }
400         for(i=0; i<pieces.length; i++){
401             try{
402                 index = pieces[i].indexOf("=");
403                 key = pieces[i].substring(0,index);
404                 value = pieces[i].substring(index+1);
405                 if(!(params[key] = unescape(value))){
406                     throw new Error("uri has wrong query string when run mapQuery.");
407                 }
408             }
409             catch(e){
410                 //J.out("错误:[" + e.name + "] "+e.message+", " + e.fileName+", 行号:"+e.lineNumber+"; stack:"+typeof e.stack, 2);
411             }
412         }
413         return params;
414     };
415     
416     /**
417      * 
418      * test的方法
419      * 
420      * @memberOf string
421      * 
422      * @param {String|RegExp} regex 正则表达式,或者正则表达式的字符串
423      * @param {String} params 正则的参数
424      * @return {Boolean} 返回结果
425      */
426     test = function(string, regex, params){
427         return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(string);
428     };
429 
430     /**
431      * 判断是否含有指定的字符串
432      * 
433      * @memberOf string
434      * @name contains
435      * @function
436      * @param {String} string 是否含有的字符串
437      * @param {String} separator 分隔符,可选
438      * @return {Boolean} 如果含有,返回 true,否则返回 false
439      */
440     contains = function(string1, string2, separator){
441         return (separator) ? (separator + string1 + separator).indexOf(separator + string2 + separator) > -1 : string1.indexOf(string2) > -1;
442     };
443 
444     /**
445      * 清除字符串开头和结尾的空格
446      * 
447      * @memberOf string
448      * 
449      * @return {String} 返回清除后的字符串
450      */
451     trim = function(string){
452         return String(string).replace(/^\s+|\s+$/g, '');
453     };
454 
455     /**
456      * 清除字符串开头和结尾的空格,并把字符串之间的多个空格转换为一个空格
457      * 
458      * @memberOf string
459      * 
460      * @return {String} 返回清除后的字符串
461      */
462     clean = function(string){
463         return trim(string.replace(/\s+/g, ' '));
464     };
465 
466     /**
467      * 将“-”连接的字符串转换成驼峰式写法
468      * 
469      * @memberOf string
470      * 
471      * @return {String} 返回转换后的字符串
472      */
473     camelCase = function(string){
474         return string.replace(/-\D/g, function(match){
475             return match.charAt(1).toUpperCase();
476         });
477     };
478     
479     /**
480      * 将驼峰式写法字符串转换成“-”连接的
481      * 
482      * @memberOf string
483      * 
484      * @return {String} 返回转换后的字符串
485      */
486     hyphenate = function(string){
487         return string.replace(/[A-Z]/g, function(match){
488             return ('-' + match.charAt(0).toLowerCase());
489         });
490     };
491 
492     /**
493      * 将字符串转换成全大写字母
494      * 
495      * @memberOf string
496      * 
497      * @return {String} 返回转换后的字符串
498      */
499     capitalize = function(string){
500         return string.replace(/\b[a-z]/g, function(match){
501             return match.toUpperCase();
502         });
503     };
504 
505     /**
506      * 转换 RegExp 正则表达式
507      * 
508      * @memberOf string
509      * 
510      * @return {String} 返回转换后的字符串
511      */
512     escapeRegExp = function(string){
513         return string.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
514     };
515 
516     /**
517      * 将字符串转换成整数
518      * 
519      * @memberOf string
520      * 
521      * @return {Number} 返回转换后的整数
522      */
523     toInt = function(string, base){
524         return parseInt(string, base || 10);
525     };
526 
527     /**
528      * 将字符串转换成浮点数
529      * 
530      * @memberOf string
531      * @param {Sring} string 要转换的字符串
532      * @return {Number} 返回转换后的浮点数
533      */
534     toFloat = function(string){
535         return parseFloat(string);
536     };
537     
538     /**
539      * 将带换行符的字符串转换成无换行符的字符串
540      * 
541      * @memberOf string
542      * @param {Sring} str 要转换的字符串
543      * @return {Sring} 返回转换后的字符串
544      */
545     toSingleLine = function(str){
546         return String(str).replace(/\r/gi,"")
547                             .replace(/\n/gi,"");
548     };
549     
550     /**
551      * 将字符串转换成html源码
552      * 
553      * @memberOf string
554      * @param {Sring} str 要转换的字符串
555      * @return {Sring} 返回转换后的html代码字符串
556      */
557     toHtml = function(str){
558         return String(str).replace(/&/gi,"&")
559                             .replace(/\\/gi,"\")
560                             .replace(/\'/gi,"'")
561                             .replace(/\"/gi,""")
562                             .replace (/</gi,"<")
563                             .replace(/>/gi,">")
564                             .replace(/ /gi," ")
565                             .replace(/\r\n/g,"<br />")
566                             .replace(/\n\r/g,"<br />")
567                             .replace(/\n/g,"<br />")
568                             .replace(/\r/g,"<br />");
569     };
570     
571     
572     
573     /**
574      * 将字符串转换成用于title的字符串
575      * 
576      * @memberOf string
577      * @param {Sring} str 要转换的字符串
578      * @return {Number} 返回转换后的in title字符串
579      */
580     toTitle = function(str){
581         return String(str).replace(/\\/gi,"\\")
582                             .replace(/\'/gi,"\'")
583                             .replace(/\"/gi,"\'");
584     };
585 
586     
587     
588     
589     
590 
591     /**
592      * 将颜色 Hex 写法转换成 RGB 写法
593      * 
594      * @memberOf string
595      * @return {String} 返回转换后的字符串
596      */
597     hexToRgb = function(string, array){
598         var hex = string.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
599         return (hex) ? hex.slice(1).hexToRgb(array) : null;
600     };
601 
602     /**
603      * 将颜色 RGB 写法转换成 Hex 写法
604      * 
605      * @memberOf string
606      * @return {String} 返回转换后的字符串
607      */
608     rgbToHex = function(string, array){
609         var rgb = string.match(/\d{1,3}/g);
610         return (rgb) ? rgb.rgbToHex(array) : null;
611     };
612 
613     /**
614      * 脱去script标签
615      * 
616      * @memberOf string
617      * @return {String} 返回转换后的字符串
618      */
619     stripScripts = function(string, option){
620         var scripts = '';
621         var text = string.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
622             scripts += arguments[1] + '\n';
623             return '';
624         });
625         if (option === true){
626             $exec(scripts);
627         }else if($type(option) == 'function'){
628             option(scripts, text);
629         }
630         return text;
631     };
632     
633     /**
634      * 。。。。
635      * 
636      * @memberOf string
637      * @param {Object} obj 要转换成查询字符串的对象
638      * @return {String} 返回转换后的查询字符串
639      */
640     toQueryPair = function(key, value) {
641         return encodeURIComponent(String(key)) + "=" + encodeURIComponent(String(value));
642     };
643     
644     /**
645      * 。。。。
646      * 
647      * @memberOf string
648      * @param {Object} obj 要转换成查询字符串的对象
649      * @return {String} 返回转换后的查询字符串
650      */
651     toQueryString = function(obj){
652         var result=[];
653         for(var key in obj){
654             result.push(toQueryPair(key, obj[key]));
655         }
656         return result.join("&");
657     };
658 
659 
660 
661     /**
662      * 。。。。
663      * 
664      * @memberOf string
665      * @return {String} 返回转换后的字符串
666      */
667     substitute = function(string, object, regexp){
668         return string.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
669             if (match.charAt(0) == '\\') return match.slice(1);
670             return (object[name] != undefined) ? object[name] : '';
671         });
672     };
673     
674     /**
675      * 全局替换指定的字符串
676      * 
677      * @memberOf string
678      * @return {String} 返回替换后的字符串
679      */
680     replaceAll = function(string, reallyDo, replaceWith, ignoreCase) {
681         if (!RegExp.prototype.isPrototypeOf(reallyDo)) {
682             return string.replace(new RegExp(reallyDo, (ignoreCase ? "gi": "g")), replaceWith);
683         } else {
684             return string.replace(reallyDo, replaceWith);
685         }
686     };
687     
688     /**
689      * 计算字符串的字节长度
690      * 
691      * @memberOf string
692      * @param {String} string
693      * @param {Number} n 指定一个中文的字节数, 默认为2
694      * @return {Number} 返回自己长度
695      */
696     byteLength = function(string,n){
697         n= n||2;
698         return string.replace(/[^\x00-\xff]/g,({2:"aa",3:"aaa"})[n]).length;
699     };
700     /**
701      * 按字符按给定长度裁剪给定字符串
702      * @memberOf string
703      * @param {String} string
704      * @param {Number} n 
705      * @return {String} 
706      */
707     cutRight = function(string, n){
708         return string.substring(0, (string.length - n));
709     };
710     /**
711      * 按字节按给定长度裁剪给定字符串
712      * @memberOf string
713      * @param {String} string
714      * @param {Number} n 
715      * @return {String} 
716      */
717     cutByBytes = function(string,n) {
718         var s= string;
719         while(byteLength(s)>n) {
720             s= cutRight(s,1);
721         }
722         return s;
723     };
724     /**
725      * 判断给定字符串是否是数字
726      * @memberOf string
727      * @name isNumber
728      * @function
729      * 
730      * @param {String} string
731      * @param {Number} n 
732      * @return {String} 
733      */
734     isNumber = function(string){
735         if (string.search(/^\d+$/) !== -1){
736             return true;
737         }
738         else{
739             return false;
740         }
741     };
742     /**
743      * 判断一个字符串是否是邮箱格式
744      * @memberOf string
745      * @param {String} emailStr
746      * @return {Boolean}
747      */
748     isEmail = function(emailStr){
749         if (emailStr.search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/) !== -1){
750             return true;
751         }
752         else{
753             return false;
754         }
755     };
756     
757     
758     
759     
760     /*
761     JS安全API v1.1
762     Created By Web Application Security Group of TSC
763     UpDate: 2007-12-08
764     */
765 
766     
767     /**
768      * html正文编码, 对需要出现在HTML正文里(除了HTML属性外)的不信任输入进行编码
769      * @memberOf string
770      * @param {String} sStr
771      * @return {String} 
772      */
773     var encodeHtmlSimple = function(sStr){
774         sStr = sStr.replace(/&/g,"&");
775         sStr = sStr.replace(/>/g,">");
776         sStr = sStr.replace(/</g,"<");
777         sStr = sStr.replace(/"/g,""");
778         sStr = sStr.replace(/'/g,"'");
779         return sStr;
780     };
781     
782     /**
783      * html正文解码, 对HtmlEncode函数的结果进行解码
784      * @memberOf string
785      * @param {String} sStr
786      * @return {String} 
787      */
788     var decodeHtmlSimple = function(sStr){
789         sStr = sStr.replace(/&/g,"&");
790         sStr = sStr.replace(/>/g,">");
791         sStr = sStr.replace(/</g,"<");
792         sStr = sStr.replace(/"/g,'"');
793         sStr = sStr.replace(/'/g,"'");
794         return sStr;
795     };
796     
797     var decodeHtmlSimple2 = function(sStr){
798         sStr = sStr.replace(/&/g,"&");
799         sStr = sStr.replace(/>/g,">");
800         sStr = sStr.replace(/</g,"<");
801         sStr = sStr.replace(/\\\\"/g,'"');
802         sStr = sStr.replace(/\\\\'/g,"'");
803         return sStr;
804     };
805     
806     /**
807      * html属性编码:对需要出现在HTML属性里的不信任输入进行编码
808         注意:
809         (1)该函数不适用于属性为一个URL地址的编码.这些标记包括:a/img/frame/iframe/script/xml/embed/object...
810         属性包括:href/src/lowsrc/dynsrc/background/...
811         (2)该函数不适用于属性名为 style="[Un-trusted input]" 的编码
812      * @memberOf string
813      * @param {String} sStr
814      * @return {String} 
815      */
816     var encodeHtmlAttributeSimple = function(sStr){
817         sStr = sStr.replace(/&/g,"&");
818         sStr = sStr.replace(/>/g,">");
819         sStr = sStr.replace(/</g,"<");
820         sStr = sStr.replace(/"/g,""");
821         sStr = sStr.replace(/'/g,"'");
822         sStr = sStr.replace(/=/g,"=");
823         sStr = sStr.replace(/`/g,"`");
824         return sStr;
825     };
826 
827     
828     
829     
830     /**
831      * 用做过滤直接放到HTML里的
832      * @memberOf string
833      * @param {String} sStr
834      * @return {String} 
835      */
836     var encodeHtml = function(sStr) { 
837         return sStr.replace(/[&'"<>\/\\\-\x00-\x09\x0b-\x0c\x1f\x80-\xff]/g, function(r){ 
838             return "&#"+r.charCodeAt(0)+";";
839         }).replace(/ /g, " ").replace(/\r\n/g, "<br />").replace(/\n/g, "<br />").replace(/\r/g, "<br />"); 
840     };
841     
842     /**
843      * 用做过滤HTML标签里面的东东 比如这个例子里的<input value="XXXX">  XXXX就是要过滤的
844      * @memberOf string
845      * @param {String} sStr
846      * @return {String} 
847      */
848     var encodeHtmlAttribute = function(sStr) { 
849         return sStr.replace(/[&'"<>\/\\\-\x00-\x1f\x80-\xff]/g, function(r){ 
850             return "&#"+r.charCodeAt(0)+";";
851         }); 
852     };
853     
854     /**
855      * 用做过滤直接放到HTML里js中的
856      * @memberOf string
857      * @param {String} sStr
858      * @return {String} 
859      */
860     var encodeScript = function(sStr) {
861         sStr+="";//确保为String
862         return sStr.replace(/[\\"']/g, function(r){ 
863             return "\\"+r; 
864         }).replace(/%/g, "\\x25").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\x01/g, "\\x01");
865     };
866     
867     
868     
869     /**
870      * 用做过滤直接放到<a href="javascript:XXXX">中的
871      * @memberOf string
872      * @param {String} sStr
873      * @return {String} 
874      */
875     var encodeHrefScript = function(sStr) {
876         return encodeHtml(encodeUrl(escScript(sStr)));
877     };
878     
879     /**
880      * 用做过滤直接放到正则表达式中的
881      * @memberOf string
882      * @param {String} sStr
883      * @return {String} 
884      */
885     var encodeRegExp = function(sStr) {
886         return sStr.replace(/[\\\^\$\*\+\?\{\}\.\(\)\[\]]/g, function(a,b){
887             return "\\"+a;
888         });
889     };
890     
891     /**
892      * 用做过滤直接URL参数里的  比如 http://show8.qq.com/abc_cgi?a=XXX  XXX就是要过滤的
893      * @memberOf string
894      * @param {String} sStr
895      * @return {String} 
896      */
897     var encodeUrl = function(sStr) {
898         return escape(sStr).replace(/\+/g, "%2B");
899     };
900     
901     /**
902         对需要出现在一个URI的一部分的不信任输入进行编码 
903         例如:
904         <a href="http://search.msn.com/results.aspx?q1=[Un-trusted-input]& q2=[Un-trusted-input]">Click Here!</a>
905         以下字符将会被编码: 
906         除[a-zA-Z0-9.-_]以外的字符都会被替换成URL编码
907      *
908      * @memberOf string
909      * @param {String} sStr
910      * @return {String} 
911      */
912     var encodeUriComponent = function(sStr){
913         sStr = encodeURIComponent(sStr);
914         sStr = sStr.replace(/~/g,"%7E");
915         sStr = sStr.replace(/!/g,"%21");
916         sStr = sStr.replace(/\*/g,"%2A");
917         sStr = sStr.replace(/\(/g,"%28");
918         sStr = sStr.replace(/\)/g,"%29");
919         sStr = sStr.replace(/'/g,"%27");
920         sStr = sStr.replace(/\?/g,"%3F");
921         sStr = sStr.replace(/;/g,"%3B");
922         return sStr;
923     };
924     
925     /**
926     url转向验证
927     描述:对通过javascript语句载入(或转向)的页面进行验证,防止转到第三方网页和跨站脚本攻击
928     返回值:true -- 合法;false -- 非法
929     例:
930     合法的值
931         http://xxx.qq.com/hi/redirect.html?url=http://www.qq.com
932         http://xxx.qq.com/hi/redirect.html?url=a.html
933         http://xxx.qq.com/hi/redirect.html?url=/a/1.html
934     非法的值
935         http://xxx.qq.com/hi/redirect.html?url=http://www.baidu.com
936         http://xxx.qq.com/hi/redirect.html?url=javascript:codehere
937         http://xxx.qq.com/hi/redirect.html?url=//www.qq.com
938      *
939      * @memberOf string
940      * @param {String} sUrl
941      * @return {String} 
942      */
943     var vaildTencentUrl = function(sUrl){
944         return (/^(https?:\/\/)?[\w\-.]+\.(qq|paipai|soso|taotao)\.com($|\/|\\)/i).test(sUrl)||(/^[\w][\w\/\.\-_%]+$/i).test(sUrl)||(/^[\/\\][^\/\\]/i).test(sUrl) ? true : false;
945     };
946     
947 
948     /**
949      * 验证给定字符串是否是url, 如果是url 则返回正常的url
950      * 
951      * @memberOf string
952      * @param {String} sUrl
953      * @return {String} 
954      */
955     var vaildUrl = function(url){ 
956         var url=encodeURI(url).replace(/(^\s*)|(\s*$)/g, ''),
957             protocolReg=/(^[a-zA-Z0-9]+[^.]):/,
958             domainReg=/^[\S.]+\.[\S.]+$/,
959             domainendReg=/[\w.]+\/(\S*)/,
960             jsReg=/;$/,
961             jpReg=/^[\s*]*javascript[\s*]*:/;
962             
963         if((!protocolReg.test(url)) && (!domainReg.test(url))){
964             url="";
965         }else{
966             if(!protocolReg.test(url)){
967                 url="http://"+url;
968             }
969             if(!domainendReg.test(url)){
970                 url=url+"/";
971                 
972             }
973             //如果是js为协议就清空
974             if(jpReg.test(url)){
975                 url="";
976             }
977         }
978         
979         return url;
980     };
981     
982     
983     /**
984      * 获取字符实际宽度
985      * @memberOf string
986      * @param {String} str 需要计算的字符串
987      * @param {Number} fontsize 字体大小,可以不填
988      * @return {Number}
989      */
990     var getCharWidth = function(str,fontsize) {
991         var d= document.createElement("div");
992         d.style.visibility= "hidden";
993         d.style.width= "auto";
994         if(fontsize) {
995             d.style.fontSize= fontsize + "px";
996         }
997         d.style.position= "absolute";
998         d.innerHTML= J.string.encodeHtmlSimple(str);
999         document.body.appendChild(d);
1000         var width= d.offsetWidth;
1001         document.body.removeChild(d);
1002         return width;
1003     };
1004     
1005     /**
1006      * 按给定宽度裁剪字符串
1007      * @memberOf string
1008      * @param {String} str 
1009      * @param {Number} fontsize 字体大小
1010      * @param {Number} width 限定的宽度
1011      * @return {Number}
1012      */
1013     var cutByWidth = function(str,fontsize,width) {
1014         for(var i=str.length;i>=0;--i)
1015         {
1016             str=str.substring(0, i);
1017             if(getCharWidth(str, fontsize)<width)
1018             {
1019                 return str;
1020             }
1021         }
1022         return '';
1023     };
1024     $S.cutByWidth = cutByWidth;
1025     $S.toString = toString;
1026     $S.template = template;
1027     $S.isURL = isURL;
1028     $S.parseURL = parseURL;
1029     $S.buildURL = buildURL;
1030     $S.mapQuery = mapQuery;
1031     $S.test = test;
1032     $S.contains = contains;
1033     $S.trim = trim;
1034     $S.clean = clean;
1035     $S.camelCase = camelCase;
1036     $S.hyphenate = hyphenate;
1037     $S.capitalize = capitalize;
1038     $S.escapeRegExp = escapeRegExp;
1039     $S.toInt = toInt;
1040     $S.toFloat = toFloat;
1041     $S.toSingleLine = toSingleLine;
1042     
1043     $S.toHtml = toHtml;
1044     $S.toTitle = toTitle;
1045     $S.toQueryPair = toQueryPair;
1046     $S.toQueryString = toQueryString;
1047     
1048     $S.hexToRgb = hexToRgb;
1049     $S.rgbToHex = rgbToHex;
1050     $S.stripScripts = stripScripts;
1051     $S.substitute = substitute;
1052     $S.replaceAll = replaceAll;
1053     
1054     $S.byteLength = byteLength;
1055     $S.cutRight = cutRight;
1056     
1057     $S.isNumber = isNumber;
1058     $S.isEmail = isEmail;
1059     
1060     $S.cutByBytes = cutByBytes;
1061     
1062     //html正文编码:对需要出现在HTML正文里(除了HTML属性外)的不信任输入进行编码
1063     $S.encodeHtmlSimple = encodeHtmlSimple;
1064     
1065     //html正文解码:对HtmlEncode函数的结果进行解码
1066     $S.decodeHtmlSimple = decodeHtmlSimple;
1067     $S.decodeHtmlSimple2 = decodeHtmlSimple2;
1068     
1069     
1070     /*
1071     html属性编码:对需要出现在HTML属性里的不信任输入进行编码
1072     注意:
1073     (1)该函数不适用于属性为一个URL地址的编码.这些标记包括:a/img/frame/iframe/script/xml/embed/object...
1074     属性包括:href/src/lowsrc/dynsrc/background/...
1075     (2)该函数不适用于属性名为 style="[Un-trusted input]" 的编码
1076     */
1077     $S.encodeHtmlAttributeSimple = encodeHtmlAttributeSimple;
1078     
1079     //用做过滤HTML标签里面的东东 比如这个例子里的<input value="XXXX">  XXXX就是要过滤的
1080     $S.encodeHtmlAttribute = encodeHtmlAttribute;
1081     
1082     //用做过滤直接放到HTML里的
1083     $S.encodeHtml = encodeHtml;
1084     
1085     //用做过滤直接放到HTML里js中的
1086     $S.encodeScript = encodeScript;
1087     
1088     //用做过滤直接放到<a href="javascript:XXXX">中的
1089     $S.encodeHrefScript = encodeHrefScript;
1090     
1091     //用做过滤直接放到正则表达式中的
1092     $S.encodeRegExp = encodeRegExp;
1093     
1094     //用做过滤直接URL参数里的  比如 http://show8.qq.com/abc_cgi?a=XXX  XXX就是要过滤的
1095     $S.encodeUrl = encodeUrl;
1096     
1097     /*
1098     对需要出现在一个URI的一部分的不信任输入进行编码 
1099     例如:
1100     <a href="http://search.msn.com/results.aspx?q1=[Un-trusted-input]& q2=[Un-trusted-input]">Click Here!</a>
1101     以下字符将会被编码: 
1102     除[a-zA-Z0-9.-_]以外的字符都会被替换成URL编码
1103     */
1104     $S.encodeUriComponent = encodeUriComponent;
1105     
1106     /*
1107     url转向验证
1108     描述:对通过javascript语句载入(或转向)的页面进行验证,防止转到第三方网页和跨站脚本攻击
1109     返回值:true -- 合法;false -- 非法
1110     例:
1111     合法的值
1112         http://xxx.qq.com/hi/redirect.html?url=http://www.qq.com
1113         http://xxx.qq.com/hi/redirect.html?url=a.html
1114         http://xxx.qq.com/hi/redirect.html?url=/a/1.html
1115     非法的值
1116         http://xxx.qq.com/hi/redirect.html?url=http://www.baidu.com
1117         http://xxx.qq.com/hi/redirect.html?url=javascript:codehere
1118         http://xxx.qq.com/hi/redirect.html?url=//www.qq.com
1119     */
1120     $S.vaildTencentUrl = vaildTencentUrl;
1121     
1122     $S.vaildUrl = vaildUrl;
1123     
1124     $S.getCharWidth = getCharWidth;
1125 
1126     
1127     
1128 
1129 
1130 
1131 
1132 
1133 
1134 
1135 
1136 
1137 
1138 
1139 
1140 });
1141 
1142 
1143 
1144 
1145 
1146 
1147 
1148 
1149