I am trying to validate a string to ensure it only contains certain characters using a function in my TypeScript project. The function takes a string and an options object as arguments, with the options specifying which characters are allowed.
Here’s the function:
/**
* 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);
};
Here is jest test:
it('should return true when name is valid and allowSpecialCharacters is true', () => {
expect(validateName('Deri!', { allowSpecialCharacters: true })).toBe(true);
});
and here is error test:
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.
However, I keep getting an "invalid escape" error when I try to use the function, even though I’ve escaped all the special characters. Can anyone tell me what I’m doing wrong? Thanks!
answer explanation and a correct RegExp code
3
Answers
Some of your escaped characters are not specials in JavaScript. When you use Unicode mode with
u
flag, you cannot escape non-special characters "just in case". This is forbidden to ensure the possibility to add special escape sequences in future.Compare:
So you only need to escape
[ ^ $ . | ? * + ( )
, or even less inside[]
.See https://javascript.info/regexp-escaping and https://javascript.info/regexp-character-sets-and-ranges#escaping-in- .
If you run this in the browser you will get the same
the problem is you have specified – /u
Which means its expecting backslash characters to preceed with the u like this
this works:
The problem seems to be with the
'u'
option. Don’t know exactly what changes with that (other than allowing unicode escapes) but it seems like it treats escape characters a bit differently.The thing is inside
[]
you don’t need to escape special characters, with a few exceptions. Also, to write raw strings i Javascript you can useString.raw``
.So this should work: