Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript正则表达式 #1

Open
lznbuild opened this issue Nov 27, 2019 · 0 comments
Open

JavaScript正则表达式 #1

lznbuild opened this issue Nov 27, 2019 · 0 comments

Comments

@lznbuild
Copy link
Owner

lznbuild commented Nov 27, 2019

创建正则的两种方式

1.创建RegExp对象

// JavaScript中有一个特殊对象,RegExp对象
var reg = new RegExp('a'); 
'12a3'.replace(reg, '&');  // '12&3'

2.创建正则表达式字面量

var reg = /a/;
'12a3'.replace(reg, '&'); // '12&3'

两种创建方式的区别有两点:

1.创建RegExp对象的方法,可以创建动态正则

var str = '2';
var reg = /str/;   // 这里的str只是单纯的字符串'str'
reg.test('123'); // false
reg.test('11str22'); // true


var newReg = new RegExp(str);  // 这里的str是一个变量,也就是字符串2
reg.test('123'); //true
reg.test('11str22') // false

2.创建RegExp对象的方法,需要对特殊字符做转义处理

var reg = new RegExp('\\d'); // \d是正则中的元字符,下面会有详细介绍,表示匹配数字,在这之前要加转义处理
reg.test('jk'); // false
reg.test('12'); // true

var strReg = /\d/; // 直接用\d
strReg.test('1'); // true

search() 和indexOf方法的返回跟判断完全一致,可以写正则,indexOf不可以

字符串对象共有4个方法,可以使用正则表达式:match()、replace()、search()和split(),test()

正则其实只匹配字符和位置,这句话就概括了正则的精髓。

修饰符

g 表示全局匹配

'1232'.replace(/2/, '$'); // '1$32',只匹配第一个,后面即使有字符匹配正则的规则,也不会再替换

'1232'.replace(/2/g, '$'); // '1$3$',所有和正则匹配规则的字符都会被替换

i 表示不区分大小写

'abcABC'.replace(/A/g, '$'); // 'abc$BC'
'abcABC'.replace(/A/ig, '$'); // '$bc$BC'

m 表示多行匹配

// m修饰符的使用,多行匹配
var result = "I\nlove\njavascript".replace(/^|$/gm, '#'); // 每一行都匹配一下此正则
console.log(result); 
// #I#
// #love#
// #javascript#

这里只列举常用的,更多请查询MDN

特殊字符

普通的特殊字符

字符 描述
^ 匹配字符串的开头
$ 匹配字符串的结尾
. 匹配几乎任意字符。换行符、回车符、行分隔符和段分隔符除外
\d 匹配数字
\D 匹配非数字
\b 匹配字符边界
\B 匹配非字符边界
\s 匹配空白字符, \t,\v,\n,\r,\f都是空白符
\S 匹配非空白字符
\w 匹配字母数字或下划线
\W 匹配非字母数字或下划线

有些不好理解,所以配合案例

  • ^,$边界
'1232'.replace(/^2$/, '&'); // '1232'因为此正则表示只匹配一个字符2  
'2'.replace(/^2$/, '&'); // &,只有字符2
  • \b 匹配字符边界,具体就是 \w 与 \W 之间的位置,也包括 \w 与 ^ 之间的位置,和 \w 与 $ 之间的位置,注意,匹配的是位置!
'moon'.replace(/\bm/, '&'); // '&oon',因为m字符前面的位置,符合匹配规则\w 与 ^ 之间的位置。

"[JS] Lesson_01.mp4".replace(/\b/g, '#'); // "[#JS#] #Lesson_01#.#mp4#",这个案例很能说明\b的匹配规则了

而\B呢,当然就和\b相反了,具体就是\w 与 \w、 \W 与 \W、^ 与 \W,\W 与 $ 之间的位置。

"[JS] Lesson_01.mp4".replace(/\B/g, '#'); // => "#[J#S]# L#e#s#s#o#n#_#0#1.m#p#4
  • (?=l), 表示 "l" 字符前面的位置
var result = "hello".replace(/(?=l)/g, '#');
console.log(result);
// => "he#l#lo"
  • (?!p), 就是 (?=p) 的反面意思
var result = "hello".replace(/(?!l)/g, '#');
console.log(result);
// => "#h#ell#o#"
  • () 捕获括号
// \1 相当于第一个括号里的内容,也就是foo,\2同理
/(foo) (bar) \1 \2/.test('foo bar foo bar'); // true

分组后面有量词的话,分组最终捕获到的数据是最后一次的匹配。

var regex = /(\d)+ \1/;
console.log( regex.test("12345 1") ); // => false
console.log( regex.test("12345 5") ); // => true

如果只想要括号最原始的功能,但不会引用它,即,既不在 API 里引用,也不在正则里反向引用。 此时可以使用非捕获括号 (?:p)

var regex = /(?:ab)+/g;
var string = "ababa abbb ababab";
console.log( string.match(regex) ); // => ["abab", "ab", "ababab"]

写到\10分组的时候,想写一个、\1后跟字符0怎么写?

\10 分组
展示为\1 和0的写法 \1(?:0)

// $1,$2是在正则以外的写法,必须调用跟正则有关的方法后才能使用
var re = /(\w+)\s(\w+)/;
console.log(re.$1)//报错
var str = "John Smith";
var newstr = str.replace(re, "$2, $1"); // 调用replace方法用到了re正则,可以使用$1,$2
console.log(newstr);    // Smith, John

方法调用后的特殊字符

// $& 匹配到的子串文本
// $` 匹配到的子串的左边文本
// $' 匹配到的子串的右边文本,包含匹配项
// $$ 美元符号
var result = "2+3=5".replace(/=/, "$&$`$&$'$&");
console.log(result);
// => "2+3=2+3=5=5"
  • x(?=y) 先行断言
// 匹配字符j,后面紧跟s字符的j,只匹配j
'jsji'.replace(/j(?=s)/,'@'); // @sji
  • x(?!y) 正向否定查找(相当于先行断言的取反)
// 匹配j,后面不跟s字符的j,只匹配j
'jsjije'.replace(/j(?!s)/g, '@'); // js@i@e
  • (?<=y)x 后行断言
// 匹配字符s,前面紧跟j字符的s,只匹配s
'jsis'.replace(/(?<=j)s/,'@'); // j@is
  • (?<!y)x 反向否定查找(相当于后行断言的取反)
// 匹配字符s,前面不跟j字符的s,只匹配s
'jsisys'.replace(/(?<!j)s/g,'@'); // jsi@y@
  • x|y | 表示'或'
/1|2/.test('781'); // true
/1|2/.test('782'); // true
  • [a-z] 字符集
/[a-z]/.test('aUI'); // true只要字符串中的某一项是a,b,c...z中的一项,此正则就匹配,常用的字符集[a-z],[A-Z],[0-9]
  • [^a] 取反
/[^8]/.test('8'); // false,匹配项只要不是8,就返回true

这里只列举常用的,更多请查询MDN

匹配位置的总结

    ^ & \b \B (?=p)  (?!p)

描述数量的特殊字符

描述数量的特殊字符前面必须跟有效的字符(没字符的话描述谁的数量呢)

字符 描述
+ 表示字符出现一次或多次,等价于{1,}
* 表示字符出现0次或多次,等价于{0,}
? 表示字符出现0次或1次,等价于{0,1}
{n} 表示字符出现2次
{2,5} 表示字符出现2-5次
{2,} 表示字符出现2次或多次(大于2)
// 这里只放一个案例,其他数量字符使用同理
'142344546'.replace(/4{2}/, '$'); // 1423$546

?不光表示数量特殊字符,还可以表示惰性匹配,跟在数量特殊字符的后面。

// /\d{2,5}?/ 表示,虽然 2 到 5 次都行,当 2 个就够的时候,就不再往下尝试了。
var regex = /\d{2,5}?/g;
var string = "123 1234 12345 123456";
console.log( string.match(regex) ); // => ["12", "12", "34", "12", "34", "12", "34", "56"]

// 实际案例,想匹配id="xxxxx"这段字符
var regex = /id=".*"/ 
var string = '<div id="container" class="main">'; 
console.log(string.match(regex)[0]); // => id="container" class="main"
/id=".*?"/               //id="container" 涉及到回溯,最好的写法是 /id="[^"]*"/

常用方法(只列举常用的)

字符串对象共有4个方法,可以使用正则表达式:match()、replace()、search()和split()。

// replace以上实例用作多次,不再赘述。

// match  返回所有匹配字符组成的数组,不加修饰符g,返回类数组
'2m9jklj7jkl'.match(/\d/g) // ["2", "8", "9", "7"]  

// search() 返回第一个匹配项的下标,即使加修饰符g,也只匹配第一个下标,search方法就是这样定义的
'sdf7jkl87df0'.search(/\d/) // 3

// split 按匹配项进行字符串分割,返回分割后的所有项组成的数组  
'1jk23'.split(/\d/) // ["", "jk", "", ""]

test()方法用于正则表达式,有匹配项就返回true

// 以上实例用作多次,不再赘述。

关于正则使用的案例

数字的千位分隔符表示法(比如把 "12345678",变成 "12,345,678")

var regex = /(?!^)(?=(\d{3})+$)/g;
var result = "12345678".replace(regex, ',')
console.log(result); // => "12,345,678"

result = "123456789".replace(regex, ',');
console.log(result);
// => "123,456,789"

匹配标签

var regex = /<([^>]+)>[\d\D]*<\/\1>/;
var string1 = "<title>regular expression</title>";
var string2 = "<p>laoyao bye bye</p>";
var string3 = "<title>wrong!</p>";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // false

实体字符转换为等值的HTML。

function unescapeHTML (str) {    
    var htmlEntities = {       
        nbsp: ' ',       
        lt: '<',       
        gt: '>',       
        quot: '"',       
        amp: '&',       
        apos: '\''     
    };                
    return str.replace(/\&([^;]+);/g, function (match, key) {    
        if (key in htmlEntities) {            
            return htmlEntities[key];        
        }        
        return match;    
    });
}
console.log( unescapeHTML('&lt;div&gt;Blah blah blah&lt;/div&gt;') ); // => "<div>Blah blah blah</div>"

将HTML特殊字符转换成等值的实体

function escapeHTML (str) {    
    var escapeChars = {       
        '<' : 'lt',       
        '>' : 'gt',       
        '"' : 'quot',       
        '&' : 'amp',       
        '\'' : '#39'     
        
    };    
    return str.replace(new RegExp('[' + Object.keys(escapeChars).join('') +']', 'g'), function (match) {                        
        return '&' + escapeChars[match] + ';';    
    });
}
console.log( escapeHTML('<div>Blah blah blah</div>') ); // => "&lt;div&gt;Blah blah blah&lt;/div&gt";

将单词的首字符转换为大写

function titleize (str) {    
    return str.toLowerCase().replace(/(?:^|\s)\w/g, function (c) {        
        return c.toUpperCase();    
    });
}
console.log( titleize('my name is epeli') ); // => "My Name Is Epeli"

驼峰化

function camelize (str) {    
    return str.replace(/[-_\s]+(.)?/g, function (match, c) {        
        return c ? c.toUpperCase() : '';    
    });
}
console.log( camelize('-moz-transform') ); // => "MozTransform"

中划线化

function dasherize (str) {    
    return str.replace(/([A-Z])/g, '-$1').replace(/[-_\s]+/g, '-').toLowerCase();
}
console.log( dasherize('MozTransform') ); // => "-moz-transform"

实现模板引擎

function render(template, data) {
  const reg = /\{\{(\w+)\}\}/; // 模板字符串正则
  if (reg.test(template)) { // 判断模板里是否有模板字符串
    const name = reg.exec(template)[1]; // 查找当前模板里第一个模板字符串的字段
    template = template.replace(reg, data[name]); // 将第一个模板字符串渲染
    return render(template, data); // 递归的渲染并返回渲染后的结构
  }
  return template; // 如果模板没有模板字符串直接返回
}
let template = '我是{{name}},年龄{{age}},性别{{sex}}';
let data = {
  name: '姓名',
  age: 18
}
render(template, data); // 我是姓名,年龄18,性别undefined

《JavaScript正则迷你书》链接
https://pan.baidu.com/s/1J_sVhmgZ94qXTr5c4hAItQ
4ki3

@lznbuild lznbuild changed the title 的萨芬啊手动阀就ij JavaScript正则表达式 Nov 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant