Home > Software engineering >  How can I compare two strings and replace matching words with JavaScript?
How can I compare two strings and replace matching words with JavaScript?

Time:11-17

I am trying to create a function which takes in 2 strings:

- title: "Lorem ipsum dolor sit amet",

- itle_highlighted: "ipsum amet",

and returns one string or array containing the all words in title in addition words defined in the string title_highlighted will have a certain property and replace their matching word in title.

End result should be something like: <h1>Lorem<span style={{color: "orange"}}>impsum</span>dolor sit<span style={{color: "orange"}}>amet</span>/h1>

Output example

My approach so far:

const highlightHeading = (title, title_highlighted) => {
  const title_arr = title.trim().split(/\s /);
  const title_highlighted_arr = title_highlighted.trim().split(/\s /);

  for (const element1 of title_arr) {
    console.log(element1);
    for (const element2 of title_highlighted_arr) {
      if (element1 === element2) {
        const highlighted = `<span style={{ color: "orange" }}>${element1}</span>`;
        console.log(highlighted);
      }
    }
  }
};
highlightHeading("Lorem ipsum dolor sit amet", "ipsum amet");

Thanks in advance.

CodePudding user response:

You could create a <HighlightedHeading> component that accepts a color, title, and words.

const { useMemo, useState } = React;

const tokenize = (str, delim = /\s /) => str.trim().split(delim);

const toWordArray = (words) => {
  if (Array.isArray(words)) return words;
  if (typeof words === 'string') return tokenize(words);
  return []; // or throw Error
};

const toWordSet = (words) =>
  new Set(toWordArray(words).map(word => word.toLowerCase()));

const HighlightedHeading = (props) => {
  const { color, title, words } = props;
  const wordSet = useMemo(() => toWordSet(words), [words]);
  return (
    <h2 className="highlighted-text">
      {tokenize(title).map((token) => (
        <React.Fragment>
          {wordSet.has(token)
            ? <span style={{ color }}>{token}</span>
            : token}
          {/* Add spaces for copy-paste */}
          {' '}
        </React.Fragment>
      ))}
    </h2>
  );
};

const App = () => {
  return (
    <div>
      <HighlightedHeading
        color="yellow"
        title="Lorem ipsum dolor sit amet"
        words="ipsum amet"
      />
    </div>
  );
};

ReactDOM
  .createRoot(document.getElementById("root"))
    .render(<App title="Example using Hooks:" />);
*, *::before, *::after {
  box-sizing: border-box;
}

html, body, #root {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

#root {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background: #222;
  color: #FFF;
}

.highlighted-text {
  display: flex;
  gap: 0.5ch; /* Display spaces in HTML */
  margin: 0;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>

CodePudding user response:

The naive splitting approach doesn't take punctuation into account (e.g. Lorem ipsum? Dolor amet!). You can try a regex with a word boundary \b instead:

title = "Lorem ipsum dolor sit amet"

keywords = ["ipsum", "amet"]

regex = new RegExp('\\b('   keywords.join('|')   ')\\b', 'g')

result = title.replace(regex, '<span whatever>$&</span>')

console.log(result)

  • Related