JavaScript即学即用教程[2]-字符串操作
我们观察整个计算机领域,这么多年,在研究的内容无非是这几种: 文本,图片,视频. 字符串的处理,至今仍然是一门很深的学问,如自然语言处理技术。所以我们学习js中的字符串基本处理方法,也是很有价值的。
字符串在底层的数据结构是一种数组,所以基本上文字处理操作函数,是对数组处理算法的一种综合和封装的运用。
创建字符串
字符串声明很简单,直接用双引号,或单引号包裹即可。
特殊的字符字面量-转义序列
非打印字符不能直接用字符字面量表示,需要用转义符号来表达. 例如:
1 | \n 换行 |
另外要知道,字符字面量还有一种十六进制编码值的表示法,比如你知道这个字符在ASCII码表的16进制值或unicode码表中的编码值,那么可以用 \xnn
\unnnn
的方式来表示。例如:
1 | \xa0 表示十进制160,他是latin1字符集(扩展了ASC码)里面的表象空格的这个字符。 |
备注: 在 JavaScript 里面,一个中文字和英文字,取 length 的时候,都是返回 1.
其他类型转String类型
首先,在JavaScript里面任何类型都可以有办法转换为String类型。转换办法有2种:
- 对象自身的toString方法
- 全局的String函数
toString方法几乎可以应用在任何类型,但是除了null和undefined。我认为可以把toString理解为对象的方法(实际上也是的),所以JavaScript里面凡是调用时是对象或能自动包装为对象的,则都拥有toString方法,如:
1 | true.toString() 返回'true' |
而String函数在调用时,其实他会优先调用toString函数来返回值。碰上null和undefined则自己处理:
1 | var str = String(123) 返回'123' |
不可变
像其他语言中一样,String在内存中应该是不可变的。
故,所有string的API操作函数,没有任何一个是对原始字符串进行修改的,哪怕是replace()也是返回一个新的字符串。字符串自身的toString方法,也是返回一个新的字符串副本。
API
原型方法:
- str.length, 获取字符串的长度
- charAt(index), 取某个索引位置的字符
- charCodeAt(index), 取某个索引位置的字符ASC码(实际是UCS码,在ES6里是unicode码)
- indexOf(str, [fromIndex]), 取某个字符或字符串所在的索引位置, 找不到输出-1。 同样还有个lastIndexOf
- search(str), 跟indexOf一样,只是既可以字符串,又可以搜正则。search无法找到所有匹配的子串的位置。
- slice(index, index), 沾出一部分字符串来,从index到另一个index,如果第二个参数没有,就到末尾. 前包后不包。这个跟substring函数一样,且能支持负数(-1表示最后一个元素的下标,以此类推),所以直接学习slice就可以了。
- substr(index,len), 从某个位置开始截取一定数量的字符。
- match(regexp), 可以返回匹配的子串的数组,匹配不到返回null. 正则带g可以返回所有匹配的数组,不带则返回一个项的数组。(所以match好像无法找出匹配到的子捕获组的内容,这样的话,我们貌似只能通过regexp.exec那个函数来实现拿出捕获组的内容了)。通过match拿到结果数组,我们可以对匹配到的所有内容数组进行后续的map,forEach等操作
- replace(regexp|substr, newSubstr|function), 替换某个子串为另外一个子串,或者新的子串用自己的函数来处理。带g才能替换所有匹配到的子串。
- split(separatorStr|regexp), 可以用指定分隔符,或者正则,来把字符串隔成多个子串的数组。
- toLowerCase,toUpperCase: 变小写变大写
- concat(), 连接一个新的字符串,返回连接后的字符串。
- padStart/padEnd 这俩方法后来新加的,挺有用的,可以用来给定特定的字符来对齐字符串
- repeat 重复某个字符串n次
- startWith(str)/endWith(), 判断是否以某个子串开头。
str.includes(searchString[, position]) 判断是否包含某个子串(内部实现可以用indexOf是否为-1来作为判定)
String.fromCharCode(), 可以把数值转换为字符串。适合你知道一个unicode码,想直接以unicode的形式输入这个字符的时候。当然,如果真有这种需求,也可以直接在双引号内使用\u+unicode这样的字面量的形式。
replace
replace函数配合正则可以进行更强大的匹配替换。
- 默认replace只能替换匹配到的第一个子串。如果想全部替换则可以使用正则表达式,并带上g参数
1 | text.replace(/at/g, 'amd') |
带了g参数正则的replace,相当于正则会对字符串进行多次匹配,直到正则游标进行到无法匹配为止,因此可以对字符串中符合正则的子串进行全部替换。
在上面的替換字符串’amd’中,可以使用這些特定的符号来构造你要生成的目标字符串:
1 | $$ // 表示 $ 这个符号自身 |
更精细的replace控制
有时,需要在替换字符串时加入一些控制逻辑,此时可以把replace第二个参数设置为function函数:
1 | text.replace(/[<>"&]/g, function (matched, pos, originalText) { |
应用
- 找出一个字符串中所有等于abc的子串坐标
1 |
找出一个字符串中所有等于abc的单词的坐标
找出一个字符串中所有等于abc的单词的个数
统计一个字符串中各个单词出现的频数(wordcount)
统计一个字符串中出现次数最多的那个单词(对wordcount结果进行取最大值?)
实现一个trim函数,去掉字符串左右的空格
表单项不能以xxx开头
1
2
3if (str.indexOf(0) == '-') {
alert('error')
}判断一个字符串里有没有数字
利用search函数,支持正则。而indexOf不支持。1
2
3if (str.search(/[0-9]/) != -1) {
alert('有数字')
}寻找出字符串里符号要求的某个子串
要想满足这个要求,比如找出一个字符串里以a开头的单词,这种需求,用String的其他方法都无法满足。
用search确实可以找到第一个位置,却无法找到所有的,自然就无法取出这些子串。
而通过在match正则匹配,就可以对字符串进行子串匹配搜索,并且拿到结果。1
str.match(/a\w+\s/)
replace字符串里某些字符替换成另外一种逻辑
String的replace函数就比较适合这种场景了,而且这种场景在现实中很常见。像服务端提交数据时,把年和月份连接提来提交
利用String的concat方法, 或者直接用+号运算符进行字符串拼接。1
str1.concat(str2)
防范xss攻击,实现HTML转义
利用了replace的高级用法1
2
3
4
5
6
7
8
9
10this.REGX_HTML_ENCODE = /"|&|'|<|>|[\x00-\x20]|[\x7F-\xFF]|[\u0100-\u2700]/g;
function encode(s){
return (typeof s != "string") ? s :
s.replace(this.REGX_HTML_ENCODE, function($0){
var c = $0.charCodeAt(0), r = ["&#"];
c = (c == 0x20) ? 0xA0 : c;
r.push(c); r.push(";");
return r.join("");
});
};
这里的0x20这个ASC值是ASCII码里面的空格,之所以换成0xA0是因为html实体里面定义了0xA0表示空格,所以这里做了切换。其实用0x20也没什么问题。http://www.w3school.com.cn/tags/html_ref_entities.html
- 实现首字母大写的几种方式,如例子 “abc def hig” 变为 “Abc Def Hig”
解决思路:可以想象为是对每个单词进行首字母大写(比如先split整个句子为单词的数组,再遍历处理)
针对单词:
1 | // 方法1:对于单个单词,直接取第一个字符,再拼上slice后面的子串 |
针对句子的话,其实如果是分割为单词数组,每个单词同样可以使用上面的算法,我们来看下句子还有哪些更方便的算法:
1 | // 方法2: 把句子分割为单词数组,对每个单词:把第一个单词找出,并replace为其大写形式 |
1 | // 方法3: 上面是直接拿出第一个字符再replace,我们还直接用正则找出第一个字符 |
那么,到底最好用的方法是哪个呢? 我觉得有这两个:
1 | // 要么分割为单词数组,再正则替换 |
Refer
学习下html转义可参考:
http://www.cnblogs.com/snowinmay/p/3224375.html
http://blog.chinaunix.net/uid-20511797-id-3118652.html
http://www.cnblogs.com/sxz2008/p/6518367.html