Сопоставление только части регулярного выражения

#javascript #regex #mongodb

#javascript #регулярное выражение #mongodb

Вопрос:

Мне нужно отфильтровать список имен, используя regex .

Я сохранил данные в этом формате

 [
 {
  "firstName": "Jhon",
  "lastName": "Doe",
 },
 ...
]
 

Пользователь может ввести полное имя, имя или фамилию. Но мне нужно сопоставить их все. Мой запрос mongo выглядит следующим образом (я использовал Loopback 4 для создания этого запроса, но идея очевидна)

         {
          or: [{firstName: new RegExp(searchKey, 'i')}, {lastName: new RegExp(searchKey, 'i')}],
        };
 

Но это не соответствует, когда пользователь вводит jhon doe, но работает, когда вводится только имя или фамилия.

Мой вопрос в том, есть ли способ сопоставить часть строки с регулярным выражением?

ожидается, что будет возвращено успешное совпадение для всех «jhon», «doe», «jhon doe» и «jhondoe»

Комментарии:

1. searchKey.split(/s/g).join('|') ..?

2. Да, это решение. Но предположим, что пользователь вводит «jhondoe»??

3. Это не будет допустимой частью имени пользователя ни по каким критериям, следовательно, это должно завершиться неудачей. Вы могли бы добавить '|' searchKey в конец строки, чтобы включить также исходный ключ поиска, но я бы отказался от этой альтернативы.

4. Согласен, если это имена пользователей. но это имена пользователей, и требуется найти совпадающие имена. Мне нужно знать, может ли это быть реализовано с помощью каких-либо регулярных выражений. Кстати, ваш приведенный выше комментарий пока работал

5. Рассматривали ли вы текстовый индекс ?

Ответ №1:

Я не знаю, возможно ли написать общее регулярное выражение, которое может это сделать, я создал алгоритм грубой силы для построения регулярного выражения.

 let text = `[
    {
     "firstName": "Jhon",
     "lastName": "Doe",
    },
    ...
   ]`;

// Brute force
let key = "jhondoe";
let keyArr = [];
for (let i = 0; i < key.length; i  ) {
    let a = key.slice(0, i);
    let b = key.slice(i);
    a amp;amp; keyArr.push(a);
    b amp;amp; keyArr.push(b);
}
let keySearch = keyArr.join("|");
console.error(keySearch);
let regex = new RegExp(`"(?:first|last)Name": "(${keySearch})"`, `gim`);
let matches = text.match(regex);
console.log(matches); 

Комментарии:

1. ВАУ !!!!.. это грубо. вы можете получить неожиданные результаты, поскольку он также сравнивает каждую букву.. Но я понял, что мой вопрос заслуживает этого ответа. Я не уверен, должен ли я принять этот ответ или нет, но он правильный

2. Возможно, измените, чтобы принять целое слово, или, если это подстрока, вы должны сопоставить имя и фамилию одновременно.

Ответ №2:

Теперь я создал полный код, который учитывает несколько вещей. К сожалению, если у кого-то есть имя jhon doe, а у кого-то еще есть имя jhond oe, этот код примет его.

Основная идея состоит в том, чтобы проверить, является ли ключ именем ИЛИ фамилией. В противном случае, если оно содержит пробелы, все, что находится перед первым пробелом, является FirstName , а все, что после, — LastName . В противном случае, используя грубую силу, он проверяет все комбинации FirstName и LastName, левая подстрока — fisrtName, правая подстрока — LastName.

 let text = `[
    {
     "firstName": "Jhon",
     "lastName": "Doe",
    },
    ...
   ]`;

const nameValidator = (key, text) => {
  // Attempts to check whether the entire key received is a first or last name.
  let regexKey = new RegExp(`"(?:first|last)Name": "${key}"`, `gim`);
  if (regexKey.test(text)) {
    return true;
  } else if (key.includes(" ")) {
    // if the key has spaces, we already know the first and lastName
    // if the key has more than one space, everything after the first space goes to lastName
    let [_, a, b] = /^(w ) (.*)$/.exec(key);
    let regexFirstLastName = new RegExp(`"firstName": "${a}",(\s|\t|\n)*"lastName": "${b}",`, `gim`);
    if (regexFirstLastName.test(text)) {
      return true;
    }
  } else {
    // Search by brute force for the division between first and last name
    for (let i = 1; i < key.length; i  ) {
      let a = key.slice(0, i);
      let b = key.slice(i);
      console.log(`Trying name="${a}" and lastname="${b}"`);
      let regexFirstLastName = new RegExp(`"firstName": "${a}",(\s|\t|\n)*"lastName": "${b}",`, `gim`);
      if (regexFirstLastName.test(text)) {
        return true;
      }
    }
  }
  return false;
}

const keys = ["jhon", "doe", "jhon doe", "jhondoe", "auehuaheuahe"];

for (key of keys) {
  console.log(key, nameValidator(key, text));
  console.log("=======================n");
}