Home > Software engineering >  typescript Yup validation or condition with regex using matches problem
typescript Yup validation or condition with regex using matches problem

Time:04-01

I'm trying to make sure only one type of special character (semi-colon, comma, or space) is used in a string.

Valid case:

  • Can contain alphanumeric letters and numbers
  • Can contain special characters : / .
  • Can contain only one type of special characters from: space, semi-colon or comma in the string

e.g this should match as it only uses one type of special character (semi-colon): https://hello.com/example1;https://hello.com.com/example2;https://hello.com.com/example3

This should fail as it mixes two types of special characters (space and semi-colon)

https://hello.com/example1; https://hello.com.com/example2 ;https://hello.com.com/example3

This is my code:

const myValidation = yup
.string()
.matches(/^([A-Za-z0-9://,\\.]|[A-Za-z0-9:// \\.]|[A-Za-z0-9://;\\.]) $/, 'Please separate each with a comma, space or semicolon')
.required();

When i only have /^([A-Za-z0-9://,\\.] $/ it works correctly to only match the string if it has a only a comma as special character: https://hello.com/example1,https://hello.com.com/example2,https://hello.com.com/example3

but as soon as i add the other or conditions /^([A-Za-z0-9://,\\.]|[A-Za-z0-9:// \\.]|[A-Za-z0-9://;\\.]) $/ it starts allowing for semi-colon and space and comma special characters in the string at the same time (the invalid case)

CodePudding user response:

For the valid cases, you can use a capture group with a backreference \1 to make sure that the "special character" is the same delimiter between the matches

^[A-Za-z0-9:/.] (?:([ ,;])[A-Za-z0-9:/.] (?:\1[A-Za-z0-9:/.] )*)?$

The pattern matches:

  • ^ Start of string
  • [A-Za-z0-9:/.] Match 1 of the allowed characters
  • (?: Non capture group to match as a whole part
    • ([ ,;]) Capture group 1, match one of the delimiters
    • [A-Za-z0-9:/.] Match 1 of the allowed characters
    • (?:\1[A-Za-z0-9:/.] )* Optionally repeat a backreference to the same delimiter and again 1 of the allowed characters
  • )? Close the non capture group and make it optional
  • $ End of string

See a regex demo.

const regex = /^[A-Za-z0-9:/.] (?:([ ,;])[A-Za-z0-9:/.] (?:\1[A-Za-z0-9:/.] )*)?$/;
[
  "https://hello.com/example1;https://hello.com.com/example2;https://hello.com.com/example3",
  "https://hello.com/example1; https://hello.com.com/example2 ;https://hello.com.com/example3",
  "https://hello.com/example1"
].forEach(s =>
  console.log(`${regex.test(s)} --> ${s}`)
);


If there should be at least a single delimiter present, you could shorten the pattern to:

^[A-Za-z0-9:/.] ([ ,;])[A-Za-z0-9:/.] (?:\1[A-Za-z0-9:/.] )*$

If the strings should start with http:// or https:// you could use:

^https?:\/\/[A-Za-z0-9:/.] (?:([ ,;])https?:\/\/[A-Za-z0-9:/.] (?:\1[A-Za-z0-9:/.] )*)?$

See another regex demo.

CodePudding user response:

Is only one

function isOnlyOne() {
  let s = "zy,,aemnofgbcjkhilpqasdfrstuvrhfwx";
  console.log([...new Set(s.split("").filter(e => e.match(/[;, ]/)))].length==1);
  //return [...new Set(s.split("").filter(e => e.match(/[a-z]/)))].length==26;
}
  • Related