function inputIsValid(value) { var r = /(^[0-9]{4}$)|(^(?:(?:[X]{0,2}(?:[I](?:[XV]?|[I]{0,2})?|(?:[V][I]{0,3})?))|(?:[X]{3}[I]{0,3}))\-[AZ]{2}$)/ig; return value.match(r); }
This will correspond to either a 4-digit input or a Roman number (ranging from 1 to 33), followed by a dash and two letters.
To explain the regex, below is an extended source with comments:
// Test for a 4-digit number ( // Start required capturing group ^ // Start of string [0-9]{4} // Test for 0-9, exactly 4 times $ // End of string ) // End required capturing group | // OR // Test for Roman Numerals, 1 - 33, followed by a dash and two letters ( // Start required capturing group ^ // Start of string (?: // Start required non-capturing group // Test for 1 - 29 (?: // Start required non-capturing group // Test for 10, 20, (and implied 0, although the Romans did not have a digit, or mathematical concept, for 0) [X]{0,2} // X, optionally up to 2 times (?: // Start required non-capturing group // Test for 1 - 4, and 9 [I] // I, exactly once (I = 1) (?: // Start optional non-capturing group // IV = 4, IX = 9 [XV]? // Optional X or V, exactly once | // OR // II = 2, III = 3 [I]{0,2} // Optional I, up to 2 times )? // End optional non-capturing group | // OR // Test for 5 - 8 (?: // Start optional non-capturing group [V][I]{0,3} // Required V, followed by optional I, up to 3 times )? // End optional non-capturing group ) // End required non-capturing group ) // End required non-capturing group | // OR // Test for 30 - 33 (?: // Start required non-capturing group // Test for 30 [X]{3} // X exactly 3 times // Test for 1 - 3 [I]{0,3} // Optional I, up to 3 times ) // End required non-capturing group ) // End required non-capturing group // Test for dash and two letters \- // Literal -, exactly 1 time [AZ]{2} // Alphabetic character, exactly 2 times $ // End of string ) // End required capturing group
The 4-digit number and the end \-[AZ]{2} were (for me) taken for granted. My method for Roman numerals was as follows:
- Open Excel Customize column number 1-33.
- Convert this column to Roman numerals (in all 7 different versions).
- Check if any variety is different from 1-33 (they were not).
- Curling up with the movement of Roman numerals by the minimum number of unique patterns that limited them to 33 (that is, “then you will count to thirty-three, no more, no less.” Thirty-three will be the number you need to count, and the number of counts it’s thirty-three, but don’t count thirty-four, and count thirty-two, unless you go to thirty-three. Thirty-five is straight. ”)
- I realized that up to thirty-nine is one pattern (
^(([X]{0,3}([I]([XV]?|[I]{0,2})?|([V][I]{0,3})?)))$ , Which has been modified to capture groups for greater clarity). - Changed the template, allowing up to twenty-nine.
- Added one more to allow thirty to thirty nine.
- Build the entire template and test in RegexBuddy (a priceless tool for this material) with the numbers 0-20,000 and the Roman numbers 1 - 150 followed by "-AA".
- The sample worked, so I placed it (then I grabbed another cup of coffee and self-directed the “atta-boy” to complete what I thought was a wonderful morning morning challenge).
Extraneous brackets, I assume you mean non-capturing groups (?: ... ) . I use a lot to group things (and grouping is really needed here). I made them not exciting, because I do not need to capture subgroups, but only the parent groups (in which case I do not think that they really should be captured, but this does not interfere with this). Doing them without capturing them, they will not create backlinks that speed up processing (although for one input, the time received is negligible).