Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regex to validate subtract equations like "abc-b=ac"

Tags:

regex

pcre

I've stumbled upon a regex question.

How to validate a subtract equation like this?

A string subtract another string equals to whatever remains(all the terms are just plain strings, not sets. So ab and ba are different strings).

Pass

  • abc-b=ac
  • abcde-cd=abe
  • ab-a=b
  • abcde-a=bcde
  • abcde-cde=ab

Fail

  • abc-a=c
  • abcde-bd=ace
  • abc-cd=ab
  • abcde-a=cde
  • abc-abc=
  • abc-=abc

Here's what I tried and you may play around with it

https://regex101.com/r/lTWUCY/1/

like image 500
Hao Wu Avatar asked Mar 26 '21 08:03

Hao Wu


2 Answers

Disclaimer: I see that some of the comments were deleted. So let me start by saying that, though short (in terms of code-golf), the following answer is not the most efficient in terms of steps involved. Though, looking at the nature of the question and its "puzzle" aspect, it will probably do fine. For a more efficient answer, I'd like to redirect you to this answer.


Here is my attempt:

^(.*)(.+)(.*)-\2=(?=.)\1\3$

See the online demo

  • ^ - Start line anchor.
  • (.*) - A 1st capture group with 0+ non-newline characters right upto;
  • (.+) - A 2nd capture group with 1+ non-newline characters right upto;
  • (.*) - A 3rd capture group with 0+ non-newline characters right upto;
  • -\2= - An hyphen followed by a backreference to our 2nd capture group and a literal "=".
  • (?=.) - A positive lookahead to assert position is followed by at least a single character other than newline.
  • \1\3 - A backreference to what was captured in both the 1st and 3rd capture group.
  • $ - End line anchor.

EDIT:

I guess a bit more restrictive could be:

^([a-z]*)([a-z]+)((?1))-\2=(?=.)\1\3$
like image 104
JvdV Avatar answered Nov 20 '22 03:11

JvdV


You may use this more efficient regex with a lookahead at the start with a capture group that matches text on the right hand side of - i.e. substring between - and = and captures it in group #1. Then in the main body of regex we just check presence of capture group #1 and capture text before and after \1 in 2 separate groups.

^(?=[^-]+-([^=]+)=.)([^-]*?)\1([^-]*)-[^=]+=\2\3$

RegEx Demo

RegEx Demo:

  • ^: Start
  • (?=[^-]+-([^=]+)=.): Lookahead to make sure we have expression structure of pqr-pq=r and also more importantly capture substring between - and = in capture group #1. . after = is there for a reason to disallow any empty string after =.
  • ([^-]*?): Match 0 or more non-- characters in capture group #2
  • \1: Back-reference to group #1 to make sure we match same value as in capture group #1
  • ([^-]*): Match 0 or more non-- characters in capture group #3
  • -: Match a -
  • [^=]+: Match 0 or more non-= characters
  • =: Match a =
  • \2\3: Back-reference to group #2 and #3 which is difference of substraction
  • $: End
like image 13
anubhava Avatar answered Nov 20 '22 02:11

anubhava