简体   繁体   中英

Regex lookbehind alternative for Safari

I have implemented this regex for matching a string for validation purposes: ^(?<serialCode>[a-zA-Z0-9]{0,3})(?:(?<serialMarket>[a-zA-Z]{1,2})(?<serialSuffix>(?<=^.{5})[a-zA-Z0-9]*)?)?

I'm using it in JS using match() function like this:

 const regex = '^(?<serialCode>[a-zA-Z0-9]{0,3})(?:(?<serialMarket>[a-zA-Z]{1,2})(?<serialSuffix>(?<=^.{5})[a-zA-Z0-9]*)?)?'; const stringToMatch = 'EV1FOO12FF344'; const result = stringToMatch.match(new RegExp(regex)); console.log(result); // returns each group for match and also the full match

What basically this does is that it's doing the following step by step validations and creating groups:

  • first 3 characters should be only alphanumeric characters
  • characters 4 and 5 should be only letters
  • all the rest of the characters should be alphanumeric characters

This validation is done for every typed value in an input field, character by character .

Using lookbehind as you can see above, this works perfectly for my purposes in Chrome and Mozilla Firefox browsers.

The problem : lookbehind (in current case (?<=^.{5}) ) is not supported on Safari browser as per this link: https://caniuse.com/js-regexp-lookbehind We receive this error in this case: Invalid regular expression: invalid group specifier name

Is there any alternative to that lookbehind so the regex will work in the exact same way?

I have the link where I tested some values for exemplification: https://regex101.com/r/fPmiTk/1 There you can see how the strings are matched and how the groups are created.

I doubt there is a way with a single regex with no lookbehind or conditionals support thus I suggest the following approach combining regex and additional programming logic:

 var texts = ['abcfobar','abc33bar']; var regex = /^([a-zA-Z0-9]{0,3})(?:([a-zA-Z]{1,2})([a-zA-Z0-9]+)?)?/; for (var i=0; i<texts.length;i++) { var serialCode = ''; var serialMarket = ''; var serialSuffixmatch = ''; var match = texts[i].match(regex); if (match) { serialCode = match[1]; serialMarket = (match[2] || ""); if (serialCode.length == 3 && serialMarket.length == 2) { serialSuffixmatch = match[3]; } } console.log(texts[i], '=>', serialCode + "\n" + serialMarket + "\n" + serialSuffixmatch); }

That is, simply use numbered capturing groups, and once a match is obtained, check the length of the first and second groups, and if the sum of their lengths is 5, grab Group 3 value, too.

You can use a conditional to start with your most restrictive pattern and work your way backwards to the least restrictive one:

^(?:[a-zA-Z0-9]{3}[a-zA-Z]{2}[a-zA-Z0-9]*|[a-zA-Z0-9]{3}[a-zA-Z]{1,2}|[a-zA-Z0-9]{0,3})

I don't know if the named capture groups have any significance for your JS code logic but unfortunately you cannot declare the same capture group name.

https://regex101.com/r/2uztK5/1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM