简体   繁体   中英

How to match two non-consecutive words in a String for React/Javascript search?

I have a search bar which relies on this filter method. I concatenate all the search strings in a variable concat , and then use either .includes() or .match() as shown below. If searched for multiple words, this only returns a result if the words occur consecutively in concat .

However, I want it to match ANY two words in concat , not just consecutive ones. Is there a way to do this easily?

    .filter((frontMatter) => {
      var concat =
        frontMatter.summary +
        frontMatter.title +
        frontMatter.abc+
        frontMatter.def+
        frontMatter.ghi+
        frontMatter.jkl;
      return concat.toLowerCase().match(searchValue.toLowerCase());
    });

Also tried;

    .filter((frontMatter) => {
      const concat =
        frontMatter.summary +
        frontMatter.title +
        frontMatter.abc+
        frontMatter.def+
        frontMatter.ghi+
        frontMatter.jkl;
      return concat.toLowerCase().includes(searchValue.toLowerCase());
    });

Thanks!

Everything is explained in the comments of the code.

If you don't care that "deter" matches the word "undetermined"

.filter((frontMatter) => {
  // Get the front matter into a string, separated by spaces
  const concat = Object.values(frontMatter).join(" ").toLowerCase();

  // Look for a string in quotes, if not then just find a word
  const regex = /\"([\w\s\\\-]+)\"|([\w\\\-]+)/g;

  // Get all the queries
  const queries = [...searchValue.toLowerCase().matchAll(regex)].map((arr) => arr[1] || arr[2]);

  // Make sure that every query is satisfied
  return queries.every((q) => concat.includes(q));
});

If you DO care that "deter" should NOT match the word "undetermined"

.filter((frontMatter) => {
  // Get the front matter into a string, separated by spaces
  // The prepended and appended spaces are important for the regex later!
  const concat = ` ${Object.values(frontMatter).join(" ").toLowerCase()} `;

  // Look for a string in quotes, if not then just find a word
  const regex = /\"([\w\s\\\-]+)\"|([\w\\\-]+)/g;

  // Get all the queries
  const queries = [...searchValue.toLowerCase().matchAll(regex)].map((arr) => arr[1] || arr[2]);

  // Make sure that every query is satisfied
  // [\\s\\.?!_] and [\\s\\.?!_] check for a space or punctuation at the beginning and end of a word
  // so that something like "deter" isn't matching inside of "undetermined"
  return queries.every((q) => new RegExp(`[\\s\\.?!_]${q}[\\s\\.?!_]`).test(concat));
});

I'd use .reduce to count up the number of matches, and return true if there are at least 2:

const props = ['summary', 'title', 'abc', 'def', 'ghi', 'jkl'];
// ...
.filter((frontMatter) => {
  const lowerSearch = searchValue.toLowerCase();
  const matchCount = props.reduce(
    (a, prop) => a + lowerSearch.includes(frontMatter[prop].toLowerCase()),
    0
  );
  return matchCount >= 2;
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM