正则表达式是一种描述模式的方法,用来描述“部分字符串的查找问题”。每个正则表达式表示的都是一个字符串的集合。
1.基本操作
它主要有三种模式:
1.1连接操作
多个字符组成字符串,比如AB
1.2或操作
用"|"表示,可以在模式中指定多种可能的匹配,比如A|B,代表查找A或B
1.3闭包操作
可以将模式中的部分重复任意次,用*标记在需要重复的模式之后,表示闭包。比如A*B,代表由0个或多个A和一个B组成的字符串
1.4三种模式的优先级
闭包操作 > 连接操作 > 或操作,比如
- AB|C 代表{AB,C}
- AB* 代表{A,AB,ABB,ABBB...}
通过()可以修改优先顺序,比如:
- C(A|B)D 代表 {CAD,CBD};
- (A|C)((B|C)D) 代表 {ABD,ACD,CBD,CCD};
- (AB)*代表{‘’,AB,ABAB,ABABAB...}
2.缩略写法
有时有的描述使用基本操作可能显得比较冗长,比如想要表示可能是26个字母中的一个,就要写成A|B|C|D....|X|Y|Z,正则表达式提供很多缩略写法,上面可以简写为[A-Z]。
2.1字符集描述
名称 | 写法 | 举例 |
---|---|---|
通配符 | . | A.B(代表{A,任意字符1,任意字符2,..., B}) |
指定集合 | 包含在[]中 | [ABcd] |
范围集合 | 包含在[]中,由-间隔 | [a-z][0-9] |
补集 | 包含在[]中,首字母为^ | [^ABCD] (代表除了A,B,C,D意外的其他字符) |
2.2闭包的简写
含义 | 记法 | 举例 | 原始写法 |
---|---|---|---|
至少重复1次 | + | (AB)+ | (AB)(AB)* |
重复0或1次 | ? | (AB)? | ∈|AB |
重复n次 | 由{}指定次数 | (AB){3} | (AB)(AB)(AB) |
重复指定范围内的次数 | 由{}指定次数范围 | (AB){1-2} | (AB)|(AB)(AB) |
2.3转义字符
某些字符,比如"\","|","*",".","(",")"等都是正则标的是的元字符,如果想要表示需要在前面添加转义字符"\",例如匹配</br>要写成let re = /<\/br>/
2.4三种括号的区分
记法 | 作用 |
---|---|
() | 改变优先级 |
[] | 代表某个集合 |
{} | 用来指定重复次数 |
3.其他常用字符
记法 | 作用 |
---|---|
\s | 空格 |
\S | 非空格 |
\d | 数字 |
\D | 非数字 |
\w | 字符 ( 字母 ,数字,下划线_ ) |
\W | 非字符 |
4.js中正则表达式的运用:
4.1在js中的定义:
//方式1,可以传入多个参数,,第一个参数是正则规则,第二个是其他字符,比如全局g,忽略大小写i
let re1 = new RegExp('a');
let re2 = new RegExp('a','g'); //全局匹配
let re2 = new RegExp('a','i'); //忽略大小写匹配
let re3 = new RegExp('a','gi'); //全局忽略大小写匹配
//方式2
let re4 = /a/; // 简写方法
let re5 = /a/g;
let re6=/a/gi;
4.2 test()
作用:test方法用来在字符串中查找符合正则的内容,若查找到返回true,反之返回false。
用法:正则.test(字符串)
function test(){
let re =/rr.y/;
let testStr1 = 'array';
let testStr2 = 'b';
let result1 = re.test(testStr1);//true
let result2 = re.test(testStr2);//false
}
4.3 search()
作用:在字符串搜索符合正则的内容,搜索到就返回出现的位置(从0开始,如果有多个,返回第一个的位置), 如果搜索失败就返回 -1
用法:字符串.search(正则)
function search(){
let re = /a/i;//忽略大小写查找a
let testStr = 'NBA';
testStr.search(re); //返回2
}
4.4 match()
作用:在字符串中搜索复合规则的内容,搜索成功就返回内容,格式为数组,失败就返回null。
用法: 字符串.match(正则)
4.4.1 非全局匹配
function match() {
let testStr = 'aa1bb12cc3dd';
let re = /\d+/;
testStr.match(re)//[ '1', index: 2, input: 'aa1bb12cc3dd' ]
}
非全局匹配的时候,返回的数据中包含了此次匹配详细的信息,数组的第一个元素是这次匹配到的字符串,数组的index属性是该字符串的index,最后的input是此次的输入。
4.4.2 全局匹配
在全局匹配的模式下只会输出简单的结果,如果想要详细的结果请使用exec方法
function match(){
let testStr = 'aa1bb12cc3dd';
let re = /\d+/g;//全局匹配至少出现一个数字的字符串
testStr.match(re)//输出:[ '1', '12', '3' ]
}
4.5 replace()
作用:查找符合正则的字符串,就替换成对应的字符串。返回替换后的内容。
用法1: 字符串.replace(正则,替换字符串)
function replace(){
/**注意这两个的差别,会导致不同的结果,是从左向右匹配的,比如下面的re1的匹配过程:
* 1.找到所有的"北京仁科互动"替换
* 2.找到所有的"仁科互动"替换
* 3.找到所有的"仁科"替换
*/
let re1 = /北京仁科互动|仁科互动|仁科/g;//全局或匹配
let re2 = /北京仁科互动|仁科|仁科互动/g;
let testStr = '北京仁科互动的简称不是仁科而是仁科互动';
let result1 = testStr.replace(re1,'a');//a的简称不是a而是a
let result2 = testStr.replace(re2,'a');//a的简称不是a而是a互动
上面的代码只是简单的将匹配字符串换成了单个a,如果想"北京仁科互动"对应“aaaaaa”,"仁科"对应“aa”,需要使用第二种写法
用法2: 字符串.replace(正则,回调函数)
回调函数的参数是被匹配的字符串,返回值是替换字符串
function replace2(){
let re = /北京仁科互动|仁科互动|仁科/g;
let testStr = '北京仁科互动的简称不是仁科而是仁科互动';
let result = testStr.replace(re,(matchStr) => {
//matchStr就是re中定义的所要匹配的字符串,比如这里一次是:"北京仁科互动","仁科互动","仁科"
let result='';
for(let i = 0, len = matchStr.length; i < len; i++){
result+='a';
}
return result;
});
console.log(result);//打印结果:aaaaaa的简称不是aa而是aaaa
}
回调函数的第二个参数是matchStr在字符串中的角标,比如修改下上面的代码:
let result = testStr.replace(re,(matchStr,index) => {
console.log(index)//依次打印0,11,15
return 'a';
});
4.6 exec()
作用:用来检索字符串中正则表达式的匹配,如果匹配到了那么就返回一个存放有结果的数组,如果没有匹配到就返回一个null。
用法:正则.exec(字符串)
4.6.1 非全局匹配
function exec() {
let re = /nba|好看/;
let testStr = 'nba要比cba好看的多';
let match1 = re.exec(testStr);
console.log(match1);//[ 'nba', index: 0, input: 'nba要比cba好看的多' ]
console.log(re.lastIndex);//lastIndex => 0
let match2 = re.exec(testStr);
console.log(match2);//[ 'nba', index: 0, input: 'nba要比cba好看的多' ]
console.log(re.lastIndex);////lastIndex => 0
}
可以看到非全局匹配时,返回的数组与调用方法 String.match() 返回的数组是相同的:返回的结果依次是:匹配到的字符串,该字符串在输入源中所在的index,输入源;
此外match1和match2的结果是相同的,而写两个match是为了和下面的全局匹配做比较的。
4.6.2 全局匹配
在全局匹配下,exec() 的行为就稍微复杂一些。每次执行exec()以后,RegExpObject的lastIndex属性会指向此次匹配的字符串的最后一个字符所在的角标,在下次匹配时会在 RegExpObject 的 lastIndex 属性指定的字符处开始检索字符串 string。当 exec() 找到了与表达式相匹配的文本时,在匹配后,它将把 RegExpObject 的 lastIndex 属性设置为匹配文本的最后一个字符的下一个位置。这就是说,
可以通过反复调用 exec() 方法来遍历字符串中的所有匹配文本。当 exec() 再也找不到匹配的文本时,它将返回 null,并把 lastIndex 属性重置为 0。
function execGlobal() {
let re = /nba|好看/g;
let testStr = 'nba要比cba好看的多';
let match1 = re.exec(testStr);
console.log(match1);//[ 'nba', index: 0, input: 'nba要比cba好看的多' ]
console.log(re.lastIndex);//lastIndex => 3
let match2 = re.exec(testStr);
console.log(match2);//[ '好看', index: 8, input: 'nba要比cba好看的多' ]
console.log(re.lastIndex);////lastIndex => 10
}
在一般情况下我们会写一个循环来进行全局匹配:
function execGlobalWhile() {
let re = new RegExp('好看|nba','gi');
let testStr = 'nba要比cba好看的多';
let match;
while (match = re.exec(testStr)){
console.log(match);
}
//打印结果如下:
//[ 'nba', index: 0, input: 'nba要比cba好看的多' ]
//[ '好看', index: 8, input: 'nba要比cba好看的多' ]
}
4.7 例子
4.7.1 查找出现次数最多的字符
function findMore(){
let str = 'assssjdssskssalsssdkjsssdss';
let arr = str.split(''); //把字符串转换为数组
str = arr.sort().join(''); //首先进行排序,这样结果会把相同的字符放在一起,然后再转换为字符串
//alert(str); // aaddjjkklsssssssssssssssss
let value = '';
let index = 0;
let re = /(\w)\1+/g; //匹配字符,且重复这个字符,重复次数至少一次。
str.replace(re,function($0,$1){
//alert($0); 代表每次匹配成功的结果 : aa dd jj kk l sssssssssssssssss
//alert($1); 代表每次匹配成功的第一个子项,也就是\w: a d j k l S
if(index<$0.length){ //如果index保存的值小于$0的长度就进行下面的操作
index = $0.length; // 这样index一直保存的就在最大的长度
value = $1; //value保存的是出现最多的这个字符
}
});
console.log('最多的字符:'+value+',重复的次数:'+index); // 最多的字符:s,重复的次数:17
}
4.7.2在react native中实现hightlightText
就是类似于百度搜索的关键字高亮显示:
1.在render方法中返回如下:
render(){
let searchKeys = this.props.searchKeys;
//排序是为了让长度比较长的key在前面
searchKeys.sort((k1,k2) => k2.length - k1.length);
return <Text style={this.props.contentStyle}
numberOfLines={1}>
{this._getPieceTexts(this.props.textToHighlight, searchKeys)}
</Text>
}
2._getPieceTexts:
_getPieceTexts(textToHighlight, keys) {
let pieces = this._getPieces(textToHighlight, keys);
return pieces.map(piece => {
let text = textToHighlight.substring(piece.start, piece.end);
return piece.highlight ? this._getText(text) : text;
});
}
上面的_getPieces方法就是利用正则的exec方法,将原字符串中每一个片段都保存为一个对象,该对象格式如下:
{
start,//片段开始位置
end,//片段结束位置
highlight//该片段是否要高亮显示
}
3._getPieces方法如下
:
_getPieces(textToHighlight, keys = []) {
let re = new RegExp(keys.join('|'), this.props.caseSensitive ? 'g' : 'gi');
let match;
let pieces = [];
let result =[];
while ((match = re.exec(textToHighlight))) {
let start = match.index;
let end = re.lastIndex;
pieces.push({
start: start,
end: end,
});
}
let totalLength = textToHighlight.length;
if (pieces.length === 0) {
this._append(0, totalLength, false, result);
} else {
let lastIndex = 0;
pieces.forEach((piece) => {
this._append(lastIndex, piece.start, false, result);
this._append(piece.start, piece.end, true, result);
lastIndex = piece.end;
} );
this._append(lastIndex, totalLength, false, result);
}
// console.log('result:' + JSON.stringify(result));
return result;
}
_append(start, end, highlight, result) {
if (end - start > 0) {
result.push({
start: start,
end: end,
highlight: highlight
});
}
}
展示效果如下:
完整代码请看github:https://github.com/wangzhen90/react-native-highlight-text
参考:https://www.cnblogs.com/moqing/archive/2016/07/13/5665126.html