Регулярное выражение с необязательными точками в буквенно-цифровой строке

#javascript #regex #alphanumeric

#javascript #регулярное выражение #буквенно-цифровое

Вопрос:

Я пытаюсь написать регулярное выражение, соответствующее фиксированной буквенно-цифровой строке, которая может содержать точки.
Это регулярное выражение должно соответствовать всем символам, кроме точек. Мне нужно было бы использовать это в Javascript search() для сравнения двух строк. Слово для поиска: 30A10Z20

Все они соответствуют действительности:

 30A1.0Z2.0
30A.10Z20
3.0.A10.Z20
3.0.A.1.0.Z.2.0.
 

Я написал это, но безуспешно:

 ^30A10Z20\.{0,1}?$
^30A10Z20\.?$
^30A10Z20(?=\.)
 

Любые подсказки или помощь будут очень признательны.

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

1. Было бы проще, если бы вы просто заменили все точки, а затем проверили, равна ли строка 30A10Z20 .

2. @Sweeper прав, иначе вам пришлось бы поставить .? после каждого символа…

3. 30A...............10Z20 Также допустимо?

4. @georg да, это допустимо

5. @Sweeper Я думал об этом, но для меня это нехорошо. 30A10Z20 — это всего лишь часть конечной строки (например, «30A10Z20 Lorem Ipsum 3324»), и я должен соответствовать только тому, что я упомянул, чтобы я мог отформатировать его с помощью HTML-тегов (жирный шрифт). Оно должно содержать точки там, где они есть.

Ответ №1:

Я не уверен, что a RegExp будет лучшим способом сделать то, что, я полагаю, вы хотите сделать (основываясь на ваших комментариях: попробуйте переформулировать свой вопрос). Будет ли этот фрагмент хорошей идеей?

 const findTerm = (word, searchTerm) => 
  word.replace(/[^a-z0-9]/gi, "") === searchTerm;

const aFewStrings = [
  `something 30A1.0Z2.0 etc`,
  `30A.10Z20 hithere`,
  `Hello 3.0.A10.Z20`,
  `The value 3.0.....A.1.0....Z.2.0. may be valid`,
  `As may be the value 3.0@@@A.1.0#amp;!'Z.2.0.`,
  `Bye 3.0.A.1.0.Z.2.0. ended`,
];

aFewStrings.forEach(s => {
  const words = s.split(" ").map( w => findTerm(w, "30A10Z20") ? `<b>${w}</b>` : w );
  console.log(words.join(" "));
}); 

Если вам нужны части строки (см. Ваш комментарий), вам нужно выполнить небольшой синтаксический анализ. Что — то вроде:

 const findTerm = (word, searchTerm) =>
  RegExp(`(${searchTerm})`, "i").test(word.replace(/[^a-z0-9]/gi, ""));

const toBold = (word, searchTerm) => {
  const word2Parse = [...word];
  const wordPreserved = word2Parse.slice(0);
  const len = searchTerm.length;
  let foundIndices = [];
  let i = 0;

  while (word2Parse.length) {
    const noDots = word2Parse.slice(1).filter(v => !/[^a-z0-9]/i.test(v));
    const next = searchTerm.length > 1 amp;amp;  noDots[0] === searchTerm[1];
    const found = searchTerm.length > 1 
        ? word2Parse[0] === searchTerm[0] amp;amp; next
        : word2Parse[0] === searchTerm[0];
    
    searchTerm = found ? searchTerm.slice(1) : searchTerm;
    found amp;amp; foundIndices.push(i);
    i  = 1;
    word2Parse.shift();
  }


  wordPreserved[foundIndices[0]] = `<b>${wordPreserved[foundIndices[0]]}`;
  wordPreserved[foundIndices.slice(-1)] = `${
        wordPreserved[foundIndices.slice(-1)]}</b>`;
  return wordPreserved.join("");
}

const aFewStrings = [
  `something 30A1.0Z2.0 etc`,
  `30A.10Z20 hithere`,
  `Hello 3.0.A10.Z20`,
  `The value 3.0.....A.1.0....Z.2.0. may be valid`,
  `As may be the value 3.0@@@A.1.0#amp;!'Z.2.0.`,
  `Bye 3.0.A.1.0.Z.2.0. ended`,
  `3.0.A.1.0.Z.2.....0`,
];


const result = document.querySelector("#result");

let term = `30A1`;
result.appendChild(
  Object.assign(
    document.createElement("p"), {
      innerHTML: `[1 String, search '30A1']: ${
          (aFewStrings[3].split(" ")
            .map(w =>
                findTerm(w, term) ? toBold(w, term) : w)
            .join(" "))}`
    })
);

term = `notfound`;
result.appendChild(
  Object.assign(
    document.createElement("p"), {
      innerHTML: `[1 String, search 'notfound']: ${
          (aFewStrings[1].split(" ")
            .map(w =>
                findTerm(w, term) ? toBold(w, term) : w)
            .join(" "))}`
    })
);

term = `0Z20`;
aFewStrings.forEach(s => {
  const words = s.split(" ").map(w =>
    findTerm(w, term) ? toBold(w, term) : w);
  result.appendChild(
    Object.assign(
      document.createElement("div"), {
        innerHTML: words.join(" ")
      })
  );
}); 
 body {
  margin: 2rem;
  font: normal 12px/15px verdana, arial;
}

b {
  color: red;
} 
 <div id="result"></div> 

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

1. Это работает, очень приятно. Но есть ли способ заставить его работать только с частью строки? например, «30A1» —> <b> 30.A1</b> 0Z.20 или «Z20» —> 30.A.10<b> Z20</b>

2. Я полагаю, это можно сделать, но на самом деле это сложнее. Возможно, вы захотите упростить ввод (поэтому убедитесь, что точек там нет в первую очередь)

3. Я могу удалить точки на входе и провести сравнение. Но позже мне понадобится способ выделить текстовый формат жирным шрифтом только для того, что я нашел в первую очередь.