把字符串按照某几个字符切割成数组(从字符串中获取高亮文字)
我们在工作中,经常会遇到把字符串切割成数组的情况,官方也为我们提供了 stringObject.split(separator,howmany) 方法,实例:const str = '开心哈哈哈哈,悲伤哈哈哈,快乐哈哈哈,是你,开始,开心,悲伤'console.log(str.split(','))// 结果// ['开心哈哈哈哈', '悲伤哈哈哈', '快乐哈哈哈', '是你', '开始', '
我们在工作中,经常会遇到把字符串切割成数组的情况,官方也为我们提供了 stringObject.split(separator,howmany) 方法,实例:
const str = '开心哈哈哈哈,悲伤哈哈哈,快乐哈哈哈,是你,开始,开心,悲伤'
console.log(str.split(','))
// 结果
// ['开心哈哈哈哈', '悲伤哈哈哈', '快乐哈哈哈', '是你', '开始', '开心', '悲伤']
但它只能以 某一个字符 进行分割,并且分割完之后,该字符( split(‘开心’) 里的‘开心’ )会被 的 ‘,’ 替换掉,不能保留原始的 字符串。
现在,我们有这样一个需求,把 ‘开心哈哈哈哈,悲伤哈哈哈,快乐哈哈哈,是你,开始,开心,悲伤’ 这个字符串,按照 ['‘开心’, ‘悲伤’] 这两个字符进行切分,并且得到的数组能够完全保留原始字符串
// 输入
const str = '开心哈哈哈哈,悲伤哈哈哈,快乐哈哈哈,是你,开始,开心,悲伤'
// 处理
const result = splitFun(str)
// 输出
console.log(result)
['开心', '哈哈哈哈,', '悲伤', '哈哈哈,快乐哈哈哈,是你,开始,', '开心', ',', '悲伤']
//最终我们再把 输出的数组 渲染到页面上,能够得到 与原始字符串 完全相同的字符串
// react:
(result || []).map(item => <span>{item}</span>)
// vue:
<span v-for"item in result" :key="item">{{item}}</span>
// 开心哈哈哈哈,悲伤哈哈哈,快乐哈哈哈,是你,开始,开心,悲伤
思路梳理:
1、 实现 字符串分割为数组 有很多方式:split, slice,正则表达式…等等方法,最简单的还是采用 split 。
2、 虽然 split 一次只能以一个字符进行分割,但是我们通过 轮询(for循环)的方式,多执行几次,应该是可以达到效果:当我们 第一次把一个字符串 按照第一个字符 分割成为数组之后,还需要对数组里面的 每一项 按照第二个字符 进行分割, 以此类推 可以实现按照多个字符串进行分割。
3、 split 以某个字符 切割完之后,这个字符就被替换为 ‘,’ 了,要想保留原始字符,必须在每次 split 之后,将这个字符插入进去。
第一步:轮询 分割字符 数组
// 为什么以数组的形式存放 该字符串:当我们 第一次把一个字符串 按照第一个字符 分割成为数组之后,
// 还需要对数组里面的 每一项 按照第二个字符 进行分割,这是一个轮询的过程,
// 所以,一开始我们就以一个数组的形式去存放初始数组。
let array = ['开心哈哈哈哈,悲伤哈哈哈,快乐哈哈哈,是你,开始,开心,悲伤']
const labels = ['开心', '悲伤']
for(let i = 0; i < labels.length; i++) {
// 分割字符串操作
const twoArray = splitFunc(array, labels[i])
}
第二步:分割字符
const splitFunc = (array, label) => {
// 定义 一个数组 去存放这一轮 最终被分割 好的数组
const outArray = []
// 循环 需要被分割的 数组字符串
for(let i = 0; i < array.length; i++) {
// 定义 一个数组 去存放 当前项 最终被分割 好的数组
let newArr = []
// 把 当前项 的字符串 按照 传进来 字符进行分割
const splitArr = array[i].split(label)
// 得到分割好的数组后,将被 替换为 ‘,’ 的 label 追加进数组的相应位置
// 例如: ‘开心哈哈哈哈,悲伤哈哈哈,快乐哈哈哈,是你,开始,开心,悲伤’, 以 ‘开心’ 分割
// 被分割为 ["", "哈哈哈哈,悲伤哈哈哈,快乐哈哈哈,是你,开始,", ",悲伤"]
// , 每一项的末尾,就应该应该是 开心 二字,最后一项的末尾除外
// 遍历被分割好的数组
for(let j = 0; j < splitArr.length; j++) {
// 向被分割好的数组里 追加 label 字符
newArr.push(splitArr[j])
// 数组的末尾无需 追加
if (j < splitArr.length -1) {
newArr.push(label)
}
}
// 把当前轮得到 的数组 推到 outArray 里去
outArray.push(newArr)
}
// 返回 outArray ,注意 outArray 是一个二维数组
return outArray
}
第三步:轮询调用 splitFunc 函数
for(let i = 0; i < labels.length; i++) {
// 接收 当前轮 返回的 二维数组
const twoArray = splitFunc(array, labels[i])
// 将二维数组平铺成为 一维数组
const oneArray = twoArray.reduce(function (a, b) { return a.concat(b)} )
// 过滤掉一维数组里的空字符串,并把它重新赋值给 array,
// 下一轮循环将 切割 上一轮 已经被分割好的 数组
array = oneArray.filter(item => item !== "")
}
// 最终循环结束的 array 就是被彻底分割好的数组
最终代码:
const splitFunc = (array, label) => {
const outArray = []
for(let i = 0; i < array.length; i++) {
let newArr = []
const splitArr = array[i].split(label)
console.log('splitArr', splitArr)
for(let j = 0; j < splitArr.length; j++) {
newArr.push(splitArr[j])
if (j < splitArr.length -1) {
newArr.push(label)
}
}
outArray.push(newArr)
}
return outArray
}
let array = ['开心哈哈哈哈,悲伤哈哈哈,快乐哈哈哈,是你,开始,开心,悲伤']
const labels = ['开心', '悲伤']
for(let i = 0; i < labels.length; i++) {
const twoArray = splitFunc(array, labels[i])
const oneArray = twoArray.reduce(function (a, b) { return a.concat(b)} )
array = oneArray.filter(item => item !== "")
}
console.log('array', array)
为什么需要如此麻烦的 将一个字符串 分割完成 之后,在组装渲染到页面上?
主要是为了 这些字符里的 关键字符(也就是 需要被分割的字符),在渲染的时候,能够被我们所控制,为他设置CSS样式,追加点击事件等等,达到动态的效果,如果仅仅是一个字符串被渲染到页面上,这些操作我们将无法控制。
如果以上算法逻辑有不足之处,欢迎大家指出教导👏👏。
2025.01.03日更新
今天又遇到类似的需求,换了一种实现方式,用正则匹配。
interface HighlightSegment {
text: string;
highlight: boolean;
}
function processHighlightText(text: string, keywords: string[]): HighlightSegment[] {
// 如果没有关键词,直接返回整个文本作为非高亮片段
if (!keywords.length) {
return [{ text, highlight: false }];
}
// 将关键词按长度降序排序,避免短词先匹配导致的问题
const sortedKeywords = [...keywords].sort((a, b) => b.length - a.length);
// 创建正则表达式
// 步骤1: k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
// 这部分是转义正则表达式中的特殊字符
// 比如如果关键词中包含 '.' '*' '+' 等特殊字符,会在前面加上 '\'
// 步骤2: sortedKeywords.map(...).join('|')
// 将所有关键词用 '|' 连接
// 结果类似:'灵活|高效|美观'
// 步骤3: new RegExp(`(${...})`, 'g')
// 最终生成的正则表达式类似:/(灵活|高效|美观)/g
const regex = new RegExp(`(${sortedKeywords.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|')})`, 'g');
const result: HighlightSegment[] = [];
let lastIndex = 0;
// 使用正则表达式匹配所有关键词
text.replace(regex, (match, _, index) => {
// 添加匹配词之前的非高亮文本
if (index > lastIndex) {
result.push({
text: text.slice(lastIndex, index),
highlight: false
});
}
// 添加高亮关键词
result.push({
text: match,
highlight: true
});
lastIndex = index + match.length;
return match;
});
// 添加最后一个非高亮片段(如果有的话)
if (lastIndex < text.length) {
result.push({
text: text.slice(lastIndex),
highlight: false
});
}
return result;
}
export default processHighlightText
// 测试代码
// const str = '简单灵活,让开发变得更,让产品变得更美观高效';
// const keywords = ['灵活', '高效', '美观'];
// const result = processHighlightText(str, keywords);
// console.log(result);
// 输出:
// [
// {text: '简单', highlight: false},
// {text: '灵活', highlight: true},
// {text: ',让开发变得更,让产品变得更', highlight: false},
// {text: '美观', highlight: true},
// {text: '高效', highlight: true},
]
更多推荐
所有评论(0)