根据textContent中的索引突出显示文本 [英] Highlight text based on index in textContent

查看:130
本文介绍了根据textContent中的索引突出显示文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Bounty



在测试时,奖励将通过最新版本的Firefox,Chrome和Internet Explorer获得最快的解决方案,如jsPerf所示在我自行决定创建此类解决方案时最有用的答案。 Mwahahaha!



我将主要对解决方案感到满意,该解决方案采用所有偏移和未处理< span> 并添加突出显示,以便 parent.textContent = parent.textContent 然后运行更新的偏移列表上的解决方案将重新突出显示,但这具有不利的时间复杂性,因此不是首选。






相关问题








我有一个只包含文字的元素,我想突出显示。我还有一个 [startline,startcol,endline,endcol] 的数组,知道每行的长度来自 .textContent ,我可以规范化为 [startoffset,endoffset] 。如何在每对偏移之间突出显示



这个问题比看起来更难,因为:




  • 内容不保证没有重复(所以没有查找/替换),

  • 必须最终对已经突出显示的文本执行突出显示,有时与已突出显示的文本相交,

  • 必须根据父元素的索引执行突出显示.textContent property。



Definitions




  • 突出显示:将元素的 textContent 中的文本子集放在一个或多个中< span class =highlight> 而不更改父元素的 textContent 值,使得突出显示n次的文本在n个嵌套中< span class =highlight> elements。

  • offset :非负整数represen在某一点(在两个字符之间)之前的字符的数量。

  • 字符:JavaScript给你的一个实例,作为 .textContent 字符串(包括空格)的给定索引处的值。



MCVE



  function highlight(parent,startoff,endoff){// Erm ... parent.textContent;} // Test casesvar starts = [5,44,0,50,6,100,99,50,51, 52]; var ends = [20,62,4,70,10,100,101,54,53,53]; for(var i = 0;我< 10; i + = 1){highlight(document.getElementById(target),starts [i],ends [i]);}  

  #target {white-space:pre-wrap;}  

 < span id =target>'Twas brillig,以及狡猾的toves在wabe中做了gyre和gimble:所有的模仿都是borogoves,And 我的儿子,请小心Jabberwock!咬住的下颚,抓住的爪子!小心Jubjub的小鸟,避开冷酷的Bandersnatch!他手里拿着他的蝎子剑:很长一段时间他寻找的男人的敌人 - 所以他在Tumtum树旁休息了一会儿,然后站了一会儿思绪。然后,就像在他那个犹豫的想法中他站着一样,Jabberwock,带着火焰的眼睛,穿过那片郁郁葱葱的木头,然后在它来了的时候烧掉了!一,二!一二!通过和通过the vorpal blade去了snicker-snack!他把它弄死了,并且用它的头向后去了。而且,你杀了Jabberwock吗?来到我的怀抱,我的光芒四射的男孩!天啊!!Callooh! Callay!'他的喜悦充满了他的意思。'那是光彩夺目的,而且那些狡猾的小蛮傻嘟嘟嘟嘟咕噜咕噜咕噜咕噜咕噜咕噜咕噜咕噜咕噜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜/ pre> 

解决方案

对开始/结束位置进行标准化以避免重叠。


  1. 将起始位置和结束位置合并为具有相反值的单个列表(例如,-1和1)

  2. 按位置值排序列表,然后按标记值排序(基于第二级排序,您可以区分连续范围合并它们)

  3. 通过位置列表并将当前位置的值标记添加到当前总和;一旦它为0 - 这意味着您刚刚找到了一些嵌套的结束/相交的部分;

这样,您将获得突出显示的位置,而不会嵌套/重叠范围。



用文本节点和HTML元素混合替换文本节点(如< span> documentFragment .replaceChild()将有所帮助:



  let starts = [5,44,0,50,6,100,99,50,51,52]; let ends = [20,62,4,70,10,100,101, 54,53,53]; let positions = []; let normalizedPositions = []; starts.forEach(function(position){positions.push({position,value:1});}); ends.forEach(function( position){positions.push({position,value:-1});}); positions = positions.sort(function(a,b){return a.position  -  b.position || b.value  -  a.value}); var currentSection = {from:0,counter:0}; for(position position of positions){if(!currentSection.counter){if(position.value === -1){抛出`不一致的边界:在打开$ {position.position}之前关闭; } currentSection.from = position.position; } currentSection.counter + = position.value; if(!currentSection.counter){normalizedPositions.push({from:currentSection.from,to:position.position}); if(currentSection.counter){throw最后一节没有正确关闭; } let parentNode = document.querySelector('p'); let textNodeToReplace = parentNode.childNodes [0]; let sourceText = textNodeToReplace.nodeValue; let documentFragment = document.createDocumentFragment(); let withoutHighlightingStart = 0; normalizedPositions.forEach(function( highlightRange){if(highlightRange.from> withoutHighlightingStart){let notHighlighted = createTextNode(sourceText.slice(withoutHighlightingStart,highlightRange.from)); documentFragment.appendChild(notHighlighted);} let highlight = createHighlighted(sourceText.slice(highlightRange.from, highlightRange.to)); documentFragment.appendChild(突出显示); withoutHighlightingStart = highlightRange.to;}); let lastNotHighlighted = createTextNode(sourceText.slice(withoutHighlightingStart)); documentFragment.appendChild(lastNotHighlighted); parentNode.replaceChild(documentFragment,textNodeToReplace) ; function createTextNode(str){return document.createTextNode(str);} function createHighlighted(st r){let span = document.createElement('span'); span.classList.add(突出); span.appendChild(一个createTextNode(STR)); return span;}  

  .highlight {background-color:yellow ;颜色:深蓝色;}  

 < p> Lorem ipsum dolor sit amet,consectetur adipiscing elit,sed do eiusmod tempor incididunt ut labore et dolore magna aliqua。 Ut enim ad minim veniam,quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat。 Duis aute irure dolor in repreptderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur。 Excepteur sint occaecat cupidatat non proident,sunt in culpa qui officia deserunt mollit anim id est laborum。< / p>  


Bounty

The bounty will go to the fastest solution, as demonstrated by jsPerf, across the latest release versions of Firefox, Chrome and Internet Explorer at time of testing or the answer most useful in creating such a solution at my discretion. Mwahahaha!

I'll be mostly satisfied with a solution that takes all of the offsets and an unprocessed <span> and adds the highlighting to that, so that parent.textContent = parent.textContent followed by running the solution on an updated list of offsets will re-highlight, but this has unfavourable time complexity so is not preferred.


Related questions


I have an element containing nothing but text, which I would like to highlight. I also have an array of [startline, startcol, endline, endcol] which, knowing the lengths of each line from .textContent, I can normalise to [startoffset, endoffset]. How can I highlight between each pair of offsets?

This problem is harder than it seems because:

  • the content is not guaranteed to have no repeats (so no find / replace), and
  • highlighting must ultimately be performed on already highlighted text, sometimes intersecting with text that has already been highlighted, and
  • highlighting must be performed based on the index of the parent element's .textContent property.

Definitions

  • highlight: to place a subset of the text from an element's textContent in one or more <span class="highlighted"> without changing the parent element's textContent value, such that text that is highlighted n times is within n nested <span class="highlighted"> elements.
  • offset: a non-negative integer representing the number of characters before a certain point (which is between two characters).
  • character: an instance of whatever JavaScript gives you as the value at a given index of a .textContent string (including whitespace).

MCVE

function highlight(parent, startoff, endoff) {
  // Erm...
  parent.textContent;
}

// Test cases

var starts = [
  5,  44, 0, 50, 6,  100, 99,  50, 51, 52
];
var ends = [
  20, 62, 4, 70, 10, 100, 101, 54, 53, 53
];
for (var i = 0; i < 10; i += 1) {
  highlight(document.getElementById("target"),
            starts[i], ends[i]);
}

#target {
  white-space: pre-wrap;
}

<span id="target">
'Twas brillig, and the slithy toves
  Did gyre and gimble in the wabe:
All mimsy were the borogoves,
  And the mome raths outgrabe.

"Beware the Jabberwock, my son!
  The jaws that bite, the claws that catch!
Beware the Jubjub bird, and shun
  The frumious Bandersnatch!"

He took his vorpal sword in hand:
  Long time the manxome foe he sought --
So rested he by the Tumtum tree,
  And stood awhile in thought.

And, as in uffish thought he stood,
  The Jabberwock, with eyes of flame,
Came whiffling through the tulgey wood,
  And burbled as it came!

One, two! One, two! And through and through
  The vorpal blade went snicker-snack!
He left it dead, and with its head
  He went galumphing back.

"And, has thou slain the Jabberwock?
  Come to my arms, my beamish boy!
O frabjous day! Callooh! Callay!'
  He chortled in his joy.

'Twas brillig, and the slithy toves
  Did gyre and gimble in the wabe;
All mimsy were the borogoves,
  And the mome raths outgrabe.
</span>

解决方案

Make normalization to start/end positions to avoid overlapping.

  1. Merge starting and ending positions to single list with opposite values(say, -1 and 1)
  2. Sort list by position value and then - by marker value(and based on second level sorting you can either distinguish sequential ranges or merge them)
  3. go through list of positions and add current position's value marker to current sum; once it's "0" - it means you have just found ending for some set nested/intersected sections;

This way you will get positions for highlighting without nested/overlapped ranges.

To replace text node with mix of text nodes and HTML elements(like <span>) documentFragment and .replaceChild() will help:

let starts = [
    5,  44, 0, 50, 6,  100, 99,  50, 51, 52
];
let ends = [
    20, 62, 4, 70, 10, 100, 101, 54, 53, 53
];

let positions = [];
let normalizedPositions = [];
starts.forEach(function(position) {
    positions.push({position, value: 1});
});
ends.forEach(function(position) {
    positions.push({position, value: -1});
});
positions = positions.sort(function(a, b) {
    return a.position - b.position || 
        b.value - a.value
});

var currentSection = {from: 0, counter: 0};

for(position of positions) {
    if (!currentSection.counter) {
        if (position.value === -1) {
            throw `inconsistent boundaries: closing before opening ${position.position}`;
        }
        currentSection.from = position.position;  
    }
    currentSection.counter += position.value;

    if (!currentSection.counter) { 
        normalizedPositions.push({
            from: currentSection.from, 
            to: position.position
        });
    }
}
if (currentSection.counter) {
    throw "last section has not been closed properly";   
}


let parentNode = document.querySelector('p');
let textNodeToReplace = parentNode.childNodes[0];
let sourceText = textNodeToReplace.nodeValue;

let documentFragment = document.createDocumentFragment();
let withoutHighlightingStart = 0;

normalizedPositions.forEach(function (highlightRange) {
    if (highlightRange.from> withoutHighlightingStart) {
      let notHighlighted = createTextNode(sourceText.slice(withoutHighlightingStart, highlightRange.from));
      documentFragment.appendChild(notHighlighted);
    }
    let highlighted = createHighlighted(sourceText.slice(highlightRange.from, highlightRange.to));
    documentFragment.appendChild(highlighted);
    withoutHighlightingStart = highlightRange.to;
});
let lastNotHighlighted = createTextNode(sourceText.slice(withoutHighlightingStart));
documentFragment.appendChild(lastNotHighlighted);

parentNode.replaceChild(documentFragment, textNodeToReplace);

function createTextNode(str) {
   return document.createTextNode(str);
}

function createHighlighted(str) {
   let span = document.createElement('span');
   span.classList.add('highlight');
   span.appendChild(createTextNode(str));
   return span;
}

.highlight {
    background-color: yellow;
    color: dark-blue;
}

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

这篇关于根据textContent中的索引突出显示文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆