我有一个应用程序,用户在其中输入文本,然后将该文本发送到服务器,并返回包含该文本的单词数组。
但是如您所见,当匹配数超过1时问题就开始了。这是我当前的代码:
state.input !== '' && vocabularyItems && (vocabularyItems.map((vocabularyItem, index) => {
const regex = new RegExp(input, 'gi');
const results = vocabularyItem.matchAll(regex);
const tmp = [];
console.log(vocabularyItem);
for (const match of results) {
console.log(match);
let currentLoop = vocabularyItem.slice(0, match.index);
currentLoop += '<strong className="tt-highlight">';
currentLoop += vocabularyItem.slice(match.index, match.index + input.length);
currentLoop += '</strong>';
currentLoop += vocabularyItem.slice(match.index + input.length, vocabularyItem.length);
tmp.push(currentLoop);
}
console.table(tmp);
return (
<div
id={index}
className={`override-strong tt-suggestion tt-selectable ${cursor === index && 'tt-cursor'}`}
onMouseDown={handleClick}
key={index}
dangerouslySetInnerHTML={{ __html: tmp }}
/>
);
}))
这是HTML代码中的一些示例
1.
<strong className="tt-highlight">En</strong>kelkind
2.
<strong className="tt-highlight">En</strong>gagement
Engagem<strong className="tt-highlight">en</strong>t
如您所见,它仅在出现一次时起作用,但是在出现多于一个匹配项时重复该单词。我怎么能只得到类似的东西
<strong>en</strong>gagem<strong>en</strong>t?
en gagem en t?
我忘记补充一点,我需要保留案子
答案 0 :(得分:3)
这是使用string.replace
的一种方法:
const list = [
'end',
'England',
'engagement'
]
const boldify = (search) => {
return (string) =>
string.replace(new RegExp(search, 'gi'), '<strong>$&</strong>')
}
document.body.innerHTML = list.map(boldify('en')).join('<br>')
编辑:经过一段时间的思考,看到了可接受的答案,我想推送香草JS版本以使内容更完整。而且,React版本对我来说似乎很落后,这个版本更快!
之所以更快,是因为:
innerHTML
)
'use strict'
const list = [
'end',
'England',
'engagement',
'Ken Bogard',
'Venom',
'Engagement'
]
const boldify = (search) => {
return (string) => {
const div = document.createElement('div')
const parts = string.split(new RegExp(`(?=${search})|(?<=${search})`, 'gi'))
div.append(
...parts.map(part => {
if (part.toUpperCase() !== search.toUpperCase()) return part
const strong = document.createElement('strong')
strong.innerText = part
return strong
})
)
return div
}
}
const contains = (search) => {
search = search.toUpperCase()
return (string) => string.toUpperCase().indexOf(search) >= 0
}
const refreshSuggestions = () => {
// Fast removal of children.
while (suggestions.firstChild) suggestions.removeChild(suggestions.firstChild)
// nothing to do
if (searchInput.value.length == 0) return
const newSuggestions =
list.filter(contains(searchInput.value))
.map(boldify(searchInput.value))
suggestions.append(...newSuggestions)
}
searchInput.addEventListener('input', refreshSuggestions)
<input id="searchInput" list="suggestions">
<div id="suggestions">
</div>
答案 1 :(得分:3)
首先,我建议使用类似这样的东西:
const results = vocabularyItems.filter(word => word.toLowerCase().includes(input.toLowerCase()))
不区分大小写的词汇表查找。
接下来,我将以一些不同的方式突出显示比赛。我将建议的选项分为几个部分(匹配搜索输入和不匹配输入),然后分别设置样式:
const parts = suggestion.split(new RegExp(`(?=${match})|(?<=${match})`, 'gi'))
...
parts.map((part,key) => {
const style = part.toLowerCase() == match.toLowerCase() ? 'bold' : 'normal'
return <span style={{fontWeight:style}} {...{key}}>{part}</span>
})
我认为假设您建立自动完成搜索输入已经足够安全了,因此您可能会发现使用下面的快速演示(不包括所有样式):
//dependencies
const { render } = ReactDOM,
{ useState } = React
//vocabulary
const vocabulary = ['engagement', 'Bentley', 'English', 'seven', 'Engagement']
//suggested option component
const SuggestedOption = ({suggestion, match}) => {
const parts = suggestion.split(new RegExp(`(?=${match})|(?<=${match})`, 'gi'))
return (
<div>
{
parts.map((part,key) => {
const style = part.toLowerCase() == match.toLowerCase() ? 'bold' : 'normal'
return <span style={{fontWeight:style}} {...{key}}>{part}</span>
})
}
</div>
)
}
//autocomplete component
const SearchBar = () => {
const [suggestions, setSuggestions] = useState([]),
[inputValue, setInputValue] = useState(''),
onInput = input => {
setInputValue(input)
setSuggestions(vocabulary.filter(word => input.length && word.toLowerCase().includes(input.toLowerCase())))
}
return (
<div>
<input onKeyUp={e => onInput(e.target.value)} />
<div >
{
suggestions.map((suggestion,key) => <SuggestedOption {...{key,suggestion,match:inputValue}} />)
}
</div>
</div>
)
}
render(
<SearchBar />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
答案 2 :(得分:1)
编辑-叶夫根的答案比这个答案要好得多。
如果我正确理解您想要的内容,则可以通过一个简单的循环来实现:
var array = ["end","engagement","Engagement","england","enough","not this","or this"];
function filterArray(array, id) {
var returnArray = [];
for (var i = 0; i < array.length; i++) {
value = array[i];
if (value.includes(id)) {
returnArray.push(value);
}
}
return returnArray;
}
var filteredArray = filterArray(array,"en");
console.log(filteredArray);
如果要确保重复(在“参与”情况下会导致重复),则可以在推入数组之前将字符串设置为小写,并在再次推入之前检查数组是否存在字符串。