7

I want to make sure users don't fill in their username (pattern is a upercase or lowercase u, followed by 7-10 digits: U0000000)

In the following example, the regex itself does work. However in conjunction with the .matches() method it does not validate the field.

const schema = Yup.object()
  .shape({
    myField: Yup.string()
      .matches(/.*\d/, 'Should contain a digit') // <- this works
      .matches(/(?!.*[uU]\d{7,10})/, 'Should not contain a user ID') // <- this does not
  });
Remi
  • 4,663
  • 11
  • 49
  • 84

2 Answers2

18

Turns out that matches will only validate an invalid error if the Regex you provide returns positive.

If you want to validate on a negative 'match' (a.k.a. not operator regex match), you can use the .test() method.

In the documentation it's not mentioned under string, but under mixed (source):

mixed.test(name: string, message: string | function, test: function): Schema

So in my example I ended up with:

const containsDeviceId = (string) => /d\d{7,10}/.test(string);
const schema = Yup.object()
  .shape({
    myField: Yup.string()
      .matches(/.*\d/, 'Should contain a digit')
      .test(
        'Should not contain a user ID',
        'Should not contain a user ID',
        (value) => !containsDeviceId(value)
      ),

Hope this helps someone.

Remi
  • 4,663
  • 11
  • 49
  • 84
1

Adding to the "negate regex match" discussion here to show another example.

Yes, you can use Yup.matches() if your regex is formed using the negative lookup feature for regular expressions. For example, if I do not want to select an option from a radio group that has the word "prefer" in it:

const testYum = () => {
  // Regex pattern matches if pattern is not in the value.
  // The 'im' option at end of regex is to (i)gnore case and
  // search over (m)ultiple lines in the value. Starts at beginning
  // of line.
  const notDeviceIdPattern = /^(?!.*[uU]\d{7,10}).*/im;

  const yupToTest = Yup.object().shape({
    password: Yup.string()
      .required("This is needed")
      .matches(/.*\d/, "Should contain a digit")
      .matches(notDeviceIdPattern, "Do not embed device id")
  });

  // Change this to pattern to test.
  const testPassword = { password: "sddsfasf" };

  yupToTest
    .validate(testPassword)
    .then(function (value) {
      alert("Valid password: " + JSON.stringify(value, null, 2));
    })
    .catch(function (err) {
      alert("Invalid password: " + JSON.stringify(err.errors, null, 2));
    });
};


I hope this helps someone. One of the better discussion on this topic can be found here: https://regexland.com/regex-match-all-except