A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 没名字i 于 2019-2-22 09:33 编辑

首先介绍一下业务需求:
在实时输入过程中,&&、||和-三个符号中的任意两个(包括自身重复在内)不能直接或通过空格连在一起,否则只保留第一个。
思路1:穷举这是我第一时间想到的方法,穷举这三个符号任意两个符号的排列组合,然后一一替换。根据排列组合公式可知一共有6种不同的组合方式,需要写6个正则。
这种方法的好处是易于理解,但缺点也显而易见,代码臃肿,难以维护。
思路2:写一个匹配出所有组合的正则,然后进行替换。首先,写出这个正则
let reg = /((&&|\|\||-)\s*){2,}/g
这个正则的意思是,匹配任意这三个符号(&& || -)加零个或多个空格出现两次以上的文本。
有了这个正则,接下来就是如何替换了,首先想到的是正则的反向引用了$1($1的意思是第一个分组的内容,正则中括号()代表分组,即((&&|\|\||-)\s*))
先来分析一下这个正则的匹配过程,我们写个测试案例来演示
'|| -'.replace(/((&&|\|\||-)\s*){2,}/g,"\$1")   // -
匹配过程是这样的:
  • 从左到右遍历这个字符串,找到 "|| "符合第一个分组内容,但不符合{2,}(出现两次以上),  此时$1分组的内容是"|| "
  • 继续遍历,匹配到"-"符合规则,此时$1分组的内容是"-"
  • 这时已满足(&&|\|\||-)\s*)同时出现两次以上的规则,开始替换,将整个字符串替换成$1,即-,所以输出为"-"
那么问题来了,业务的需求是替换成第一个字符,而我们却替换成了最后一个字符。别着急,先喝口水冷静一下。其实我们只要把原字符串翻转一下,再传进来不就符合要求了吗,替换完毕后记得把字符串翻转回去就行了
// 翻转字符串function rever(str) {   return str.split("").reverse().join("")}复制代码完整代码如下:
let str = 'ccc && ||'function rever(str) {  return str.split("").reverse().join("")}let newStr = rever(rever(str).replace(/((&&|\|\||-)\s*){2,}/g,"\$1"))console.log(newStr);
代码写出来了,测试结果也符合预期,那么就大功告成了吗?
看看这段代码的实现原理,是把原字符串翻转,然后进行匹配替换,替换完在把字符串翻转回来。代码执行过程中,是对原字符进行了修改的。如果放到生产环境中,由于用户的输入习惯不同,可能会造成某些不可预期的错误。
另辟蹊径:replace的第二个参数,除了传入字符串,不是还可以传入一个函数吗?我们只要在这个函数中,把符合业务需要的第一个字符找出来,然后return 出去,不就完事了吗?
用这种方式处理,不会污染原字符串,没有副作用。不知道算不算得上最优解呢?
代码很简单,大家看一下应该就明白了:
let str = 'ccc && ||'let newStr = str.replace(/((&&|\|\||-)\s+){2,}/g, function(a){  return a.substr(0, a.indexOf(' ')) + ' ';});console.log(newStr);  // "ccc && "

链接:https://juejin.im/post/5c6cc48ae51d45587b32e78c

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马