Fogarasi Norbert
Fogarasi Norbert

Reputation: 672

Javascript replace already replaced text

I have two textareas written in HTML like this:

<textarea id="checked-words"></textarea>
<br />
<textarea id="words" onkeyup="displayColoredText()"></textarea>
<div id="text-to-insert"></div>

(into the div element, I will insert text, using JavaScript)

My task is to write into the div section the text from the second textarea and make red the occurrences of strings from the first textarea.
Example
If the first textarea contains the following words: aaa, aab and the second contains aaab, all of the characters have to be red. If the second one contains abaa, none of the characters will be red in the div section.

Here is my JavaScript function which displays and colorize the text:

function displayColoredText() {
//Displays the colored text below the second textarea

//Find the two textareas
var firstTextArea = document.getElementById('checked-words');
var secondTextArea = document.getElementById('words');

//Split by spaces
var checkedWords = firstTextArea.value.split(" ");
var text = secondTextArea.value.split(" ");

var textToInsert = secondTextArea.value;

for(i in checkedWords) {
    console.log(checkedWords.length);
    textToInsert = textToInsert.replace(new RegExp(checkedWords[i], 'g'), '<span class="insertRed">' + checkedWords[i] + '</span>');
}

document.getElementById('text-to-insert').innerHTML = textToInsert;
}

My problem is, that an already replaced text won't be considered, for example, if the first textarea contains aaa and aab and if the second one contains aaab, only the first three characters will be red, instead of the whole string. How can I resolve this?

EDIT: Screenshot of the problem enter image description here

Upvotes: 1

Views: 160

Answers (2)

Benjamin Hollon
Benjamin Hollon

Reputation: 181

Your problem is how your strings get replaced. Your first string is 'aaa aab'. After replacing for 'aaa' in 'aaab', you get '<span class="insertRed">aaa</span>b'. Trying to find 'aab' in this string will come up with no results. You have to replace from your original string and somehow combine the two. I'm not sure how to do this, but I hope this sets you on the right track.

EDIT: I think this will work: Instead of replacing the text in the string, place the beginning coordinate in an array and the end coordinate in a second array. Keep doing this for every word found. Then at all of the beginning coordinates, insert the string '<span class="insertRed">'. At all of the end coordinates, insert the string '<span>'. Here is the JS:

function displayColoredText() {
    //Displays the colored text below the second textarea
    //arrays with coordinates
    var beginnings = [];
    var ends = [];
    //Find the two textareas
    var firstTextArea = document.getElementById('checked-words');
    var secondTextArea = document.getElementById('words');

    //Split by spaces
    var checkedWords = firstTextArea.value.split(" ");
    var text = secondTextArea.value.split(" ");

    var textToInsert = firstTextArea.value;

    for(i in checkedWords) {
        console.log(checkedWords.length);
        if (firstTextArea.value.indexOf(checkedWords[i]) != -1) {
            beginnings.push(firstTextArea.value.indexOf(checkedWords[i]));
            ends.push(firstTextArea.value.indexOf(checkedWords[i]) + checkedWords[i].length);
        }
    }
    beginnings.sort(function(a, b){return b-a});
    ends.sort(function(a, b){return b-a});
    for (b in beginnings) {
        textToInsert = textToInsert.slice(0, ends[b]) + "</span>" + textToInsert.slice(ends[b]);
        textToInsert = textToInsert.slice(0, beginnings[b]) + '<span class="insertRed">' + textToInsert.slice(beginnings[b]);
    }
    document.getElementById('text-to-insert').innerHTML = textToInsert;
}

This code is untested, so tell me if something doesn't work and I will change it. Basically, what I am doing is instead of replacing occurrences, I find them first, place them in arrays, and insert the correct text at those coordinates. I hope this helps!

Upvotes: 0

C3roe
C3roe

Reputation: 96241

Your original input from the second text area is pure text, not HTML, so this is the "state" of the data you want to do this in.

This would be my way of implementing it as mentioned in comments, recording which positions have a match first, and then simply looping over all characters in the end to wrap them in a span each:

function displayColoredText() {
  //Displays the colored text below the second textarea

  //Find the two textareas
  var firstTextArea = document.getElementById('checked-words');
  var secondTextArea = document.getElementById('words');

  //Split by spaces
  var checkedWords = firstTextArea.value.split(" ");
  var text = secondTextArea.value;
  // empty array with keys 0 to length-1 set to undefined
  var markedMatches = new Array(secondTextArea.value.length);

  for (var i = 0, l = checkedWords.length; i < l; ++i) {
    var checkedWord = checkedWords[i],
      start = 0,
      matchPos;
    // check for match from current starting position
    while ((matchPos = text.indexOf(checkedWord, start)) !== -1) {
      // mark positions from current match start to that plus length of match
      for (var k = matchPos, m = matchPos + checkedWord.length; k < m; ++k) {
        markedMatches[k] = true;
      }
      // advance starting position to continue searching
      start = matchPos + 1;
    }
  }

  var textToInsert = '';
  for (var i = 0, l = text.length; i < l; ++i) {
    // wrap in span if markedMatches contains true at this position
    textToInsert += (markedMatches[i] ? '<span class="match">' + text[i] + '</span>' : text[i]);
  }
  document.getElementById('text-to-insert').innerHTML = textToInsert;
}

https://jsfiddle.net/t9xjzkaw/

As I said, you could get more sophisticated in collecting the matches as intervals, or putting multiple adjoining matching characters into a single span element, instead of wrapping each one on its own ... but this does the basic job.

Upvotes: 2

Related Questions