我试图使用开始和结束索引在字符串中突出显示子字符串。但我面临的问题,而突出重叠的子字符串。例如
我有一个text
和一个array
用于高亮。
有什么方法可以避免重叠的标签吗?我尝试用regex
匹配子字符串,但无法解决它。
沙箱联系
let tagObject = {
"text": "I am asking a question in stackoverflow",
"tags": [{
start: 0,
end: 1,
value: "I",
tag: "TAG1"
},
{
start: 0,
end: 4,
value: "I am",
tag: "TAG2"
},
{
start: 5,
end: 22,
value: "asking a question",
tag: "TAG3"
},
{
start: 14,
end: 22,
value: "question",
tag: "TAG4"
},
{
start: 14,
end: 25,
value: "question in",
tag: "TAG5"
}
]
}
const color = {
outer: "color: #1d39c4; background: #f0f5ff; border-color: #adc6ff;",
inner: "background: #adc6ff;",
bg: "#f0f5ff"
}
const createStyledString = (obj) => {
let {
text,
tags
} = obj;
tags.sort((a, b) => b.start - a.start);
tags.forEach(t => {
const {
start,
end,
value,
tag
} = t;
text = text.substring(0, start) +
`<span contenteditable="false" data-action="${value}---${start}---${end}---${color.bg}---${tag}" unselectable="on" onselectstart="return false;" name="tag" class="outer" style="${color.outer}">${value}<span class="ne-c-inner" unselectable="on" onselectstart="return false;" data-action="${value}---${start}---${end}---${color.bg}---${tag}" style="${color.inner}">${tag}</span></span>` +
text.substring(end)
});
return text;
}
document.body.innerHTML=createStyledString(tagObject)
你的方法有两个主要问题。
- 首先,如果你有嵌套的值,你会追加它们不止一次。
- 第二,你正在处理的开始和结束位置,如果他们没有改变后,字符串被修改。
所以一个可能的解决方案是:
- 不要嵌套值,只需再次取相同的子字符串。
- 跟踪实际位置以及初始位置和"虚拟"位置,并使用它在正确的位置插入代码。
下面是一个工作代码片段:
let tagObject = {
"text": "I am asking a question in stackoverflow",
"tags": [{
start: 0,
end: 1,
value: "I",
tag: "TAG1"
},
{
start: 0,
end: 4,
value: "I am",
tag: "TAG2"
},
{
start: 5,
end: 22,
value: "asking a question",
tag: "TAG3"
},
{
start: 14,
end: 22,
value: "question",
tag: "TAG4"
},
{
start: 14,
end: 25,
value: "question in",
tag: "TAG5"
}
]
}
const color = {
outer: "color: #1d39c4; background: #f0f5ff; border-color: #adc6ff;",
inner: "background: #adc6ff;",
bg: "#f0f5ff"
}
const createStyledString = (obj) => {
let {
text,
tags
} = obj;
tags.sort((a, b) => b.start - a.start);
// TO KEEP TRACK OF INSERTED TEXT
let insertedAmmount = []
tags.forEach(t => {
const {
start,
end,
value,
tag
} = t;
// COMPUTE THE REAL START AND END POSITIONS
// TAKING INSERTED TEXT INTO ACCOUNT
let realStart = start
let realEnd = end
for(let idx in insertedAmmount){
if(idx < start){
realStart += insertedAmmount[idx]
}
if(idx <= end){
realEnd += insertedAmmount[idx]
}
}
let pre = `<span contenteditable="false" data-action="${value}---${start}---${end}---${color.bg}---${tag}" unselectable="on" onselectstart="return false;" name="tag" class="outer" style="${color.outer}">`
let pos = `<span class="ne-c-inner" unselectable="on" onselectstart="return false;" data-action="${value}---${start}---${end}---${color.bg}---${tag}" style="${color.inner}">${tag}</span></span>`
// UPDATE THE INFORMATION ABOUT INSERTED TEXT
insertedAmmount[start] = (insertedAmmount[start] || 0) + pre.length
insertedAmmount[end] = (insertedAmmount[end] || 0) + pos.length
// DON'T INSERT DIRECTLY THE VALUE BUT THE ALREADY EXISTENT TEXT
text = text.substring(0, realStart)
+ pre
+ text.substring(realStart, realEnd)
+ pos
+ text.substring(realEnd)
});
return text;
}
document.body.innerHTML=createStyledString(tagObject)