用js实现英文字母大小写的切换

559 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

虽然写的都是很基础的东西,但我在尽自己最大的努力去做,去记录。到现在是第16天了,好几次想过今天少写一次吧,少写一次吧,但转念一想,今天放弃了,少写一次,明天我是不是又会用相同的理由少写一次?我被困住了,真的被困住了吗?不,我相信这只是黎明前最后的黑暗。

用js实现英文字母大小写的切换,也就是将字符串中的大写字母变成小写,小写字母变成大小。
示例:'123aBc' => '123AbC'

分析题目

最开始看到题目的时候我竟然想过要for循环并且一次判断字符串中每个字符是a-z中哪一个,或者是A-Z中的哪一个,但是转年一想,如果这样写,那要写多少个if判断呀?

再仔细想想自己的思路,看到a-z和A-Z就想到了思路一,利用正则表达式。但是正则似乎时间复杂度不好判定,而且比较消耗性能,那是不是有其他的方案呢?

既然正则可以,那么利用数组是不是也可以呢?分别建立两个数组存储所有的小写和大写英文字母,判断数组中是否存在该字符。这应该也是一种思路,但相对而言数组的操作成本较高,是否存在其他方案呢?

这个时候突然想起enter回车键在ASCII中是有特定的编码的,那么字母肯定也会存在,利用charCodeAt() 是不是也可以呢?

2.jpeg 通过上方的图片可以看到A-Z对应的ASCII编码中的十进制的数字为65-90,a-z对应的ASCII编码中的十进制的数字为97-122.

下面对三种思路进行验证。

思路一:利用正则

//利用正则
function switchLLetterCase1(s: string): string{
  let res = '';

  const reg1 = /[a-z]/;
  const reg2 = /[A-Z]/;

  for(let i = 0; i < s.length; i++){
    const newS = s[i];
    if(reg1.test(newS)){
      res += newS.toUpperCase()
    }else if(reg2.test(newS)){
      res += newS.toLowerCase()
    }else{
      res += newS
    }
  }

  return res;
}

//功能测试
const testStr = '123AbCdEf'
const newStr1 = switchLLetterCase1(testStr);
console.log(newStr1)//123aBcDeF

思路二: 利用数组

//利用数组
function switchLLetterCase2(s: string): string{
  let res = '';
  
  let lowerArr = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
  let upperArr = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];

  for(let i = 0; i < s.length; i++){
    const newS = s[i];
    if(lowerArr.indexOf(newS) > -1 ){
      res += newS.toUpperCase()
    }else if(upperArr.indexOf(newS) > -1){
      res += newS.toLowerCase()
    }else{
      res += newS
    }
  }

  return res;
}
//功能测试
const newStr2 = switchLLetterCase2(testStr);
console.log(newStr2)//123aBcDeF

思路三: 利用ASCII

//利用ASCII
function switchLLetterCase3(s: string): string{
  let res = '';
  
  for(let i = 0; i < s.length; i++){
    const newS = s[i];
    if(newS.charCodeAt(0) > 96 &&  newS.charCodeAt(0) < 123){
      res += newS.toUpperCase()
    }else if(newS.charCodeAt(0) > 64 &&  newS.charCodeAt(0) < 91){
      res += newS.toLowerCase()
    }else{
      res += newS
    }
  }

  return res;
}
//功能测试
const newStr3 = switchLLetterCase3(testStr);
console.log(newStr3)//123aBcDeF

通过上面的代码,我们可以看出,三种方案都能够实现题目中的要求,那么这三种方案究竟谁的性能会更好呢?

性能分析

三种思路都用到了for循环,其时间复杂度都不会低于O(n),思路一是用了正则,而且是极简单的正则,查找每个字符是否符合正则;思路二利用了数组,使用了indexOf方法,也是查找该数组中是否存在该字符;思路一和思路二的时间复杂度应该是差不多的;思路三是用了charCodeAt方法,猜测该方法的时间复杂度是较低的。让我们实际测试一下;

//性能测试
const newTestStr = 'abcDeXyHzabcDeXyHzabcDeXyHzabcDeXyHzabcDeXyHzabcDeXyHzabcDeXyHzabcDeXyHzabcDeXyHzabcDeXyHzabcDeXyHz';
console.time('switchLLetterCase1')
for(let i = 0; i < 10 * 10000; i++){
  switchLLetterCase1(newTestStr)
}
console.timeEnd('switchLLetterCase1')//switchLLetterCase1: 573.437255859375 ms

console.time('switchLLetterCase2')
for(let i = 0; i < 10 * 10000; i++){
  switchLLetterCase2(newTestStr)
}
console.timeEnd('switchLLetterCase2')//switchLLetterCase2: 1360.840087890625 ms


console.time('switchLLetterCase3')
for(let i = 0; i < 10 * 10000; i++){
  switchLLetterCase3(newTestStr)
}
console.timeEnd('switchLLetterCase3')//switchLLetterCase3: 290.35791015625 ms

通过上面的时间对比并结合本地多次测试得到相似的结果,我们可以看出思路三运行速度最快,利用数组的运行速度最慢。

思路一使用的是正则,但是这个正则非常的简单,其消耗性能也会相对较低。如果使用的是一个非常复杂的正则,那么它的运行时间还会继续增加。无法判定正则的渐渐复杂度,故综合结果和上方分析,其时间复杂度不会低于O(n)不会高于O(n^2);

思路二操作数组,使用了indexOf方法,其结果相对而言十分慢。其总的时间度达到了O(n^2);

思路三直接操作字符串,其时间复杂度较低,应该是O(n);

总的来说计算机处理数据的速度: 数字 > 字符串 > 数组