RegExp

人海茫茫,找到合适的那一个岂止简单?

Posted by Lorry on June 21, 2018

文章字数:3206, 阅读全文大约需要:9 分钟

前言

使用正则,可以少写很多的判断,使代码更加的优雅,可以从字符串当中拿出任何你需要的字符,然后进行加工,得到你想要的任何结果,听起来是不是很棒?

然而正则的表达式看起来不是那么的浅显易懂,往往通用的东西都会更加的抽象,只有抽象出来,才能普适.

正文

从创建说起 两种创建方式:

  • new RegExp
  • / /, (推荐,除非是需要动态创建)
const dynamicReg = 'some_sort_variable'
const test = new RegExp(dynamicReg, 'ig')

const literal1 = /some_sort_variable/ig
const literal2 = /some_sort_variable/ig

console.log(literal1.toString() === test.toString()) // true
console.log(literal1 === literal2) // false,所有的正则都是新的对象

// 用于动态(运行时)创建
function findClassInElement(className, type) {
  const elems = document.getElementsByClassNames(type);
  const re = new RegExp("(\\s|^)" + className + "(\\s|$)") // <div class='foo bar zoo'></div>
  let result = [];
  for (let elem in elems) {
    if (re.test(elem.className)) {
      result.push(elem)
    }
  }
}

字符集 [ ],表示中括号中的任意一个字符匹配

const test = /[abc]/ // 匹配a或b或c而不是abc
const test2 = /[^abc]/ // 匹配非a非b非c的任意字符

特殊字符

  • ^ 开始符
  • $ 结束符
  • . 匹配任何字符
  • ? 匹配0个或1个,用于非贪婪匹配
    • 匹配一个或多个
    • 匹配0个,1个或多个
  • \ 匹配特殊字符
  • () 分组(?:)或捕获
  • \1,\2 back reference, 获取对应位置的匹配值
    const re = /<(\w+)[^>]*>(.*)?<\/\1>/ // <div></div> 
    

方法

  • test 返回是否满足对应规则
  • match
    • 本地的match,不带/g,返回所有匹配值和捕获值
    • 全局的match,带/g, // 返回所有匹配值(没有捕获值)
      const test_string = "I am Lorry"
      const match1 = test_string.match(/(\w+)\s/) // [ "I ", "I" ]
      const match2 = test_string.match(/(\w+)\s/g) // [ "I ", "am "]
      
  • exec
    • 跟生成器一样,(yield)一个一个的往下匹配
    • 包含匹配的值(result[0]),也包含捕获的值(对应序列) ```js const html = “<div class='test'>Helloworld!</div>” const tag = /<(\/?)(\w+)([^>]?))>/g let match, num = 0; while(match = tag.exec(html) !== null) { num ++ console.log(match.length === 4) // 1 find and 3 captured } console.log(num === 6) // 一共匹配了六次 const pattern = /<(\w+)[^>]?>(.*?)<\/\1>/g let match = pattern.exec(‘Hello’) // [“<div class='hello'>Hello</div>”, “div”, “Hello”, index: 0, input: “<div class='hello'>Hello</div>”, groups: undefined]

// 还可以在replace中反向引用捕获值 ‘Hello‘.replace(pattern,”标签内容为:$3”) // 标签内容为: Hello


## ? 的用法

### (?:) 匹配不捕获
### (?=) 前置断言
### (?|) 前置否定断言
```js
/(\w+)\s(?:\d+)%/.exec('process 100%') // 匹配不捕获 ["process 100%", "process", index: 0, input: "process 100%", groups: undefined]
/\d+(?=%)/.exec('100%') // 匹配且捕获 ["100", index: 0, input: "100%", groups: undefined]
/\d+(?!%)/.exec('100/100') // 匹配且捕获["100", index: 0, input: "100/100", groups: undefined]

replace的使用,在结合函数可以很方便的对字符串进行替换和修改

'ABCDefg'.replace(/[A-Z]/g, "X") // "XXXXefg"

'i-am-lorry'.replace(/-(\w)/g, (all,letter) => letter.toUpperCase()) // "iAmLorry"

挑战任务: 将foo=1&foo=2&foo=3&bar=4&bar=5 替换成 foo=1,2,3&bar=4,5

let compress = (resource) => {
  const keys = {};
  const pattern = /(\w+)\=(\d+)/g;
  let match;
  while((match = pattern.exec(resource)) !== null) {
    if (!keys[match[1]]) {
      keys[match[1]] = match[2]
    } else {
      keys[match[1]] += `,${match[2]}`
    }
  }
  let res = Object.keys(keys).map(key => key + '=' + keys[key])
  return(res.join('&'));
}
compress('foo=1&foo=2&foo=3&bar=4&bar=5') // "foo=1,2,3&bar=4,5"

学会匹配,可以在茫茫信息中找到自己需要的一部分.如果匹配规则不正确,会导致错误的结果.是不是很像找另一半呢?:-)