-1

I'm currently implementing a substring search. From the algorithm, I get array of substrings occurence positions where each element is in the form of [startPos, endPos].

For example (in javascript array):

[[1,3], [8,10], [15,18]]

And the string to highlight is:

ACGATCGATCGGATCGAGCGATCGAGCGATCGAT

I want to highlight (in HTML using <b>) the original string, so it will highlight or bold the string from position 1 to 3, then 8 to 10, then 15 to 18, etc (0-indexed).

A<b>CGA</b>TCGA<b>TCG</b>GATC<b>GAGC</b>GATCGAGCGATCGAT

This is what I have tried (JavaScript):

function hilightAtPositions(text, posArray) {

    var startPos, endPos;

    var startTag = "<b>";
    var endTag   = "</b>";
    var hilightedText = "";

    for (var i = 0; i < posArray.length; i++) {
        startPos = posArray[i][0];
        endPos   = posArray[i][1];

        hilightedText = [text.slice(0, startPos), startTag, text.slice(startPos, endPos), endTag, text.slice(endPos)].join(''); 
    }

    return hilightedText;
}

But it highlights just a range from the posArray (and I know it is still incorrect yet). So, how can I highlight a string given multiple occurrences position?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Muhammad Abrar
  • 2,292
  • 1
  • 15
  • 13

5 Answers5

1

Looking at this question, and following John3136's suggestion of going from tail to head, you could do:

String.prototype.splice = function( idx, rem, s ) {
    return (this.slice(0,idx) + s + this.slice(idx + Math.abs(rem)));
};

function hilightAtPositions(text, posArray) {
    var startPos, endPos;
    posArray = posArray.sort(function(a,b){ return a[0] - b[0];});

    for (var i = posArray.length-1; i >= 0; i--) {
        startPos = posArray[i][0];
        endPos   = posArray[i][1];
        text= text.splice(endPos, 0, "</b>"); 
        text= text.splice(startPos, 0, "<b>"); 
    }
    return text;
}

Note that in your code, you are overwriting hilightedText with each iteration, losing your changes.

Community
  • 1
  • 1
Diego
  • 18,035
  • 5
  • 62
  • 66
  • Nice, it works. But, is it necessary to sort the posArray? Because it is guaranteed that the posArray is in increasing order. – Muhammad Abrar Feb 29 '12 at 06:02
  • No, if it's already sorted then you can remove `posArray = posArray.sort(function(a,b){ return a[0] - b[0];});` – Diego Feb 29 '12 at 16:57
1

Try this:

var stringToHighlight = "ACGATCGATCGGATCGAGCGATCGAGCGATCGAT";    
var highlightPositions = [[1,3], [8,10], [15,18]];

var lengthDelta = 0;

for (var highlight in highlightPositions) {
    var start = highlightPositions[highlight][0] + lengthDelta;
    var end = highlightPositions[highlight][1] + lengthDelta;

    var first = stringToHighlight.substring(0, start);
    var second = stringToHighlight.substring(start, end + 1);
    var third = stringToHighlight.substring(end + 1);

    stringToHighlight = first + "<b>" + second + "</b>" + third;
    lengthDelta += ("<b></b>").length;
}

alert(stringToHighlight);

Demo: http://jsfiddle.net/kPkk3/

fardjad
  • 20,031
  • 6
  • 53
  • 68
0

If you want to check for multiple string matches and highlight them, this code snippet works.

function highlightMatch(text, matchString) {
    let textArr = text.split(' ');
    let returnArr = [];
    
    for(let i=0; i<textArr.length; i++) {
        let subStrMatch = textArr[i].toLowerCase().indexOf(matchString.toLowerCase());
        
        if(subStrMatch !== -1) {
            let subStr = textArr[i].split('');
            let subStrReturn = [];
            
            for(let j=0 ;j<subStr.length; j++) {
                
                if(j === subStrMatch) {
                    subStrReturn.push('<strong>' + subStr[j]);    
                } else if (j === subStrMatch + (matchString.length-1)){
                    subStrReturn.push(subStr[j] + '<strong>');
                } else {
                    subStrReturn.push(subStr[j]);
                }
            }
            returnArr.push(subStrReturn.join(''));
        } else {
            returnArr.push(textArr[i]);
        }
    }
    return returnArr;
}


highlightMatch('Multi Test returns multiple results', 'multi'); 
=>  (5) ['<strong>Multi<strong>', 'Test', 'returns', '<strong>multi<strong>ple', 'results']
Abby
  • 51
  • 4
0

Assuming your list of segments is ordered from lowest start to highest, try doing your array from last to first.

That way you are not changing parts of the string you haven't reached yet. Just change the loop to:

 for (var i = posArray.length-1; i >=0; i--) {
John3136
  • 28,809
  • 4
  • 51
  • 69
0

Assuming that you're trying to highlight search terms or something like that. Why not replace the term with the bolding?

example:

term: abc

var text = 'abcdefgabcqq';
var term = 'abc';
text.replace(term, '<b>' + term + '</b>');

This would allow you to avoid worrying about positions, assuming that you are trying to highlight a specific string.

Developer
  • 2,021
  • 12
  • 11