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>
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)