美文网首页
看完必会的正则表达式和递归

看完必会的正则表达式和递归

作者: 小王子__ | 来源:发表于2021-12-11 02:00 被阅读0次

1,递归

递归函数:一个函数在内部可以调用其本身

function func() {
  func()
}
func()
image
递归容易发生栈溢出错误(stack overflow),以上是一个典型的栈溢出,所以我们必须加退出条件 return
var num = 1
function func() {
  console.log(`打印${num}次`)
  if (num === 10) {
    return
  }
  num++
  func()
}
func()

递归实例:

  • 1, 利用递归求 1 ~ n 的阶乘
function func(n) {
  // 1 * 2 * 3 * ...n
  if (n === 1) return 1;
  return n * func(n - 1)
}
func(5)  // 120
  • 2, // 斐波那契数列(兔子序列):前两项的和等于第三项的值 表现: 1、1、2、3、5、8、13、21、34...
// 用户输入一个数字 n, 求出这个数字对应的兔子序列值
function fb (n) {
  if (n === 1 || n === 2) return 1
  return fb(n - 1) + fb(n - 2)
}
fb(9)  // 34
  • 3, 根据 id 返回对应的数据对象
const arr = [
  {
    id: 1,
    name: 'Jerry',
    friends: [
      {
        id: 11,
        name: 'Lise'
      },
      {
        id: 12,
        name: 'Tom'
      }
    ]
  },
  {
    id: 2,
    name: 'xiaowang'
  }
];

const arr = [
  {
    id: 1,
    name: 'Jerry',
    friends: [
      {
        id: 11,
        name: 'Lise'
      },
      {
        id: 12,
        name: 'Tom'
      }
    ]
  },
  {
    id: 2,
    name: 'xiaowang'
  }
];
function getId(data, id) {
  var o = {}
  data.forEach(function (value) {
    if (value.id === id) {
      o = value
      return value
    } else if (value.friends?.length > 0) {
      o = getId(value.friends, id)
    }
  })
  return o
}
console.log(getId(arr, 12)) // {id: 12, name: 'Tom'}
或者
function getId(arr, id) {
  let queue = [];
  arr.forEach(item => {
    queue.push(item)
  })
  while(queue.length > 0) {
    const value = queue.shift();
    if(value.id === id) return value;
    if(value.friends && value.friends.length > 0) {
      value.friends.forEach(item => queue.push(item));
    }
  }
}
console.log(getId(arr, 12)) // {id: 12, name: 'Tom'}

2,深浅拷贝

  • 1,浅拷贝只是拷贝一层,更深层对象级别的只拷贝引用
  • 2,深拷贝拷贝多层,每一级别的数据都会拷贝

浅拷贝

const obj = {
  name: 'Jerry',
  age: 18,
  friends: {
    name: 'Lise'
  }
};
var o = {}

for (var i in obj) { // i 属性名,obj[i] 属性值
  o[i] = obj[i]
}
或
Object.assign(o, obj)  // ES6新增的方法可以实现浅拷贝

o.friends.name = 'Tom'
console.log(o) 
console.log(obj)
image
image

深拷贝

const obj = {
  name: 'Jerry',
  age: 18,
  friends: {
    name: 'Lise'
  },
  colors: ['red', 'green', 'blue']
};
var o = {}
// 封装函数
function deepCopy(newObj, oldObj) {
  for(var i in oldObj) {
    // 判断属性值是简单数据类型还是复杂数据类型
      // 1,获取属性值 oldObj[i]
      const item = oldObj[i]
      // 2, 判断这个值是否是数组
      if (item instanceof Array) {
        newObj[i] = []
        deepCopy(newObj[i], item)
      } else if (item instanceof Object) {
        // 3,判断这个值是否是对象
        newObj[i] = {}
        deepCopy(newObj[i], item)
      } else {
        // 4,属于基本数据类型
        newObj[i] = item
      }
  }
}
deepCopy(o, obj)
image

3,正则表达式

正则表达式:用于匹配字符串中字符组合的模式,在JS中,正则表达式也是对象。

通常用于检测、替换那些符合某个模式的文本,例如验证表单:用户名表单只能输入英文字母、数字或者下划线。

还常用于过滤页面内容中的一些敏感词(替换),或者从字符串中获取我们想要的特定部分等

3.1,创建正则表达式

  • 创建正则表达式:
    • 1, 利用 RegExp 对象来创建
    const rg = new RegExp(/表达式/)
    
    • 2, 利用字面量创建正则表达式
    const rg = /表达式/
    
  • 测试正则表达式 test
    test()正则对象的方法,用于检测字符串是否符合该规范,该对象会返回 truefalse
const rg =  /123/
rg.test(123) // true
rg.test(456) // false
  • 正则的组成
    一个正则可以由简单的字符组成,比如/abc/,也可以是简单和特殊字符的组合,比如/ab*c/,特殊字符有叫元字符,在正则中具有特殊意义的专用符号,比如: ^、$、+等

特殊符号可以参考:MDN正则表达式

正则测试工具:https://tool.oschina.net/regex

3.2,正则中的特殊字符

  • 3.2.1 边界符
    正则中的边界符(位置符)用来提示字符串所处的位置,主要有两个:^、$
    • ^ 匹配行首的文本
    • $ 匹配行尾的文本
const rg =  /abc/ // /abc/表示只要包含有abc这个字符串返回的都是true
console.log(rg.test('abc')) // true 
console.log(rg.test('abcd')) // true
console.log(rg.test('aabc')) // true

const reg = /^abc/ // 表示必须以abc开头的
console.log(reg.test('abc')) // true 
console.log(reg.test('abcd')) // true
console.log(reg.test('aabc')) // false
console.log(reg.test('abdc')) // false

const reg1 = /^abc$/ // 精确匹配
console.log(reg1.test('abc')) // true 
console.log(reg1.test('abcd')) // false
console.log(reg1.test('aabc')) // false
  • 3.2.2 字符类:[]
    表示有一系列字符可供选择,只要匹配其中一个就可以了
const reg = /[abc]/  // 表示只要包含有a 或 有b 或 有c,都返回true
console.log(reg.test('alia')) // true

const reg1 = /^[abc]$/  // 表示只有是a 或 b 或 c,才返回true
console.log(reg1.test('alia')) // false
console.log(reg1.test('a')) // true
console.log(reg1.test('b')) // true
console.log(reg1.test('bc')) // false
console.log(reg1.test('c')) // true
console.log(reg1.test('cc')) // false
console.log(reg1.test('abc')) // false
  • 3.3.3 [-]方括号内 范围符 -
const reg = /^[a-z]$/ // 26个英文字母任何一个字母返回true
console.log(reg.test('alia')) // false
console.log(reg.test('a')) // true
console.log(reg.test('A')) // false
  • 3.3.4 字符组合
// 字符组合
const reg1 = /^[a-zA-Z]$/ // // 26个英文字母(大小写都可以) 任何 一个字母返回true
console.log(reg1.test('alia')) // false
console.log(reg1.test('a')) // true
console.log(reg1.test('A')) // true

// 比如:reg = /^[a-zA-Z0-9_-]$/
  • 3.4.5 []方括号内 表示取反
const reg = /^[^abc]$/
console.log(reg.test('a'))  // false
  • 3.4.6 量词符

用来设定某个模式出现的次数

量词 说明
* 重复0次或更多次
+ 重复1次或更多次
? 重复0次或1次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
// *  >= 0
const reg = /^a*$/
console.log(reg.test('')) // true
console.log(reg.test('a')) // true
console.log(reg.test('b')) // false
console.log(reg.test('aaa')) // true

// + >= 1
const reg1 = /^a+$/
console.log(reg1.test('')) // false
console.log(reg1.test('a')) // true
console.log(reg1.test('b')) // false
console.log(reg1.test('aaa')) // true

// ? 1 || 0
const reg2 = /^a?$/
console.log(reg2.test('')) // true
console.log(reg2.test('a')) // true
console.log(reg2.test('b')) // false
console.log(reg2.test('aaa')) // false

// {3} 重复3次
const reg3 = /^a{3}$/
console.log(reg3.test('')) // false
console.log(reg3.test('a')) // false
console.log(reg3.test('b')) // false
console.log(reg3.test('aaa')) // true

// {3,} >= 3
const reg4 = /^a{3,}$/
console.log(reg4.test('')) // false
console.log(reg4.test('a')) // false
console.log(reg4.test('b')) // false
console.log(reg4.test('aaa')) // true
console.log(reg4.test('aaaaa')) // true
console.log(reg4.test('aaabc')) // false
console.log('-----------')
// {3,8}  >= 3 && <= 8
const reg5 = /^a{3,8}$/
console.log(reg5.test('')) // false
console.log(reg5.test('a')) // false
console.log(reg5.test('b')) // false
console.log(reg5.test('aaa')) // true
console.log(reg5.test('aaaaa')) // true
console.log(reg5.test('aaabc')) // false
console.log(reg5.test('aaaaaaaa')) // true
  • 3.4.7
// 量词是设定某个模式出现的次数
var reg = /^[a-zA-Z0-9_-]$/ // 这个模式用户只能输入英文字母 数字 下划线 短横线但是有边界符和[] 这就限定了只能多选1
console.log(reg.test('a')) // true
console.log(reg.test('ab')) // false
console.log(reg.test(1)) // true
console.log(reg.test('11')) // false
console.log(reg.test('aa')) // false

4, 正则案例

1, 用户名验证,如果用户名输入合法,提示信息为:用户名合法,颜色改为绿色,如果不合法,则后面提示:用户名不符合规范,改色改为红色

const name = document.querySelector('.name');
const span = document.querySelector('span');
var reg = /^[a-zA-Z0-9_-]{6,16}$/
name.onblur = function () {
  if (reg.test(this.value)) {
    span.className = 'green'
    span.innerHTML = '用户名合法'
  } else {
    span.className = 'red'
    span.innerHTML = '用户名不符合规范'
  }
}

5, 括号总结

  • 1,量词符大括号,表示重复次数
  • 2,字符集合中括号,匹配方括号中的任意字符
  • 3,小括号,表示优先级
// 中括号[],字符集合,匹配方括号中的任意字符
const reg = /^[abc]$/ // a || b || c都可以

// 大括号{},量词符,表示重复次数
const reg1 = /^[abc]{3}$/
console.log(reg1.test('aaa')) // true
console.log(reg1.test('abcabcabc')) // false

const reg2 = /^abc{3}$/  // 它只是让c重复3次 abccc
console.log(reg2.test('aaa')) // false
console.log(reg2.test('abcabcabc')) // false
console.log(reg2.test('bbb')) // false
console.log(reg2.test('ccc')) // false
console.log(reg2.test('abccc')) // true
console.log(reg2.test('aabccc')) // false

// 小括号 表示优先级
const reg3 = /^(abc){3}$/ // 表示让 abc重复3次 
console.log(reg3.test('aaa')) // false
console.log(reg3.test('abcabcabc')) // true
console.log(reg3.test('abccc')) // false

6,可以在线测试自己写的正则对不对(https://c.runoob.com/front-end/854/)

也会有一些常用的正则:


image

7,预定义类

指的是某些常见模式的简写方式

预定义类 说明
\d 匹配0-9之间的任一数字, 相当于[0-9]
\D 匹配所有0-9以外的字符, 相当于[^0-9]
\w 匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_]
\W 除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_]
\s 匹配空格(包括换行符、制表符、空格符),相当于[\t\r\n\v\f]
\S 匹配非空格的字符,相当于[^\t\r\n\v\f]

实例:

//  座机号码验证:全国座机号码,两种格式:010-12345678 或者 0530-1234567
// const reg = /^\d{3}-\d{8}|\d{4}-\d{7}$/  // 正则里的 或 用 | 表示
// 简写
const reg = /^\d{3,4}-\d{7,8}$/
console.log(reg.test('魑魅魍魉')) // false
console.log(reg.test('3829889')) // false
console.log(reg.test('3829-889')) // false
console.log(reg.test('022-31231321')) // true

8, replace 替换

replace()方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则

// 语法
str.replace(/str/, replacement)
// 第一个参数:被替换的字符串 或者 正则
// 第二个参数:替换为的字符串
// 返回值是一个替换完的新字符串
const str = 'JerryLise'
const newStr = str.replace('Jerry', 'xiaowang')
const newStr = str.replace(/Jerry/, 'xiaowang')
console.log(newStr)  // xiaowangLise

实例:

const text = document.querySelector('textarea')
const btn = document.querySelector('button')
const div = document.querySelector('div')
btn.onclick = function () {
    div.innerHTML = text.value.replace(/小猫咪/, '**')
}
image

以上代码replace只能替换第一个满足条件的字符串,后面的就不再替换了,那么我们可以用正则表达式参数

9,正则表达式参数

/表达式/[switch]
// switch也称修饰符,按照什么样的模式来匹配,有三种值:
// 1,g: 全局匹配
// 2,i:忽略大小写
// 3,gi:全局匹配 + 忽略大小写

以上实例:

div.innerHTML = text.value.replace(/小猫咪|超/g, '**')
image

相关文章

  • 看完必会的正则表达式和递归

    1,递归 递归函数:一个函数在内部可以调用其本身 递归容易发生栈溢出错误(stack overflow),以上是一...

  • 一个程序员的自我学习第一天

    《正则表达式必知必会》笔记 第一章:正则表达式入门 1:正则表达式是一些用来匹配和处理文本的字符串。正则...

  • 如何写出高性能的代码

    使用StringBuilder来连接字符串 避免递归(无法避免时,使用尾递归代替头递归) 谨慎使用正则表达式 循环...

  • 书籍归档

    PHP入门到精通(朋友赠送) 正则表达式必知必会(朋友赠送) SQL必知必会(朋友赠送) Docker技术入门与实...

  • 【编译原理】第三章:词法分析

    一、正则表达式(RE) 语言正则表达: 正则表达式可以由较小的正则表达式递归构建。每个正则表达式r定一个语言记作L...

  • 第10课 运算符与函数

    必会单词 regexp 正则表达式 trim 修剪 replace 替换 ceiling 最高限度 year 年 ...

  • 面试必会算法之递归

    递归的基本性质就是函数调用,在处理问题的时候,递归往往是把一个大规模的问题不断地变小然后进行推导的过程。 递归(R...

  • 10分钟搞定正则表达式

    学习资料:《正则表达式必知必会》人民邮电出版社正则表达式测试工具:http://regexr.com/ 1.匹配单...

  • Leetcode.44.Wildcard Matching

    题目 正则表达式匹配, 判断字符串是否符合给定的正则表达式. 思路1 分治. 采用递归的形式, 不断缩短字符串的长...

  • 正则表达式

    正则表达式必知必会pdf版 链接:https://pan.baidu.com/s/1vE5rBUfKzVwsXiI...

网友评论

      本文标题:看完必会的正则表达式和递归

      本文链接:https://www.haomeiwen.com/subject/skzhfrtx.html