ghostagent151
ghostagent151

Reputation: 1396

Modify this yup validation to change max length to 9 if the string does not include a dash

I'm trying to write a yup validator that validates a field's max length, depending on whether a dash is included in the string. If a dash is included, the max length is 10, if there is no dash, the max length should be 9.

For example:

'string-111' should have a max length of 10.

'string111' should have a max length of 9.

My current code looks like:

import * as Yup from 'yup';

export default Yup.object().shape({
  description: Yup.string()
    .matches(
      /^[a-zA-Z0-9-]*$/,
      'Invoice # can only contain letters, numbers and dashes'
    )
    .max(10, 'Invoice # has a max length of 10 characters'),
});

I see the yup documentation https://github.com/jquense/yup has a .when() method, but it seems to be used in very specific cases in their examples. Here, the user can place the dash anywhere in the string.

Any ideas on how to rewrite this validator, so that when there is no dash in the string, the maxlength should be 9?

Upvotes: 0

Views: 5853

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110675

I worked up a solution I liked but found it had already been posted by @Thefourthbird, so I tried a different tack and came up with this:

/^(?=(?:-*[^-]-*){9}$)(?=(?:[^-]*-[^-]*){0,1}$).*/gm

You can see that this regex contains two positive lookaheads, both beginning at the start of a line. The first ensures that the string contains 9 non-hyphens; the second requires that there be at most one hyphen.

demo

The demo provides a detailed and thorough explanation of how this regex works, but we can also make it self-documenting by writing it in free-spacing mode:

/
^                      # match beginning of string
(?=                    # begin a positive lookahead
  (?:-*[^-]-*){9}      # match 9 strings, each with one char that is
                       # not a hyphen, possibly preceded and/or
                       # followed by hyphens
  $                    # match the end of a line
)                      # end positive lookahead

(?=                    # begin a positive lookahead
  (?:[^-]*-[^-]*){0,1} # match 0 or 1 strings, each containing one hyphen, 
                       # possibly preceded and/or followed by non-hyphens
  $                    # match the end of the string
)                      # end positive lookahead

.*                     # match 0+ characters (the entire string)
/gmx                   # global, multiline and free-spacing regex
                       # definition modes

If desired, [^-] could replaced with [a-zA-Z0-9], \p{Alnum} or something else, depending on requirements.

Upvotes: 1

The fourth bird
The fourth bird

Reputation: 163237

You could match either match 10 chars where a hyphen can occur at any place using a positive lookahad, or match 9 chars consisting only of a-z0-9.

^(?:(?=[a-z0-9-]{10}$)[a-z0-9]*-[a-z0-9]*|[a-z0-9]{9})$

Explanation

  • ^ Start of string
  • (?: Non capture group
    • (?= Positive lookahead, assert what is on the right is
      • [a-z0-9-]{10}$ Match 10 times either a-z0-9 or - till the end of the string
    • ) Close lookahead
    • [a-z0-9]*-[a-z0-9]* Match a hyphen between chars a-z0-9
    • | Or
    • [a-z0-9]{9} Match 9 chars a-z0-9
  • ) Close group
  • $ End of string

Regex demo

Upvotes: 2

Related Questions