正则表达式简介

正则表达式是一种描述模式的方法,用来描述“部分字符串的查找问题”。每个正则表达式表示的都是一个字符串的集合。

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
            });
        }
    }

展示效果如下:

image.png

完整代码请看github:https://github.com/wangzhen90/react-native-highlight-text

参考:https://www.cnblogs.com/moqing/archive/2016/07/13/5665126.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容