正則表達式是一種描述模式的方法,用來描述“部分字符串的查找問題”。每個正則表達式表示的都是一個字符串的集合。
1.基本操作
它主要有三種模式:
1.1連接操作
多個字符組成字符串,比如AB
1.2或操作
用"|"表示,可以在模式中指定多種可能的匹配,比如A|B,代表查找A或B
1.3閉包操作
可以將模式中的部分重復任意次,用*標記在需要重復的模式之后,表示閉包。比如A*B,代表由0個或多個A和一個B組成的字符串
1.4三種模式的優(yōu)先級
閉包操作 > 連接操作 > 或操作,比如
- AB|C 代表{AB,C}
- AB* 代表{A,AB,ABB,ABBB...}
通過()可以修改優(yōu)先順序,比如:
- 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次 | 由{}指定次數(shù) | (AB){3} | (AB)(AB)(AB) |
| 重復指定范圍內(nèi)的次數(shù) | 由{}指定次數(shù)范圍 | (AB){1-2} | (AB)|(AB)(AB) |
2.3轉(zhuǎn)義字符
某些字符,比如"\","|","*",".","(",")"等都是正則標的是的元字符,如果想要表示需要在前面添加轉(zhuǎn)義字符"\",例如匹配</br>要寫成let re = /<\/br>/
2.4三種括號的區(qū)分
| 記法 | 作用 |
|---|---|
| () | 改變優(yōu)先級 |
| [] | 代表某個集合 |
| {} | 用來指定重復次數(shù) |
3.其他常用字符
| 記法 | 作用 |
|---|---|
| \s | 空格 |
| \S | 非空格 |
| \d | 數(shù)字 |
| \D | 非數(shù)字 |
| \w | 字符 ( 字母 ,數(shù)字,下劃線_ ) |
| \W | 非字符 |
4.js中正則表達式的運用:
4.1在js中的定義:
//方式1,可以傳入多個參數(shù),,第一個參數(shù)是正則規(guī)則,第二個是其他字符,比如全局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方法用來在字符串中查找符合正則的內(nèi)容,若查找到返回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()
作用:在字符串搜索符合正則的內(nèi)容,搜索到就返回出現(xiàn)的位置(從0開始,如果有多個,返回第一個的位置), 如果搜索失敗就返回 -1
用法:字符串.search(正則)
function search(){
let re = /a/i;//忽略大小寫查找a
let testStr = 'NBA';
testStr.search(re); //返回2
}
4.4 match()
作用:在字符串中搜索復合規(guī)則的內(nèi)容,搜索成功就返回內(nèi)容,格式為數(shù)組,失敗就返回null。
用法: 字符串.match(正則)
4.4.1 非全局匹配
function match() {
let testStr = 'aa1bb12cc3dd';
let re = /\d+/;
testStr.match(re)//[ '1', index: 2, input: 'aa1bb12cc3dd' ]
}
非全局匹配的時候,返回的數(shù)據(jù)中包含了此次匹配詳細的信息,數(shù)組的第一個元素是這次匹配到的字符串,數(shù)組的index屬性是該字符串的index,最后的input是此次的輸入。
4.4.2 全局匹配
在全局匹配的模式下只會輸出簡單的結(jié)果,如果想要詳細的結(jié)果請使用exec方法
function match(){
let testStr = 'aa1bb12cc3dd';
let re = /\d+/g;//全局匹配至少出現(xiàn)一個數(shù)字的字符串
testStr.match(re)//輸出:[ '1', '12', '3' ]
}
4.5 replace()
作用:查找符合正則的字符串,就替換成對應(yīng)的字符串。返回替換后的內(nèi)容。
用法1: 字符串.replace(正則,替換字符串)
function replace(){
/**注意這兩個的差別,會導致不同的結(jié)果,是從左向右匹配的,比如下面的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,如果想"北京仁科互動"對應(yīng)“aaaaaa”,"仁科"對應(yīng)“aa”,需要使用第二種寫法
用法2: 字符串.replace(正則,回調(diào)函數(shù))
回調(diào)函數(shù)的參數(shù)是被匹配的字符串,返回值是替換字符串
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);//打印結(jié)果:aaaaaa的簡稱不是aa而是aaaa
}
回調(diào)函數(shù)的第二個參數(shù)是matchStr在字符串中的角標,比如修改下上面的代碼:
let result = testStr.replace(re,(matchStr,index) => {
console.log(index)//依次打印0,11,15
return 'a';
});
4.6 exec()
作用:用來檢索字符串中正則表達式的匹配,如果匹配到了那么就返回一個存放有結(jié)果的數(shù)組,如果沒有匹配到就返回一個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
}
可以看到非全局匹配時,返回的數(shù)組與調(diào)用方法 String.match() 返回的數(shù)組是相同的:返回的結(jié)果依次是:匹配到的字符串,該字符串在輸入源中所在的index,輸入源;
此外match1和match2的結(jié)果是相同的,而寫兩個match是為了和下面的全局匹配做比較的。
4.6.2 全局匹配
在全局匹配下,exec() 的行為就稍微復雜一些。每次執(zhí)行exec()以后,RegExpObject的lastIndex屬性會指向此次匹配的字符串的最后一個字符所在的角標,在下次匹配時會在 RegExpObject 的 lastIndex 屬性指定的字符處開始檢索字符串 string。當 exec() 找到了與表達式相匹配的文本時,在匹配后,它將把 RegExpObject 的 lastIndex 屬性設(shè)置為匹配文本的最后一個字符的下一個位置。這就是說,
可以通過反復調(diào)用 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
}
在一般情況下我們會寫一個循環(huán)來進行全局匹配:
function execGlobalWhile() {
let re = new RegExp('好看|nba','gi');
let testStr = 'nba要比cba好看的多';
let match;
while (match = re.exec(testStr)){
console.log(match);
}
//打印結(jié)果如下:
//[ 'nba', index: 0, input: 'nba要比cba好看的多' ]
//[ '好看', index: 8, input: 'nba要比cba好看的多' ]
}
4.7 例子
4.7.1 查找出現(xiàn)次數(shù)最多的字符
function findMore(){
let str = 'assssjdssskssalsssdkjsssdss';
let arr = str.split(''); //把字符串轉(zhuǎn)換為數(shù)組
str = arr.sort().join(''); //首先進行排序,這樣結(jié)果會把相同的字符放在一起,然后再轉(zhuǎn)換為字符串
//alert(str); // aaddjjkklsssssssssssssssss
let value = '';
let index = 0;
let re = /(\w)\1+/g; //匹配字符,且重復這個字符,重復次數(shù)至少一次。
str.replace(re,function($0,$1){
//alert($0); 代表每次匹配成功的結(jié)果 : 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保存的是出現(xiàn)最多的這個字符
}
});
console.log('最多的字符:'+value+',重復的次數(shù):'+index); // 最多的字符:s,重復的次數(shù):17
}
4.7.2在react native中實現(xiàn)hightlightText
就是類似于百度搜索的關(guān)鍵字高亮顯示:
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,//片段結(jié)束位置
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