Заменить слово в строке в определенной позиции - PullRequest
0 голосов
/ 11 мая 2018

Как я могу заменить строку в абзаце другой строкой, не используя метод javascript .replace(), и причина, по которой я не могу использовать метод .replace(), заключается в том, что он выполняет замену только с первым соответствием слово в строке, чтобы добавить немного больше контекста, почему я не могу использовать .replace(), я пытаюсь создать функцию маркировки, где пользователь сможет пометить текст в документе, маркер будет храниться на на стороне сервера, поэтому я запрашиваю маркеры документов, объект маркера содержит начальную и конечную позиции выделения в строке, поэтому я беру их в значения, чтобы извлечь текст и обернуть в тег mark после этого мне нужно заменить текст уже тегом mark на исходный текст, но есть случай, когда пользователь может выбрать слово, которое встречается в документе более одного раза, поэтому я не могу использовать замену поэтому мне нужно использовать начальную и конечную позиции выделения для .replace() текста, например:

Lorem Ipsum Dolor Sit Amet, Заклинатель Lorem Adipiscing Elit. Vivamus ipsum Lorem eros, interdum ac cursus et, pulvinar Lorem at est. Integer nec rutrum ligula. В элитном классе есть элитный porttitor finibus.

и я хочу заменить 3-й «Lorem» на «Space», не касаясь остальных, я не могу использовать .replace(). Есть ли другой способ для этого, возможно, с использованием начальной и конечной позиции выделения курсора?

  /**
  * Count the position and the number of the html tags
  * to position the marker.
  * @param {object} The chapter object
  * @param {object} The marker object
  * @return {object} Return the chapter with the marker on it.
  */
  public characterCounter(chapter, marker): any {
    const counters: any = {
      htmlSimbol: null, // < or >
      characters: 0,
      startTags: 0, // count html until the start of the selection.
      endTags: 0 // count html until the end of the selection.
    };

    /* Here  we loop the blocks to find the righ
    *  one to place marker.
    */
    chapter.blocks.some((block) => {
      if (marker.blockId === block.blockId) {
        /*
        * Ones the block is founded start counting the
        * characters from the string.
        */
        const blockText = block.blockElement.text;
        for (let i = 0; i < blockText.length; i++) {
          /* when the loop reach the end of the selection
          * and match with the number of characters counted
          * that are not part of html tag the loop stop.
          */
          if (counters.characters === marker.end) {
            break;
          } else {
            /*
            * if the loop crash wiht < then start counting
            * characters as part of the html tags and stop
            * when crash with >
            */
            if (blockText[i] === '<' || blockText[i] === '>') {
              counters.htmlSimbol = blockText[i];
            } else if (blockText[i] !== '<' && blockText[i] !== '>' && counters.htmlSimbol !== null) {
              if (counters.htmlSimbol === '<') {
                if (counters.characters <= marker.start) {
                  counters.startTags += 1; // count the characters from the open html tags founded
                } else {
                  counters.endTags += 1; // count the characters from the close html tags founded
                }
              } else if (counters.htmlSimbol === '>') {
                if (counters.characters <= marker.start) {
                  counters.startTags += 2;  // count the characters from the open html tags founded
                } else {
                  counters.endTags += 2; // count the characters from the close html tags founded
                }
                counters.htmlSimbol = null; // change to null to know that is the end ot he html tag
              }
            } else if (counters.htmlSimbol === null) {
              counters.characters += 1; // count the characters that are not part of html tag ( only text no html).
            }
          }
        }

        // Here is where i extract the text selected and wrapped in to the mark tag to then replaced on the original block of text

        counters.endTags += counters.startTags;
        marker.start += counters.startTags;
        marker.end += counters.endTags;

        const textSelected = blockText.substring(marker.start, marker.end);

        const markerText = `<mark class="${marker.color}" *ngClass=""  alt="${marker.id}">${textSelected}</mark>`;

        block.blockElement.text = blockText.replace(textSelected, markerText);

        return false;
      }
    });
    return chapter;
  }

  /**
  * Analyze the text block and add the marking
  * to the right block of text.
  * @param {array} The list of markers
  * @param {array} The array of blocks
  * @return {array} the array of block with the markers.
  */
  public addMarking(markersList, chaptersArray): any {
    let index = 0;
    markersList.some((marker) => {
      index = chaptersArray.map((e) => e.id).indexOf(marker.chapterId);
      if (index > -1) {
        this.characterCounter(chaptersArray[index], marker);
        return false;
      } else {
        chaptersArray.some((chapter) => {
          index = chapter.subChapters.map((e) => e.id).indexOf(marker.chapterId);
          if (index > -1) {
            this.characterCounter(chapter.subChapters[index], marker);
            return false;
          }
        });
      }
    });
    return chaptersArray;
  }

проблема в том, что после того, как я применил тег mark, после того, как я применил тег mark к выделенному тексту, мне нужно заменить исходный текст на тег mark, как вы можете видеть в код, который я использую .replace(), поэтому у меня проблема в том, что пользователь выбирает слово более одного раза в длинном абзаце, поэтому текст заменяется в неправильном месте.

Ответы [ 4 ]

0 голосов
/ 11 мая 2018

Я бы просто взял текст, разделил его на пробелы, чтобы получить точные слова, а затем отфильтровал слово и получил текущий индекс. Поскольку у вас есть индексы, вы можете обмениваться определенным словом в индексе с любым, что захотите, и после этого вы можете просто снова объединить массив.

Примерно так:

const text = "Lorem ipsum dolor sit amet, consectetur Lorem adipiscing elit. Vivamus ipsum Lorem eros, interdum ac cursus et, pulvinar Lorem at est. Integer nec rutrum ligula. In dignissim est a elit porttitor finibus.";

function exchangeWordInText(lookupWord, nr, text, newWord){

  const lookupTable = [];
  const wordArray = text.split(' ');

  wordArray.filter((word, index) => {
    if(word === lookupWord){
      lookupTable.push({ index: index , word: word});
    }
  });

  if(nr > 0 && nr <= lookupTable.length){
      const exchangeWord = lookupTable[nr-1];
      wordArray[exchangeWord.index] = newWord;
  }

  return wordArray.join(' ');
}

// This would exchange the first 'Lorem' in the text with 'CHANGED'
const result= exchangeWordInText('Lorem', 1, text, 'CHANGED');

РЕЗУЛЬТАТЫ В:

"CHANGED ipsum dolor sit amet, consectetur Lorem adipiscing elit. Vivamus ipsum Lorem eros, interdum ac cursus et, pulvinar Lorem at est. Integer nec rutrum ligula. In dignissim est a elit porttitor finibus."

Это не самое красивое решение, и оно, безусловно, может быть улучшено (оно также чувствительно к регистру), но оно может работать для вас! :)

JSBIN для проверки: https://jsbin.com/lepuyifele/1/edit?js,console,output

кр, Georg

0 голосов
/ 11 мая 2018
<!DOCTYPE html>
<html>
<body>

<p>Click the button to set "blue", "house" and "car" to upper-case, in the paragraph below:</p>

<p id="demo">Mr Blue has a blue house and a blue car.</p>

<button onclick="myFunction()">Try it</button>

<script>
function myFunction() {
    var str = document.getElementById("demo").innerHTML; 
    var res = str.replace(/blue|house|car/gi, function (x) {
        return x.toUpperCase();
    });
    document.getElementById("demo").innerHTML = res;
}
</script>

</body>
</html>
0 голосов
/ 11 мая 2018

Я пытался реализовать решение, не используя замену, а скорее итерируя один раз по маркерам и исходному тексту, а пока строил «новый текст» с примененными маркерами. Для простоты я использовал тег mark, жестко закодированный в решении. Вы можете довольно легко параметризовать этот аспект.

// suppose we are given the original text, and the markers as start-end pairs of selection character positions
const text = `Lorem ipsum dolor sit amet, consectetur Lorem adipiscing elit. Vivamus ipsum Lorem eros, interdum ac cursus et, pulvinar Lorem at est. Integer nec rutrum ligula. In dignissim est a elit porttitor finibus.`;
const markers = [{start: 77, end: 82}, {start: 40, end: 45}]; // positions defining the 2nd and the 3rd occurence of Lorem, chosen arbitrarily

function markSelections(text, markers) {
  // sort markers just in case the are not sorted from the Storage
  const sortedMarkers = [...markers].sort((m1, m2) => m1.start - m2.start);
  let markedText = '';
  let characterPointer = 0;
  sortedMarkers.forEach(({start, end}) => {
    markedText += text.substring(characterPointer, start);
    markedText += '<mark>';
    markedText += text.substring(start, end);
    markedText += '</mark>';
    characterPointer = end;
  });
  // add the remaining text after markers
  markedText += text.substring(characterPointer);
  return markedText;
}
document.write(markSelections(text, markers));
mark {
  color: red;
}
0 голосов
/ 11 мая 2018

Вы можете сделать это, используя следующее регулярное выражение:

/(?!^)lorem/gi

И использовать функцию обратного вызова в функции String.prototype.replace.Эта функция обратного вызова будет увеличивать переменную previousMatches, и в случае, если она соответствует конкретному position, она будет возвращать замену.

В фрагменте я заменяю только 3-й случай:

var originalContent, searchedWord, replacement, pattern, regExp, newContent, previousMatches = 0;

originalContent = 'Lorem ipsum dolor sit amet, consectetur Lorem adipiscing elit. Vivamus ipsum Lorem eros, interdum ac cursus et, pulvinar Lorem at est. Integer nec rutrum ligula. In dignissim est a elit porttitor finibus. Lorem ipsum dolor sit amet, consectetur Lorem adipiscing elit. Vivamus ipsum Lorem eros, interdum ac cursus et, pulvinar Lorem at est. Integer nec rutrum ligula. In dignissim est a elit porttitor finibus.';
document.write("Before : <br/> " + originalContent);
searchedWord = "Lorem";
replacement = "<b>" + searchedWord +"</b>";
pattern = "(?!^)" + searchedWord;    
position = 2; // we will replace the 3rd occurence
regExp = new RegExp(pattern, "gi");
newContent = originalContent.replace(regExp, function (occurence) {
  var toReturn;
  if (previousMatches === position) {
    // we're returning the replacement in this case 
    toReturn = replacement;
  } else {
    // returning searchedWord is similar to not replacing this occurence
    toReturn = searchedWord;
  }
  // incrementing previousMatches
  previousMatches++;
  return toReturn;
});
document.write("<br/><br/> After : <br/> " + newContent);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...