记一次正则表达式问题

    本人前端小白一枚,写文章只是为了记录本身学习过程当中的疑问,大佬可直接忽略。 最近在leetcode刷一些简单的算法题,今天遇到一道字符串翻转相关的题目,题目为:

反转字符串中的元音字母

编写一个函数,以字符串做为输入,反转该字符串中的元音字母。javascript

 示例 1: 输入: "hello" 输出: "holle" 前端

示例 2: 输入: "leetcode" 输出: "leotcede" java

说明: 元音字母不包含字母"y"。 正则表达式

 个人思路是先把字符串中的元音字母找出来,而后翻转插入一个新的字符串中。
算法

第一步:找出元音字母

对于给定字符串s,利用正则表达式筛选出元音字母,express

写出正则表达式api

var reg = /['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']/数组

使用上述正则,利用s.match(reg)去匹配,发现每次只能匹配一个,且',也会被匹配上浏览器

修正: var reg = /aeiou/ig函数

s.match(reg)会返回一个匹配结果的数组,示例:

'leetcode'.match(reg) // ['e', 'e', 'o', 'e']

第二步:依次检测字符串的元素是否匹配正则,匹配则用第一步中的数组的逆序去替换,代码以下:

var reg = /[aeiou]/ig
var arr = s.match(reg)
if(!arr) return s;  // 结果为null,则无元音字母
var res = '' // 结果字符串
var index = arr.length - 1 // 元音数组索引,倒序省去reverse操做
while(i < s.length) {
  if(reg.test(s[i])) { // 若是是元音字母
    res += arr[index] // 替换
    index += 1
  } else {
    res += s[i]
  }
    i += 1;
}

复制代码

代码看上去没什么问题,可是在浏览器中运行却怎么都不成功


如上图,指望的结果应该是'leotcede'....................

       反复看了一个多小时,最后发现是reg.test() 的问题,这个api有点坑爹,当reg中的检索是全局检索时,即加了g修饰符,test()若是连续使用结果会不一样,举个栗子:


如上图所示,没有全局修饰符和加上全局修饰符时检索结果彻底不一样。

经过查阅MDN:

若是正则表达式设置了全局标志, test() 的执行会改变正则表达式 lastIndex属性。连续的执行 test()方法,后续的执行将会从 lastIndex 处开始匹配字符串,( exec() 一样改变正则自己的 lastIndex属性值).

原来是lastIndex搞得鬼,由于使用时我都是对单个字符去匹配,因此若是匹配到了的时候,lastIndex就会变为1,下一个若是出现连续的匹配,就会没法匹配成功。

解决办法

咱们在每一次匹配成功时重置lastIndex就行了,即设置reg.lastIndex = 0

因此最终代码为:

var reverseVowels = function(s) {
    var reg = /[aeiou]/ig
    var arr = s.match(reg)
    if(!arr) return s;
    var res = ''
    var index = arr.length - 1
    var i = 0
    while(i < s.length) {
        if(reg.test(s[i])) {
            res += arr[index]
            reg.lastIndex = 0 // 重置lastIndex
            index -= 1
        } else {
            res += s[i]
        }
        i += 1;
    }
    return res;
};复制代码

但回归开头,这是算法题,我写出的这个方法并非优质解法,好吧,看了大佬的解法后,能够用双指针来解决这个问题。

思路以下:

题目的要求是翻转字符串中的元音字母,因此咱们只要找出头尾的元音字母依次交换就行了,根据大佬的思路写出以下代码:

var reverseVowels = function(s) {
    var reg = /[aeiou]/i
    var i = 0
    var len = s.length - 1
    while(i < len) {
        if(reg.test(s[i]) && reg.test(s[len])) { // 首尾都为元音,交换
            [s[i], s[len]] = [s[len], s[i]]
            i += 1;
            len -= 1;
        } else if(!reg.test(s[i])) { // 首不是元音,比较下一位
            i += 1;
        } else if(!reg.test(s[len])) { // 尾不是元音,比较上一位
            len -= 1;
        }
    }
    return s;
};复制代码

运行的时候发现s并无被改变,???这是为何,又是一个坑人的问题,明明一切看起来是那么有道理。。百思不得其解,后来发现问题就出在字符串,字符串一旦初始化是没法被修改的,而我却使用了[s[i], s[len]] = [s[len], s[i]] 去试图修改字符串。举个栗子:

var str = 'str'
str[0] = 'a'
str // 'str'

str = 'aaa'
str // 'aaa'复制代码

为何字符串经过下标没法修改,而赋值能够“修改”,上面看起来是赋值修改了字符串,实际上并无被修改,

字符串是基本数据类型, 基本数据类型的值一旦建立,便没法修改

建立字符串的时候,实际上在栈内开辟了一块内存空间来存放该字符串值,内存空间大小在初始化时已经固定了,没法修改。

进行赋值时,实际上开辟了另外一块内存空间来存放要赋值的新值,将变量指向了这个栈空间。

而原来的字符串值内存会被垃圾回收机制回收,由于没有变量指向这个字符串了。


总结

本身的基础仍是太薄弱了啊,看似一道小小的算法题,牵扯出这么多小的知识点,都是本身不懂了,慢慢加油吧。~~~

相关文章
相关标签/搜索