6
\$\begingroup\$

Using VB.NET, I have created an AddIn for Autodesk Inventor and the customer has a bunch of drawing number strings which follow this sort of scheme:

  1. P01867-13-TP09-001-4950-1775-1175-895-1125-835
  2. P01867-13-TP09-002-4950-1775-1045-895-1035
  3. P01867-13-TP02-019-L-1137-275-852-102
  4. P01867-13-TP02-019-L-1137-275-852-102
  5. P01867-13-TP02-019-R-1137-275-852-102
  6. P01867-13-TP02-021-L-1137-1055-1372
  7. P01867-13-TP02-021-L-1137-535-1027
  8. P01867-13-TP02-021-L-1137-795-1184
  9. P01867-13-TP02-021-R-1137-1055-1372
  10. P01867-13-TP02-021-R-1137-535-1027
  11. P01867-13-TP02-021-R-1137-795-1184
  12. P01867-13-TP02-025-L-1137-1315-1581
  13. P01867-13-TP02-025-R-1137-1315-1581
  14. P01867-13-TP03-005
  15. P01867-13-TP02-019-L-1137-275
  16. P01867-13-TP02-019-R-1137-275
  17. P01867-13-TP02-019-R-1137
  18. P01867-13-TP02-019-L-1137

In order to account for these groups of three digits within the variations I have created the following regex:

(\w*\d*-\d*-\w*\d*-\d*-\w-)(\d*)-(\d*)-(\d*)-(\d*)-(\d*)|(\w*\d*-\d*-\w*\d*-\d*-\w-)(\d*)-(\d*)-(\d*)-(\d*)|(\w*\d*-\d*-\w*\d*-\d*-\w-)(\d*)-(\d*)-(\d*)|(\w*\d*-\d*-\w*\d*-\d*-\w-)(\d*)-(\d*)|(\w*\d*-\d*-\w*\d*-\d*-\w-)(\d*)|(\w*\d*-\d*-\w*\d*-\d*-)(\d*)-(\d*)-(\d*)-(\d*)-(\d*)|(\w*\d*-\d*-\w*\d*-\d*-)(\d*)-(\d*)-(\d*)-(\d*)|(\w*\d*-\d*-\w*\d*-\d*-)(\d*)-(\d*)-(\d*)|(\w*\d*-\d*-\w*\d*-\d*-)(\d*)-(\d*)|(\w*\d*-\d*-\w*\d*-\d*-)(\d*)|(\w*\d*-\d*-\w*\d*-\d*)|.*(\w*\d*-\d*-)(\d*)-(\d*)-(\d*)-(\d*)-(\d*)|.*(\w*\d*-\d*-)(\d*)-(\d*)-(\d*)-(\d*)|.*(\w*\d*-\d*-)(\d*)-(\d*)-(\d*)|.*(\w*\d*-\d*-)(\d*)-(\d*)|.*(\w*\d*-\d*-)(\d*)|.*(\w*\d*-\d*-\w-)(\d*)-(\d*)-(\d*)-(\d*)-(\d*)|.*(\w*\d*-\d*-\w-)(\d*)-(\d*)-(\d*)-(\d*)|.*(\w*\d*-\d*-\w-)(\d*)-(\d*)-(\d*)|.*(\w*\d*-\d*-\w-)(\d*)-(\d*)|.*(\w*\d*-\d*-\w-)(\d*)

I now have to add the capability of looking for a sixth group of digits so figured I would ask here if there is a method within regex (which I may have overlooked) that will allow me to improve upon/simplify the above monster.

\$\endgroup\$

1 Answer 1

10
\$\begingroup\$

^P\d{5}-13-TP\d{2}-\d{3}(-(L|R|\d{4})(-\d{3,4})*)?$

Your current regex is WAY too forgiving. First of all, every one of your example starts with a P followed by some numbers, but you accept ANY COMBINATION of letters at the beginning. I'm assuming that ALEX01867-13-TP02-019-L-1137 isn't a valid key, so you should take steps to reject it by using hungry quantifiers as little as possible (*, +). Using \d{3,4} matches a digit between 3 and 4 times, so that will let you limit the sort of input you accept.

The same goes for the 5th group - according to your examples, it's either L, R, or 4 digits. In Regex, that looks like this: (L|R|\d{4})

Next, you are using alternation (option1|option2) to capture the different "forms" your string comes in as, but you are repeating a bunch of stuff (for example, the \w*\d* at the beginning). You can limit the scope of the alternation by surrounding it in brackets (()). You can see this in action with the (L|R|\d{4}) example - that whole bracket group becomes a single token that matches somewhere in a string (or doesn't).

Sometimes the string ends after the 4th group (Before the L/R group), and sometimes it doesn't. Instead of using alternation to solve this, which makes the regex VERY long, you can just surround the entire regex AFTER that point in brackets with a question mark (an-(example)?). This makes the entire second part optional.

Finally, your problem asks if there is a simple method to improve the regex. By ending it in (-\d{3,4})* you can match ANY length of additions to the end, assuming the all come in the form -015 or -1992 or whatever. If you knew that there was always a max of 15 numbers added to the end, you could change that star (*) to a max quantifier ({,15}). If sometimes the number only has two digits, change the {3,4} to {2,4}, etc.

See it in action here

\$\endgroup\$
4
  • \$\begingroup\$ Thanks for the explanation/solution @devon-parsons! I do need to group each of the three-digit strings into groups in order to be able to retrieve Dimension A, B, C, D etc. from the strings that continue after the L or R values - does that make sense? \$\endgroup\$ Commented Oct 16, 2015 at 13:15
  • \$\begingroup\$ With repeated groups, you can only capture the final group that gets captured - so currently, your first line would capture -835. If you need ALL of them, you can capture EVERYTHING after the L/R by putting brackets around it and using your programming language of choice to split on the - characters to get the different groups. \$\endgroup\$ Commented Oct 16, 2015 at 14:06
  • \$\begingroup\$ To be clear, that means you would surround (-\d{3,4})* with brackets to make the entire string read ^P\d{5}-13-TP\d{2}-\d{3}(-(L|R|\d{4})((-\d{3,4})*))?$. One of the capture groups will look like -001-002-003-004 etc. if you feel like it, look up non-capturing groups (?:) to tidy it up. \$\endgroup\$ Commented Oct 16, 2015 at 14:10
  • 1
    \$\begingroup\$ So I have cobbled together this: (?'DrawingNumber'^P\d{5}-\d{2}-TP\d{2}-\d{3})-?(?'Hand'L|R)?-?(?'Dimensions'(-?\d{2,})*)-?(?'Type'1|2)?$ based on your suggestions which looks like it can account for the Drawing Number, Hand (if one exists), the Dimensions if applicable and lastly a type (1 or 2) if applicable - regex101.com/r/eF3hC1/2 - Thanks again! \$\endgroup\$ Commented Oct 16, 2015 at 14:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.