Reputation: 54
I am currently tasked with verifying if a given expression is correctly formatted. Ex. "7x^2 + 2x +1" would pass but "7x72" or something malformed would fail.
\d*x{0,1}(\^\d*){0,1}
It checks for the existence of each piece of the function, coefficient, optional x , optional exponent. I'm just not sure how to actually format it so that it has to be correct for every part between +/- signs , otherwise the function isn't keyed in correctly.
How do I solve this problem?
Upvotes: 0
Views: 183
Reputation: 159114
TL;DR Regex is:
(?!$)(?:(-?\d*)x\^2)?(?:(?<=2)\s*([+-])\s*(?!-|^))?(?:(?<!2)(-?\d*)x)?(?:(?<=[2x])\s*([+-])\s*(?!-|^))?(?:(?<![2x])(-?\d+))?
The full syntax would be:
[ ['-'][number]'x^2' ] ['+' | '-'] [ ['-'][number]'x' ] ['+' | '-'] [ ['-']number ]
['-']
means an optional minus sign for the number.
[number]
is because a multiplier of 1
can be omitted, even if it is -1
, e.g. -x
is a valid shorthand for -1x
.
['+' | '-']
means a +
or a -
, marked optional to keep it simple, but it is actually required between parts, and not allowed by itself. That is the tricky part that will make the regex grown in size.
So, let's build it up:
part1: -?\d*x\^2
part2: -?\d*x
part3: -?\d+
OP : \s*[+-]\s*(?!-)
The (?!-)
is to prevent a minus sign following an operator.
What is left is the [part1] [OP] [part2] [OP] [part3]
with 3 optional parts and two optional operators, except that parts must be separated by operators and operators must be between parts, and at least one part must be present.
To ensure something is present, we just need to prevent empty string, i.e. start regex with (?!$)
, a zero-with negative lookahead for end-of-string, aka "at start of input, we're not also at end of input".
In regex we do optional using (?: xxx )?
, i.e. a non-capturing group marked optional, so making each part and operator optional is easy.
So far we therefore have:
(?!$)(?:part1)?(?:OP)?(?:part2)?(?:OP)?(?:part3)?
Now for the tricky parts:
Parts must be separated by operators
This is easiest tested by ensure that part2 is not immediately preceded by a 2
(last character of part1), and that part3 is not immediately preceded by a 2
or an x
(last character of part1 or part2), so we'll use zero-width negative lookbehinds.
(?:(?<!2)part2)
(?:(?<![2x])part3)
Operators must be between parts
Operators cannot be first or last
(?:(?<!^)OP(?!^))
Operators cannot be adjacent, easiest tested by ensuring that second operator is immediately preceded by part1 or part2, which makes the "not at start" redundant.
(?:(?<=[2x])OP)
For consistency, the "not at start" for first operator can be changed to "must be part1".
(?:(?<=2)OP)
That now gives us (shown on multiple lines to clarify):
(?!$)
(?:part1)?
(?:(?<=2)OP(?!^))?
(?:(?<!2)part2)?
(?:(?<=[2x])OP(?!^))?
(?:(?<![2x])part3)?
All combined, with added capture groups to capture the (signed) numbers and the operators
(?!$)(?:(-?\d*)x\^2)?(?:(?<=2)\s*([+-])\s*(?!-|^))?(?:(?<!2)(-?\d*)x)?(?:(?<=[2x])\s*([+-])\s*(?!-|^))?(?:(?<![2x])(-?\d+))?
Here it is, coded in Java, with logic for finding a
, b
, and c
in the formula ax^2 + bx + c
:
public static void main(String[] args) {
System.out.println("part1 op1 part2 op2 part3 a b c input");
test("3x^2 + 4x + 5");
test("x^2 + x + 1");
test("x^2 - 4x");
test("-x^2 - 1");
test("-4x - 5");
test("-3x^2");
test("-4x");
test("-5");
test("");
test("-3x^2 + -1x");
}
private static void test(String input) {
String regex = "(?!$)" +
"(?:(-?\\d*)x\\^2)?" +
"(?:(?<=2)\\s*([+-])\\s*(?!-|^))?" +
"(?:(?<!2)(-?\\d*)x)?" +
"(?:(?<=[2x])\\s*([+-])\\s*(?!-|^))?" +
"(?:(?<![2x])(-?\\d+))?";
Matcher m = Pattern.compile(regex).matcher(input);
if (! m.matches()) {
System.out.printf("%-41s\"%s\"%n", "No match", input);
} else {
String part1 = m.group(1);
String op1 = m.group(2);
String part2 = m.group(3);
String op2 = m.group(4);
String part3 = m.group(5);
long a = parse(null, part1);
long b = parse(op1, part2);
long c = parse((op2 != null ? op2 : op1), part3);
System.out.printf("%-6s%-6s%-6s%-6s%-6s%3d%3d%3d \"%s\"%n",
(part1 == null ? "" : '"' + part1 + '"'),
(op1 == null ? "" : '"' + op1 + '"'),
(part2 == null ? "" : '"' + part2 + '"'),
(op2 == null ? "" : '"' + op2 + '"'),
(part3 == null ? "" : '"' + part3 + '"'),
a, b, c, input);
}
}
private static long parse(String operator, String signedNumber) {
long number;
if (signedNumber == null)
number = 0;
else if (signedNumber.isEmpty())
number = 1;
else if (signedNumber.equals("-"))
number = -1;
else
number = Long.parseLong(signedNumber);
if ("-".equals(operator))
number = -number;
return number;
}
Output
part1 op1 part2 op2 part3 a b c input
"3" "+" "4" "+" "5" 3 4 5 "3x^2 + 4x + 5"
"" "+" "" "+" "1" 1 1 1 "x^2 + x + 1"
"" "-" "4" 1 -4 0 "x^2 - 4x"
"-" "-" "1" -1 0 -1 "-x^2 - 1"
"-4" "-" "5" 0 -4 -5 "-4x - 5"
"-3" -3 0 0 "-3x^2"
"-4" 0 -4 0 "-4x"
"-5" 0 0 -5 "-5"
No match ""
No match "-3x^2 + -1x"
Upvotes: 1
Reputation: 2153
Try this:
((-?\d+)x\^2\s*[+-]\s*)?(\d+)x\s*([+-]\s*\d+)
(-?\d+)x\^2\s*[+-]\s*)?
-?\d+
- 0 or 1 -
sign followed by one or more digit x\^2
- x character, ^ character, 2 character\s*
- optional space[+-]
- either + character or - character?
- 0 or 1 of this group. Quadratic formula may not have first part. Remove this ?
to make it not optional(\d+)x
- one or more digit followed by x character (ex: 2x)\s*
- optional space([+-]\s*\d+)
\s*
- optional space\d+
- one or more digit (ex: 3)Upvotes: 1