like-to-regexp.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. import {InvalidArgumentError} from '../errors/index.js';
  2. /**
  3. * Преобразует SQL LIKE-шаблон в объект RegExp.
  4. *
  5. * Экранирует специальные символы регулярных выражений,
  6. * чтобы они обрабатывались как обычные символы, и преобразует
  7. * SQL wildcards (% и _) в их эквиваленты в регулярных выражениях.
  8. *
  9. * @param {string} pattern
  10. * @param {boolean} isCaseInsensitive
  11. * @returns {RegExp}
  12. */
  13. export function likeToRegexp(pattern, isCaseInsensitive = false) {
  14. if (typeof pattern !== 'string') {
  15. throw new InvalidArgumentError(
  16. 'The first argument of `likeToRegexp` ' +
  17. 'should be a String, but %v was given.',
  18. pattern,
  19. );
  20. }
  21. // символы, которые имеют специальное значение
  22. // в RegExp и должны быть экранированы
  23. const regexSpecials = '-[]{}()*+?.\\^$|';
  24. let regexString = '';
  25. let isEscaping = false;
  26. // экранирование
  27. for (const char of pattern) {
  28. if (isEscaping) {
  29. // предыдущий символ был '\', значит текущий символ - литерал
  30. regexString += regexSpecials.includes(char) ? `\\${char}` : char;
  31. isEscaping = false;
  32. } else if (char === '\\') {
  33. // символ экранирования, следующий символ будет литералом
  34. isEscaping = true;
  35. } else if (char === '%') {
  36. // SQL wildcard: любое количество любых символов
  37. regexString += '.*';
  38. } else if (char === '_') {
  39. // SQL wildcard: ровно один любой символ
  40. regexString += '.';
  41. } else if (regexSpecials.includes(char)) {
  42. // экранирование других специальных символов RegExp
  43. regexString += `\\${char}`;
  44. } else {
  45. // обычный символ
  46. regexString += char;
  47. }
  48. }
  49. // если строка заканчивается на экранирующий символ,
  50. // считаем его литералом.
  51. if (isEscaping) {
  52. regexString += '\\\\';
  53. }
  54. const flags = isCaseInsensitive ? 'i' : '';
  55. return new RegExp(`^${regexString}$`, flags);
  56. }