解析JavaScript中的字符串类型与字符编码支持

定义
字符串就是零个或多个排在一起的字符,放在单引号或双引号之中。

'abc'
"abc"

单引号字符串的内部,可以使用双引号。双引号字符串的内部,可以使用单引号。

'key = "value"'
"It's a long journey"

上面两个都是合法的字符串。

如果要在单引号字符串的内部,使用单引号(或者在双引号字符串的内部,使用双引号),就必须在内部的单引号(或者双引号)前面加上反斜杠,用来转义。

'Did she say \'Hello\'?'
// "Did she say 'Hello'?"

"Did she say \"Hello\"?"
// "Did she say "Hello"?"

由于HTML语言的属性值使用双引号,所以很多项目约定JavaScript语言的字符串只使用单引号,本教程就遵守这个约定。当然,只使用双引号也完全可以。重要的是,坚持使用一种风格,不要两种风格混合。

字符串默认只能写在一行内,分成多行将会报错。

'a
b
c'
// SyntaxError: Unexpected token ILLEGAL

上面代码将一个字符串分成三行,JavaScript就会报错。

如果长字符串必须分成多行,可以在每一行的尾部使用反斜杠。

var longString = "Long \
long \
long \
string";

longString
// "Long long long string"

上面代码表示,加了反斜杠以后,原来写在一行的字符串,可以分成多行书写。但是,输出的时候还是单行,效果与写在同一行完全一样。注意,反斜杠的后面必须是换行符,而不能有其他字符(比如空格),否则会报错。

连接运算符(+)可以连接多个单行字符串,将长字符串拆成多行书写,输出的时候也是单行。

var longString = 'Long '
 + 'long '
 + 'long '
 + 'string';

如果想输出多行字符串,有一种利用多行注释的变通方法。

(function () { /*
line 1
line 2
line 3
*/}).toString().split('\n').slice(1, -1).join('\n')
// "line 1
// line 2
// line 3"

上面的例子中,输出的字符串就是多行。

转义
反斜杠(\)在字符串内有特殊含义,用来表示一些特殊字符,所以又称为转义符。

需要用反斜杠转义的特殊字符,主要有下面这些:

  • \0 null(\u0000)
  • \b 后退键(\u0008)
  • \f 换页符(\u000C)
  • \n 换行符(\u000A)
  • \r 回车键(\u000D)
  • \t 制表符(\u0009)
  • \v 垂直制表符(\u000B)
  • \' 单引号(\u0027)
  • \" 双引号(\u0022)
  • \ 反斜杠(\u005C)

上面这些字符前面加上反斜杠,都表示特殊含义。

console.log('1\n2')
// 1
// 2

上面代码中,\n表示换行,输出的时候就分成了两行。

反斜杠还有三种特殊用法。

(1)\HHH

反斜杠后面紧跟三个八进制数(000到377),代表一个字符。HHH对应该字符的Unicode码点,比如\251表示版权符号。显然,这种方法只能输出256种字符。

(2)\xHH

\x后面紧跟两个十六进制数(00到FF),代表一个字符。HH对应该字符的Unicode码点,比如\xA9表示版权符号。这种方法也只能输出256种字符。

(3)\uXXXX

\u后面紧跟四个十六进制数(0000到FFFF),代表一个字符。HHHH对应该字符的Unicode码点,比如\u00A9表示版权符号。

下面是这三种字符特殊写法的例子。

'\251' // "©"
'\xA9' // "©"
'\u00A9' // "©"

'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true

如果在非特殊字符前面使用反斜杠,则反斜杠会被省略。

'\a'
// "a"

上面代码中,a是一个正常字符,前面加反斜杠没有特殊含义,反斜杠会被自动省略。

如果字符串的正常内容之中,需要包含反斜杠,则反斜杠前面需要再加一个反斜杠,用来对自身转义。

"Prev \\ Next"
// "Prev \ Next"

字符串与数组
字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。

var s = 'hello';
s[0] // "h"
s[1] // "e"
s[4] // "o"

// 直接对字符串使用方括号运算符
'hello'[1] // "e"

如果方括号中的数字超过字符串的长度,或者方括号中根本不是数字,则返回undefined。

'abc'[3] // undefined
'abc'[-1] // undefined
'abc'['x'] // undefined

但是,字符串与数组的相似性仅此而已。实际上,无法改变字符串之中的单个字符。

var s = 'hello';

delete s[0];
s // "hello"

s[1] = 'a';
s // "hello"

s[5] = '!';
s // "hello"

上面代码表示,字符串内部的单个字符无法改变和增删,这些操作会默默地失败。

字符串之所以类似于字符数组,实际是由于对字符串进行方括号运算时,字符串会自动转换为一个字符串对象。

length属性
length属性返回字符串的长度,该属性也是无法改变的。

var s = 'hello';
s.length // 5

s.length = 3;
s.length // 5

s.length = 7;
s.length // 5

上面代码表示字符串的length属性无法改变,但是不会报错。

字符集
JavaScript使用Unicode字符集,也就是说在JavaScript内部,所有字符都用Unicode表示。

不仅JavaScript内部使用Unicode储存字符,而且还可以直接在程序中使用Unicode,所有字符都可以写成”\uxxxx”的形式,其中xxxx代表该字符的Unicode编码。比如,\u00A9代表版权符号。

var s = '\u00A9';
s // "©"

每个字符在JavaScript内部都是以16位(即2个字节)的UTF-16格式储存。也就是说,JavaScript的单位字符长度固定为16位长度,即2个字节。

但是,UTF-16有两种长度:对于U+0000到U+FFFF之间的字符,长度为16位(即2个字节);对于U+10000到U+10FFFF之间的字符,长度为32位(即4个字节),而且前两个字节在0xD800到0xDBFF之间,后两个字节在0xDC00到0xDFFF之间。举例来说,U+1D306对应的字符为𝌆,它写成UTF-16就是0xD834 0xDF06。浏览器会正确将这四个字节识别为一个字符,但是JavaScript内部的字符长度总是固定为16位,会把这四个字节视为两个字符。

var s = '\uD834\uDF06';

s // "𝌆"
s.length // 2
/^.$/.test(s) // false
s.charAt(0) // ""
s.charAt(1) // ""
s.charCodeAt(0) // 55348
s.charCodeAt(1) // 57094

上面代码说明,对于于U+10000到U+10FFFF之间的字符,JavaScript总是视为两个字符(字符的length属性为2),用来匹配单个字符的正则表达式会失败(JavaScript认为这里不止一个字符),charAt方法无法返回单个字符,charCodeAt方法返回每个字节对应的十进制值。

所以处理的时候,必须把这一点考虑在内。对于4个字节的Unicode字符,假定C是字符的Unicode编号,H是前两个字节,L是后两个字节,则它们之间的换算关系如下。

// 将大于U+FFFF的字符,从Unicode转为UTF-16
H = Math.floor((C - 0x10000) / 0x400) + 0xD800
L = (C - 0x10000) % 0x400 + 0xDC00

// 将大于U+FFFF的字符,从UTF-16转为Unicode
C = (H - 0xD800) * 0x400 + L - 0xDC00 + 0x10000

下面的正则表达式可以识别所有UTF-16字符。

([\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF])

由于JavaScript引擎(严格说是ES5规格)不能自动识别辅助平面(编号大于0xFFFF)的Unicode字符,导致所有字符串处理函数遇到这类字符,都会产生错误的结果。如果要完成字符串相关操作,就必须判断字符是否落在0xD800到0xDFFF这个区间。

下面是能够正确处理字符串遍历的函数。

function getSymbols(string) {
 var length = string.length;
 var index = -1;
 var output = [];
 var character;
 var charCode;
 while (++index < length) {
  character = string.charAt(index);
  charCode = character.charCodeAt(0);
  if (charCode >= 0xD800 && charCode <= 0xDBFF) {
   output.push(character + string.charAt(++index));
  } else {
   output.push(character);
  }
 }
 return output;
}

var symbols = getSymbols('𝌆');

symbols.forEach(function(symbol) {
 // ...
});

替换(String.prototype.replace)、截取子字符串(String.prototype.substring, String.prototype.slice)等其他字符串操作,都必须做类似的处理。

Base64转码
Base64是一种编码方法,可以将任意字符转成可打印字符。使用这种编码方法,主要不是为了加密,而是为了不出现特殊字符,简化程序的处理。

JavaScript原生提供两个Base64相关方法。

  • btoa():字符串或二进制值转为Base64编码
  • atob():Base64编码转为原来的编码
var string = 'Hello World!';

btoa(string) // "SGVsbG8gV29ybGQh"
atob('SGVsbG8gV29ybGQh') // "Hello World!"
这两个方法不适合非ASCII码的字符,会报错。

btoa('你好')
// Uncaught DOMException: The string to be encoded contains characters outside of the Latin1 range.
要将非ASCII码字符转为Base64编码,必须中间插入一个转码环节,再使用这两个方法。

function b64Encode(str) {
 return btoa(encodeURIComponent(str));
}

function b64Decode(str) {
 return decodeURIComponent(atob(str));
}

b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE"
b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好"
(0)

相关推荐

  • JS实现对中文字符串进行utf-8的Base64编码的方法(使其与Java编码相同)

    本文实例讲述了JS实现对中文字符串进行utf-8的Base64编码的方法.分享给大家供大家参考,具体如下: 要进行编码的字符串:"select 用户名 from 用户" 使用JAVA进行编码,Java程序: String sql = "select 用户名 from 用户"; String encodeStr = new String(Base64.encode(sql.getBytes("UTF-8"))); // 编码 System.out.

  • JS对字符串编码的几种方式使用指南

    函数 描述 encodeURI() 把字符串编码为 URI encodeURIComponent() 把字符串编码为 URI 组件 escape() 对字符串进行编码 上面是查询来自w3school的资料.那么三者之间有什么区别呢,请容我测试测试. 复制代码 代码如下: var str = "http://localhost:8080/Product/index?id=123&attr=456&area=中国"; console.log(encodeURI(str));

  • 对字符串进行HTML编码和解码的JavaScript函数

    编码函数: 复制代码 代码如下: function HtmlEncode(str) { var t = document.createElement("div"); t.textContent ? t.textContent = str : t.innerText = str; return t.innerHTML; } 解码函数: 复制代码 代码如下: function HtmlDecode(str) { var t = document.createElement("di

  • Python中还原JavaScript的escape函数编码后字符串的方法

    遇到一个问题需要用Python把JavaScript中escape的中文给还原,但找了大半天,也没有找到答案,只好自己深入研究解决方案. 我们先来看在js中escape一段文字的编码 复制代码 代码如下: a = escape('这是一串文字'); alert(a); 输出: 复制代码 代码如下: %u8FD9%u662F%u4E00%u4E32%u6587%u5B57 咋一看,就感觉有点类似json格式,我们来看看标准的json格式编码同样的汉子"这是一串文字" 复制代码 代码如下:

  • JavaScript中最简洁的编码html字符串的方法

    html字符串是指'<div id="a">aklsdjfklsjdfl</div>'这样的带html特殊符号的字符串,我们通常要对他进行处理再输出以免输出成了真正的html元素,也就是把<变成<这样的html符号代码. 如果字符串很长,里面特殊符号很多,我们该怎么简单而高效的把他们全部转码呢?循环?正则表达式?都不用!且看: 复制代码 代码如下: function bian(a){return new Option(a).innerHTML} 这就

  • JS 文字符串转换unicode编码函数

    复制代码 代码如下: function uniencode(text) { text = escape(text.toString()).replace(/\+/g, "%2B"); var matches = text.match(/(%([0-9A-F]{2}))/gi); if (matches) { for (var matchid = 0; matchid < matches.length; matchid++) { var code = matches[matchid

  • 将字符串转换成gb2312或者utf-8编码的参数(js版)

    在很多时候,我们直接在url中传递中文参数时,读到的中文都是乱码,那么我们应该怎么将这些参数转换呢? 下面我们来介绍一下方法 1.我们新建一个 UrlEncode.js 然后将下面的代码拷贝进去 复制代码 代码如下: //JS版的Server.UrlEncode编码函数 String.prototype.UrlEncodeGB2312 = function () { var str = this; str = str.replace(/./g, function (sHex) { window.

  • JS对URL字符串进行编码/解码分析

    虽然escape().encodeURI().encodeURIComponent()三种方法都能对一些影响URL完整性的特殊 字符进行过滤.但后两者是将字符串转换为UTF-8的方式来传输,解决了页面编码不一至导致的乱码问 题.例如:发送页与接受页的编码格式(Charset)不一致(假设发送页面是GB2312而接收页面编码是 UTF-8),使用escape()转换传输中文字串就会出现乱码问题. 以下是JS下对URL进行编/解码的各种方法: escape 方法:返回一个可在所有计算机上读取的编码

  • JavaScript将字符串转换成字符编码列表的方法

    本文实例讲述了JavaScript将字符串转换成字符编码列表的方法.分享给大家供大家参考.具体如下: JavaScript将字符串转换成字符编码列表,例如foo转换成 [112,111,111] 方法 1: JavaScript 1.6 Array.map('foo', function(x) { return String.charCodeAt(x) }) // is [112,111,111] 方法2: JavaScript 1.7 [ String.charCodeAt(x) for ea

  • JavaScript中字符串与Unicode编码互相转换的实现方法

    本文实例讲述了JavaScript中字符串与Unicode编码互相转换的实现方法.分享给大家供大家参考,具体如下: 这段代码演示了JavaScript中字符串与Unicode编码的转换: // 为了控制台的演示方便, 变量没有添加 var 定义 // 实际编程中请避免 // 字符串 str = "中文"; // 获取字符 char0 = str.charAt(0); // "中" // 数字编码值 code = str.charCodeAt(0); // 20013

  • js中字符串编码函数escape()、encodeURI()、encodeURIComponent()区别详解

    JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数: unescape,decodeURI,decodeURIComponent . 下面简单介绍一下它们的区别 1 escape()函数 定义和用法 escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串. 语法 escape(string) 参数 描述 string 必需.要被转义或编码的字符串. 返回值 已编码的 st

  • js对图片base64编码字符串进行解码并输出图像示例

    复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv=&qu

  • js实现字符串的16进制编码不加密

    今天看到群里有人提问关于十六进制编码的问题,所以使用JS写了个小程序转换一下,记住:这只是编码,不是加密! 字符串转十六进制编码: 复制代码 代码如下: str="http://www.qq.com"; len=str.length; arr=[]; for(var i=0;i<len;i++){ arr.push(str.charCodeAt(i).toString(16)); } console.log("\\x"+arr.join("\\x&q

随机推荐