将多个子字符串匹配到一个字符串

时间:2020-01-09 09:29:08

标签: javascript html reactjs string

我有一个应用程序,用户在其中输入文本,然后将该文本发送到服务器,并返回包含该文本的单词数组。

enter image description here

但是如您所见,当匹配数超过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?

我忘记补充一点,我需要保留案子

3 个答案:

答案 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版本对我来说似乎很落后,这个版本更快!

之所以更快,是因为:

  • 它使用香草JavaScript
  • 它使用正确的dom操作(没有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);

如果要确保重复(在“参与”情况下会导致重复),则可以在推入数组之前将字符串设置为小写,并在再次推入之前检查数组是否存在字符串。