user3215374
user3215374

Reputation: 47

typescript Yup validation or condition with regex using matches problem

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

Valid case:

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)

Upvotes: 0

Views: 1201

Answers (2)

Cooper
Cooper

Reputation: 64040

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;
}

Upvotes: 0

The fourth bird
The fourth bird

Reputation: 163267

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.

Upvotes: 1

Related Questions