使用regExp

时间:2016-10-11 21:20:37

标签: javascript regex

我们都知道regExp可以使用两个字符串中的公共字匹配两个字符串作为匹配的标准。此代码将匹配&#34;我喜欢苹果&#34; &#34; 苹果&#34; < / em>因为他们都有&#34;苹果&#34;共同的。

var str1 = "apples";
var test1 = "I like apples";
var reg1 = new RegExp(str1, "i");

if (test1.match(reg1)) {
    console.log(str1 + " is matched");
}

但是如果不使用单个公共字(或字符串的公共部分)匹配字符串,我需要使用多个常用字匹配两个字符串,这些字可能被其他字分开?让我举个例子:

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

棘手的部分是,我无法知道字符串是什么,所以我必须动态匹配它们。我不知道的字符串是用户输入字段的值,并且有许多可能性。此值将与存储在此对象中的字符串匹配:

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

因此无论输入字段中的用户类型如何,当且仅当它包含其中一个对象属性的所有单词时,它必须是匹配的。因此,在此示例中,&#34; 多汁 红色和成熟水果 &#34;应匹配第二个对象属性,因为它包含所有关键字。

编辑:我的目标是输出与我匹配的字符串相关联的值。在我的例子中,如果第一个键匹配,那么&#39; fruits&#39;应该输出。如果多汁的水果&#39;匹配,它应该输出价格:10美元&#39;。获取与对象键关联的字符串是用户必须使用输入搜索它们的原因。

使用纯JavaScript可以使用regExp执行此操作吗?

这是我(很差)试图做的事情:https://jsfiddle.net/Hal_9100/fzhr0t9q/1/

2 个答案:

答案 0 :(得分: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>

更新 要使用此类实现来搜索属性,请使用如下所示的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
};

答案 1 :(得分:0)

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

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

希望这有帮助!