使用regExp动态匹配字符串中的多个单词与另一个单词

Dynamically match multiple words in a string to another one using regExp

本文关键字:单词 另一个 动态 regExp 字符串 使用      更新时间:2023-09-26

我们都知道regExp可以使用两个字符串中的共同单词作为匹配标准来匹配两个字符串。这段代码将把"I like apples""apples"匹配起来,因为它们都有相同的"apples"。

var str1 = "apples";
var test1 = "I like apples";
var reg1 = new RegExp(str1, "i");
if (test1.match(reg1)) {
    console.log(str1 + " is matched");
}

但是,如果不是使用单个公共单词(或字符串的公共部分)匹配字符串,而是需要使用多个可能被其他单词分隔的公共单词匹配两个字符串,该怎么办?让我给你看一个例子:

test2 = "我喜欢多汁的红色水果"应该匹配str2 = "多汁的水果",因为test2包含了所有str2第二关键词(见下面的对象),即使它之间有其他单词。

棘手的部分是,我不能确切地知道哪个字符串将是,所以我必须动态匹配它们。我不知道的字符串是用户输入字段的值,有很多可能性。该值将与存储在该对象中的字符串匹配:

var str2 = {
    "red apples": "fruits",
    "juicy fruits": "price : $10"
};

因此,无论用户在输入字段中键入什么,当且仅当它包含一个对象属性的所有单词时,它必须是匹配的。所以在这个例子中,"多汁的红色和成熟的水果"应该匹配第二个对象属性,因为它包含了它的所有关键字。

编辑:我的目标是输出与我匹配的字符串相关的值。在我的例子中,如果第一个键匹配,应该输出'fruits'。如果匹配"多汁的水果",它应该输出"price: $10"。获取与对象键相关联的字符串是用户必须使用输入来搜索它们的原因。

是否可以使用纯javascript实现regExp ?

这是我(糟糕的)尝试做的:https://jsfiddle.net/Hal_9100/fzhr0t9q/1/

对于您所描述的情况,您甚至不需要正则表达式。如果你用空格分割搜索字符串;您可以检查每个要匹配的单词是否包含在搜索词数组中。

function matchesAllWords(searchWords, inputString) {
  var wordsToMatch = inputString.toLowerCase().split(' ');
  return wordsToMatch.every(
    word => searchWords.indexOf(word) >= 0);
}

在下面的代码片段中,输入input会导致searchWords的重新计算。然后给予匹配的li元素.match类以突出显示它们。

function updateClasses(e) {
  var searchWords = e.target.value.toLowerCase().split(' ');
  listItems.forEach(listItem => listItem.classList.remove('match'));
  listItems.filter(
      listItem =>
      matchesAllWords(searchWords, listItem.innerText))
    .forEach(
      matchingListItem =>
      matchingListItem.classList.add('match'));
}
function matchesAllWords(searchWords, inputString) {
  var wordsToMatch = inputString.toLowerCase().split(' ');
  
  return wordsToMatch.every(
    word => searchWords.indexOf(word) >= 0);
}
function searchProperties(e) {
  var searchWords = e.target.value.toLowerCase().split(' ');
  for (var property in propertiesToSearch) {
    if (matchesAllWords(searchWords, property)) {
      console.log(property, propertiesToSearch[property]);
    }
  }
}
var propertiesToSearch = {
  "red apples": 1,
  "juicy fruit": 2
};
listItems = [].slice.call(
  document.getElementById('matches').querySelectorAll('li')
);
document.getElementById('search').addEventListener('keyup', updateClasses);
document.getElementById('search').addEventListener('keyup', searchProperties);
.match {
  color: green;
}
<label for="search">
  Search:
</label>
<input type="text" name="search" id="search" />
<ul id="matches">
  <li>red apples</li>
  <li>juicy fruits</li>
</ul>

Update要使用这种实现来搜索属性,请使用如下所示的for .. in循环。同样,请参见在上下文中工作的代码片段。

function searchProperties(e) {
  var searchWords = e.target.value.toLowerCase().split(' ');
  for (var property in propertiesToSearch) {
    if (matchesAllWords(searchWords, property)) {
      console.log(property, propertiesToSearch[property]);
    }
  }
}
var propertiesToSearch = {
  "red apples": 1,
  "juicy fruit": 2
};

我认为您可能会受益于将数据结构从对象文字转换为数组,如下所示:

const wordGroupings = [
  'red apples',
  'juicy fruits'
];

我编写了一个processString函数,它接受一个字符串和一些单词分组作为输入,并返回一个经过过滤的单词分组列表,其中单词分组中的每个单词都出现在输入字符串中。

换句话说,让我们假设测试字符串是:
const testString = 'I like big, frozen whales.';

让我们进一步想象你的wordGroupings数组看起来像这样:

const wordGroupings = [
  'whales frozen',
  'big frozen whales toucan',
  'big frozen',
  'sweaty dance club',
  'frozen whales big'
]

调用processString(wordGroupings, testString)的输出将是:

[
  'whales frozen',
  'big frozen',
  'frozen whales big'
]

如果这是你正在寻找的,这里是processString(..)的实现:

function processString(wordGroupings, testString) {
  var regexes = wordGroupings.map(words => ({
      origString: words,
      regex: new RegExp(words.replace(/'s+/g, '|'), 'g'),
      expCount: words.split(/'s+/g).length
    })
  );
  filtered = regexes.filter(({regex, expCount}) =>
    (testString.match(regex) || []).length === expCount
  );
  return filtered.map(dataObj => dataObj.origString);
}

希望这对你有帮助!

相关文章: