字符串压缩:使用正则表达式匹配相同连续字符

  今天遇到个问题,需求是字符串压缩:给定输入为英文字母组成的字符串,对字符串进行压缩,'abbbcc'压缩为‘ab3c2’,即统计连续相同字符个数,将字符连续出现2次及以上的子串压缩为“字母+出现次数”的形式。

  这个问题的解法很简单,很容易想到遍历字符串来统计的方式,不过这个方法弊端是代码要写好多行。正则如此强大,可以用正则表达式的捕获括号来实现,MDN中对正则表达式捕获括号的描述如下:

(x)

像下面的例子展示的那样,它会匹配 'x' 并且记住匹配项。其中括号被称为捕获括号

模式 /(foo) (bar) \1 \2/ 中的 '(foo)' 和 '(bar)' 匹配并记住字符串 "foo bar foo bar" 中前两个单词。模式中的 \1 和 \2 表示第一个和第二个被捕获括号匹配的子字符串,即 foo 和 bar,匹配了原字符串中的后两个单词。注意 \1\2、...、\n 是用在正则表达式的匹配环节,详情可以参阅后文的 \n 条目。而在正则表达式的替换环节,则要使用像 $1$2、...、$n 这样的语法,例如,'bar foo'.replace(/(...) (...)/, '$2 $1')$& 表示整个用于匹配的原字符串。

  不难写出,匹配连续相同字符的正则表达式:

/([a-zA-Z])(\1)+/

  该正则表达式使用了"\1"这样的特殊匹配符号,它会匹配正则本身第一个括号匹配的内容。对于字符串压缩而言,我们可以用一句代码实现:

function shrinkString (sText) {
  return sText.replace(/([a-zA-Z])(\1)+/g, (m, p1) => `${p1}${m.length}`)
}

console.log(shrinkString('aaaaaa')) // a6
console.log(shrinkString('aabbccccaaaa')) // a2b2c4a4
console.log(shrinkString('aabccddddd')) // a2bc2d5

  相比遍历字符串的方法的多行代码,运用正则和replace函数的解法简洁太多了。如果想了解更多关于replace函数的用法,可以查看之前的文章:字符串替换