-1

Can two regex be combined? Like it should match this regex or the other. Ideally exclusively (xor).

For instance, I want to validate a phone number against a landline phone number regex and a mobile phone number regex.

I wish I could do something like this but it doesn't work:

const landlinePhoneRegExp = /(^1300\d{6}$)|(^1800|1900|1902\d{6}$)|(^0[2|3|7|8]{1}[0-9]{8}$)|(^13\d{4}$)|(^04\d{2,3}\d{6}$)/
const mobilePhoneRegExp = /^04[0-9 ]+/
const stripOutDelimiters = regex => etc...

const phoneRegExp = `/${stripOutDelimiters(landlinePhoneRegExp)}|${stripOutDelimiters(mobilePhoneRegExp)}/`,

UPDATE: I forgot to add that I'm using the Yup library for validation! The code looks like this:

const validationSchema = (t, i18n) => Yup.object.shape({
  phone: Yup.string()
    .required(t('formValidationPhoneRequired'))
    .matches(localeRegex[i18n.language].phoneRegExp, t('formValidationPhoneInvalid'))
})

This explains why I was trying to dynamically combine the two regex into one like in the non-working example above.

I've been looking at the docs for a while now but there doesn't seem to be a way to do that. Maybe lazy() would be useful but apparently I can't use string.matches() then... unless I match (landlineMatch || mobileMatch) to boolean(), but how could I do that?

phone: Yup.lazy((value) => {
  const landlineMatch = value.match(localeRegex[i18n.language].landlinePhoneRegExp)
  const mobileMatch = value.match(localeRegex[i18n.language].mobilePhoneRegExp)

  return Yup.string()
    .required(t('formValidationPhoneRequired'))
    .matches( ??? , t('formValidationPhoneInvalid'))
})
zok
  • 6,065
  • 10
  • 43
  • 65
  • Much easier if you test each individually. – ctwheels Dec 03 '19 at 17:46
  • The OP has specifically said they'd like to combine these dynamically, with Javascript, and with XOR logic, so I don't think either of those two answer the question. – Andrew Dec 03 '19 at 17:48
  • @Andrew sure it does, how dynamic are we talking here, AI? – ctwheels Dec 03 '19 at 17:49
  • @ctwheels Dynamic to me implies they'd like to do this programmatically... Otherwise this question is unrelated to programming – Andrew Dec 03 '19 at 17:50
  • @Andrew so the two links we provided are considered dynamic because they present a way to accomplish this programmatically, but they aren't considered dynamic to you? Not sure what you mean. – ctwheels Dec 03 '19 at 17:51
  • @Andrew: Since original 2 regex are `const` so they are not going to change for sure. Hence proposed solution is good enough. – anubhava Dec 03 '19 at 17:54
  • You can combine those regexes dynamically using the answer I gave -- you just have to remove the `/` from the existing regexes and join them with `|` according to that answer. You can do that dynamically. Right? – TKoL Dec 03 '19 at 17:56
  • @TKoL That works mostly but would just be OR and not XOR – Andrew Dec 03 '19 at 17:58
  • 1
    Be aware that `(^1800|1900|1902\d{6}$)` matches strings that begin with `1800` with any characters after (i.e. `1800abcg*$ù^pihybncisgf456`), or strings that have `1900` somewhere in the middle (i.e.`abcdef1900xrs654ehrbt84`) or strings that end with `1902` followed by 6 digits (i.e. `xyz1234561902123456`) – Toto Dec 03 '19 at 18:08
  • 1
    The actual problem boils down to this `^(?:(04\d{8,9})|(04[0-9 ]+))$`. The last alternation overlaps the first. In other words The first is a subset of the last. Then it does not qualify as an exclusive or XOR. All that's needed is a normal OR of the subset first. –  Dec 03 '19 at 18:31
  • Thanks for the input everyone! The regex I used in the example look a bit funny and don't matter much. I think the XOR also doesn't matter much in my case. I came up with this which does exactly what I need: `const combineRegex = (r1, r2) => new RegExp(\`${new RegExp(r1).source}|${new RegExp(r2).source}\`)` – zok Dec 04 '19 at 15:48

1 Answers1

1

You're almost done, you just need to test if they match.

To test if a string matches, just use String.prototype.match():

landlineMatch = str.match(landlinePhoneRegExp)
mobileMatch = str.match(mobilePhoneRegExp)

There's no shortcut for the logical XOR test, you'll just have to use a combination of && and || like so:

(landlineMatch || mobileMatch) && !(landlineMatch && mobileMatch)
Andrew
  • 763
  • 7
  • 21
  • 1
    Or `(landlineMatch && !mobileMatch) || (mobileMatch && !landlineMatch)` –  Dec 03 '19 at 18:01
  • Or simply `if (!landlineMatch !== !mobileMatch)` (xor is equivalent to the two expressions evaluating to different Boolean values, one true and the other false) – IceMetalPunk Dec 03 '19 at 19:45