突出显示 JavaScript 中子字符串中的子字符串
Highlight substring within substring in JavaScript
我试图使用开始和结束索引突出显示字符串中的子字符串。但是我在突出显示重叠的子字符串时遇到问题。
例如
我有一个 text
和一个 array
用于突出显示。
有什么办法,怎样才能避免标签重叠。
我尝试使用 regex
匹配子字符串,但无法解决它。
let tagObject = {
"text": "I am asking a question in Whosebug",
"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 Whosebug",
"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)
我试图使用开始和结束索引突出显示字符串中的子字符串。但是我在突出显示重叠的子字符串时遇到问题。 例如
我有一个 text
和一个 array
用于突出显示。
有什么办法,怎样才能避免标签重叠。
我尝试使用 regex
匹配子字符串,但无法解决它。
let tagObject = {
"text": "I am asking a question in Whosebug",
"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 Whosebug",
"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)