0

I'm trying to replace parts of a string with a different string. I have the starting index, ending index, and the string that I'm trying to replace it with. This is how the data looks like:

const mentions = [{ uid: "abc", startingIndex: 0, endingIndex: 9, displayName: "John Doe" }, { uid: "xyz", startingIndex: 26, endingIndex: 30}];

let text = "@John Doe How are you? Hi @Ben Sup?"

I was trying to replace the @[name] in text with the UID in this format: <@UID>.

So I came up with this:

  replaceText = (input, search, replace, start, end) => {
    return (
      input.slice(0, start) +
      input.slice(start, end).replace(search, replace) +
      input.slice(end)
    );
  };

  replaceWithMentions = () => {
    const { sendMessage } = this.props;
    const { mentions } = this.state;
    let { text } = this.state;

    text = mentions.reduce((text, mention) => {
      return this.replaceText(
        text,
        `@${mention.displayName}`,
        `<@${mention.uid}>`,
        mention.startingIndex,
        mention.endingIndex
      );
    }, text);

    sendMessage(text);
    this.setState({ text: "" });
  };

But the problem is as soon as the first mention gets replaced the index of other mentions changes. Resulting in other elements not getting replaced. Is there any way to prevent this?

5
  • 3
    You can write an algorithm that starts from the end of the string; that way although the length still changes the indexes of earlier mentions do not. Commented Jun 25, 2019 at 10:33
  • (If input.slice(start, end) == search then you can replace + input.slice(start, end).replace(search, replace) + with just + replace +.) Commented Jun 25, 2019 at 10:40
  • @Tobsta Thank you! It worked. I just added this line above mentions.reduce mentions.sort((a, b) => b.startingIndex - a.startingIndex); to sort it in descending order. Commented Jun 25, 2019 at 11:03
  • @ArunKumar glad to hear it :-) Commented Jun 25, 2019 at 11:35
  • @AndrewMorton Alright :) Commented Jun 25, 2019 at 12:31

1 Answer 1

1

This should do the trick

I'm sorting because the order of the mentions matters when constructing the uidText.

const insertMentions = (text, mentions) => {

  const comparator = (mention1, mention2) => 
    mention1.startingIndex - mention2.startingIndex

  const reducer = (
    [uidText, previousEndingIndex], 
    {startingIndex, endingIndex, uid}
  ) => [
    `${uidText}${text.substring(previousEndingIndex, startingIndex)}<@${uid}>`, 
    endingIndex
  ]

  const [uidText, previousEndingIndex] = 
    mentions.sort(comparator).reduce(reducer, ["", 0])
    
  return uidText + text.substring(previousEndingIndex)
}

const mentions = [
    { 
    uid: "xyz", 
    startingIndex: 26, 
    endingIndex: 30,
  },
  { 
    uid: "abc", 
    startingIndex: 0, 
    endingIndex: 9, 
    displayName: "John Doe",
  }, 

]

const text = "@John Doe How are you? Hi @Ben Sup?"

console.log(insertMentions(text, mentions))

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.