javascript 允许特殊字符选项时出错正则表达式转义无效

gopyfrb3  于 2023-03-28  发布在  Java
关注(0)|答案(3)|浏览(133)

我正在尝试使用TypeScript项目中的函数验证字符串,以确保它只包含某些字符。该函数以字符串和选项对象作为参数,选项指定允许哪些字符。
函数如下:

/**
 * Validates a string to ensure it only contains allowed characters.
 * @param {string} name - The string to validate.
 * @param {Object} [options] - The options to use for validation.
 * @param {boolean} [options.allowNumbers=false] - Whether to allow numbers.
 * @param {boolean} [options.allowSpecialCharacters=false] - Whether to allow special characters.
 * @param {boolean} [options.allowSpaces=false] - Whether to allow spaces.
 * @param {boolean} [options.allowUnderscores=false] - Whether to allow underscores.
 * @param {boolean} [options.allowDashes=false] - Whether to allow dashes.
 * @param {boolean} [options.allowPunctuation=false] - Whether to allow punctuation.
 * @param {boolean} [options.allowCyrillic=false] - Whether to allow Cyrillic characters.
 * @param {boolean} [options.allowNonLatin=false] - Whether to allow non-Latin characters.
 * @returns {boolean} Whether the string is valid or not.
 */
interface IValidateNameOptions {
  allowNumbers?: boolean;
  allowSpecialCharacters?: boolean;
  allowSpaces?: boolean;
  allowUnderscores?: boolean;
  allowDashes?: boolean;
  allowPunctuation?: boolean;
  allowCyrillic?: boolean;
  allowNonLatin?: boolean;
}

interface IValidateName {
  (name: string, options?: IValidateNameOptions): boolean;
}

export const validateName: IValidateName = (
  name,
  options = {
    allowNumbers: false,
    allowSpecialCharacters: false,
    allowSpaces: false,
    allowUnderscores: false,
    allowDashes: false,
    allowPunctuation: false,
    allowCyrillic: false,
    allowNonLatin: false,
  },
) => {
  let regexStr = `^[a-zA-Z`;

  if (options.allowNonLatin) {
    regexStr += `\\p{L}`;
  }
  if (options.allowNumbers) {
    regexStr += `0-9`;
  }
  if (options.allowSpecialCharacters) {
    regexStr += `\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\-\\_\\=\\+\\[\\]\\{\\}\\|\\\\\\;\\:\\'\\,\\.\\/\\<\\>\\?`;
  }
  if (options.allowSpaces) {
    regexStr += `\\s`;
  }
  if (options.allowUnderscores) {
    regexStr += `\\_`;
  }
  if (options.allowDashes) {
    regexStr += `\\-`;
  }
  if (options.allowPunctuation) {
    regexStr += `\\p{P}`;
  }
  if (options.allowCyrillic) {
    regexStr += `\\p{Cyrillic}`;
  }
  regexStr += `]+$`;

  const regex = new RegExp(regexStr, 'u');
  return regex.test(name);
};

下面是jest测试:

it('should return true when name is valid and allowSpecialCharacters is true', () => {
  expect(validateName('Deri!', { allowSpecialCharacters: true })).toBe(true);
});

这里是错误测试:

FAIL  src/tests/validateName.test.ts
  ✓ should return true when name is valid (3 ms)
  ✓ should return false when name is invalid (6 ms)
  ✕ should return true when name is valid and allowSpecialCharacters is true (2 ms)

  ● should return true when name is valid and allowSpecialCharacters is true

    SyntaxError: Invalid regular expression: /^[a-zA-Z\!\@\#\$\%\^\&\*\(\)\-\_\=\+\[\]\{\}\|\\\;\:\'\,\.\/\<\>\?]+$/: Invalid escape
        at new RegExp (<anonymous>)

      69 |   regexStr += `]+$`;
      70 |
    > 71 |   const regex = new RegExp(regexStr, 'u');
         |                 ^
      72 |   return regex.test(name);
      73 | };
      74 |

      at validateName (src/lib/validateName.ts:71:17)
      at Object.<anonymous> (src/tests/validateName.test.ts:41:22)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 2 passed, 3 total
Snapshots:   0 total
Time:        1.536 s
Ran all test suites.

然而,当我尝试使用该函数时,我总是得到一个“无效转义”错误,即使我已经转义了所有的特殊字符。有人能告诉我我做错了什么吗?谢谢!
答案解释和正确的RegExp代码

rsaldnfx

rsaldnfx1#

问题似乎出在'u'选项上。不知道它到底有什么变化(除了允许unicode转义),但它似乎对转义字符的处理有点不同。
[]中,除了少数例外,你不需要转义特殊字符。此外,要在Javascript中编写原始字符串,你可以使用`String.raw```。
所以这应该行得通:

if (options.allowSpecialCharacters) {
    regexStr += String.raw`!@#$%^&*()\-_=+[\]{}|\\;:',./<>?`;
}
bkkx9g8r

bkkx9g8r2#

如果你在浏览器中运行它,你会得到相同的结果

const reg1 = /^[a-zA-Z\!\@\#\$\%\^\&\*\(\)\-\_\=\+\[\]\{\}\|\\\;\:\'\,\.\/\<\>\?]+$/u
console.log(reg1)

问题是你已经指定了- /u,这意味着它需要反斜杠字符,像这样在u前面
这是可行的:

// \u003a === :
const reg = /\u003a/u
const matched = ' :'.match(reg)
console.log(matched)
wtlkbnrh

wtlkbnrh3#

有些转义字符在JavaScript中不是特殊字符。当你使用Unicode模式和u标志时,你不能转义非特殊字符“以防万一”。这是禁止的,以确保将来添加特殊转义序列的可能性。
比较:

console.log(/:/); // No errors.
console.log(/\:/); // No errors as there is no u flag.
console.log(/\:/u); // Throws error.

所以你只需要转义[ \ ^ $ . | ? * + ( ),或者在[]中更少。
参见https://javascript.info/regexp-escaping和https://javascript.info/regexp-character-sets-and-ranges#escaping-in-。

相关问题