Validating linear equations with regular expressions? - regex

How can I validate linear equations with regular expressions or is there another way besides using regular expressions. I will use ^ to denote an exponent.
2x + 3 = 8 //This should validate fine
3x + 2y + 4z = 12 //This should validate fine
4x^2 + 2y = 22 //This should not validate because of the power.
4xy + 3y = 45 //This should not validate because of the product of two unknowns.
2/x + 4y = 22 //This should not validate because of the unknown in the denominator
(3/4)x + 3y + 2z = 40 //This should validate fine.

I'd start by writing a definition of a valid linear equation using Backus-Naur notation, with things like:
<integer> := <digit> | <integer> <digit>
<constant> := <integer> | ...
<variable> := <letter>
<term> := <constant> | <variable> | <constant> <variable>
and so on.
There are many ways to turn that into a validator. Having some experience with it, I'd use yacc or bison to write a parser that would only generate a parse tree if the input was a valid linear equation.
You might find regular expressions are too limited to do what you need - I just don't use them enough to know.

The cases you've mentioned are easy:
fail if /[xyz]\s*\^/;
fail if /\/\s*[xyz]/;
fail if /([xyz]\s*){2,}/;
(this is Perl syntax, assuming $_ contains the expression, and fail is whatever it is you do when you want to give up.)
Here you can replace xyz with whatever is a valid expression for one variable.
But in general this will require actual parsing of the expression, which is a job for lex/yacc or something like that, not a regular expression.
For example if "xy" is a legitimate variable name, then of course this all crumbles.

Related

Convert equation from string in postgresql

I am trying to write a query that takes in a string, where an equation in the form
x^3 + 0.0046x^2 - 0.159x +1.713
is expected. The equation is used to calculate new values in the output table from a list of existing values. Hence I will need to convert whatever the input equation string is into an equation that postgresql can process, e.g.
power(data.value,3) + 0.0046 * power(data.value,2) - 0.159 * data.value + 1.713
A few comforting constraints in this task are
The equation will always be in the form of a polynomial, e.g. sum(A_n * x^n)
The user will always use 'x' to represent the variable in the input equation
I have been pushing my queries into a string and executing it at the end, e.g.
_query TEXT;
SELECT 'select * from ' INTO _query;
SELECT _query || 'product.getlength( ' || min || ',' || max || ')' INTO _query;
RETURN QUERY EXECUTE _query;
Hence I know I only need to somehow
Replace the 'x''s to 'data.values'
Find all the places in the equation string where a number
immediately precede a 'x', and add a '*'
Find all exponential operations (x^n) in the equation string and
convert them to power(x,n)
This may very well be something very trivial for a lot of people, unfortunately postgresql is not my best skill and I have already spent way more time than I can afford to get this working. Any type of help is highly appreciated, cheers.
Your 9am-noon time frame is over, but here goes.
Every term of the polynomial has 4 elements:
Addition/subtraction modifier
Multiplier
Parameter, always x in your case
Power
The problem is that these elements are not always present. The first term has no addition element, although it could have a subtraction sign - which is then typically connected to the multiplier. Multipliers are only given when not equal to 1. The parameter is not present in the last term and neither is a power in the last two terms.
With optional capture groups in regular expression parsing you can sort out this mess and PostgreSQL has the handy regexp_matches() function for this:
SELECT * FROM
regexp_matches('x^3 + 0.0046x^2 - 0.159x +1.713',
'\s*([+-]?)\s*([0-9.]*)(x?)\^?([0-9]*)', 'g') AS r (terms);
The regular expression says this:
\s* Read 0 or more spaces.
([+-]?) Capture 0 or 1 plus or minus sign.
\s* Read 0 or more spaces.
([0-9.]*) Capture a number consisting of digit and a decimal dot, if present.
(x?) Capture the parameter x. This is necessary to differentiate between the last two terms, see query below.
\^? Read the power symbol, if present. Must be escaped because ^ is the constraint character.
([0-9]*) Capture an integer number, if present.
The g modifier repeats this process for every matching pattern in the string.
On your string this yields, in the form of string arrays:
| terms |
|-----------------|
| {'','',x,3} |
| {+,0.0046,x,2} |
| {-,0.159,x,''} |
| {+,1.713,'',''} |
| {'','','',''} |
(I have no idea why the last line with all empty strings comes out. Maybe a real expert can explain that.)
With this result, you can piece your query together:
SELECT id, sum(term)
FROM (
SELECT id,
CASE WHEN terms[1] = '-' THEN -1
WHEN terms[1] = '+' THEN 1
WHEN terms[3] = 'x' THEN 1 -- If no x then NULL
END *
CASE terms[2] WHEN '' THEN 1. ELSE terms[2]::float
END *
value ^ CASE WHEN terms[3] = '' THEN 0 -- If no x then 0 (x^0)
WHEN terms[4] = '' THEN 1 -- If no power then 1 (x^1)
ELSE terms[4]::int
END AS term
FROM data
JOIN regexp_matches('x^3 + 0.0046x^2 - 0.159x +1.713',
'\s*([+-]?)\s*([0-9.]*)(x?)\^?([0-9]*)', 'g') AS r (terms) ON true
) sub
GROUP BY id
ORDER BY id;
SQLFiddle
This assumes you have an id column to join on. If all you have is a value then you can still do it but you should then wrap the above query in a function that you feed the polynomial and the value. The power is assumed to be integral but you can easily turn that into a real number by adding a dot . to the regular expression and a ::float cast instead of ::int in the CASE statement. You can also support negative powers by adding another capture group to the regular expression and a case statement in the query, same as for the multiplier term; I leave this for your next weekend hackfest.
This query will also handle "odd" polynomials such as -4.3x^3+ 101.2 + 0.0046x^6 - 0.952x^7 +4x just so long as the pattern described above is maintained.

Create Regex pattern for calculator

I am trying to create a calculator,where operands are words.It can repeat any number of times.
e.g. EmpName+xyz or EmpName or x+rr+fff.
It should reject such pattern e.g.
EmpName+
I created a regular expression:
(?m)(?<Operand>^[a-z].*?)(?<Operator>[+*])
On this output:
1) a + b
2) ab+dddd
3) ab*fffff*ggggg
4) dfg+fg4444+fgf4
5) xxxxx
But it only targets 1,2,3,4 and up to only first operator. Output in regex 2.05.
"Operand: [ab]"
"Operator:[+]"
I am using regex builder 2.05 to test my regex. How i can repeat this pattern any number of times? Thanks in advance.
This would typically be expressed as
operand followed by (operator operand) one or more times
that is
(?m)<Operand>([+*]<Operator>)*
Yes i need parantheses as well as divide,percentage,minus sign also.
Then I suggest considering using a real parser. The language of balanced parentheses is not regular.

Regular expressions for phone number patterns

Do you know if is possible to transform a pattern like this to regular expressions:
ABCDXXXXYYYY
Where ABCDEFGH.. are consecutive numbers and V, X, Y, Z are any number.
The pattern above should match:
123400006666
456799994444
etc.
Please note that I'm not asking for a full solution, but some idea on how to approach this problem. Have you ever faced a situation like this before (to search a DB for defined patterns that doesn't seem to fit RegExps?
Any comment would be really appreciated.
You can't identify consecutive numbers in a regular expression as they're too context dependant.
However, I think this would be easily possible in PL/SQL and possibly possible in SQL.
If you only want to use SQL then you can generate a string of consecutive numbers using a combination of connect by and either the undocumented function wm_contact or the user-defined function stragg
Something like:
select replace(stragg(level),',','')
from dual
connect by level <= 5
Concatenating this with a regular expression may get you close but I don't think that this is the way to go. I would definitely investigate using a PL/SQL function and possibly forgetting about regular expressions completely.
Doing the following will split out a number into an array, which you can then loop through and manipulate. As requested, this is just a starting point and you may want to change it around a lot. As there's no actual SQL and it's just string manipulation it's pretty efficient doing something like this.
create or replace function validate_phone( P_phone number )
return number is
type t__phone is table of number index by binary_integer;
t_phone t__phone;
l_consecutive varchar2(150);
begin
-- Test whether we actually have a number first ( code below ).
if is_number(P_phone) = 0 then
return null;
end if;
-- Split out the phone number into individual array elements.
for i in 1 .. length(to_char(P_phone)) loop
t_phone(i) := substr(to_char(P_phone, i, 1))
end loop;
for i in t_phone.first .. t_phone.last loop
-- If we find a consecutive number then build this string.
if t_phone.exists(i + 1)
and t_phone(i) = t_phone(i + 1) - 1 then
l_consecutive := l_consecutive || t_phone(i);
end if;
end loop;
return something;
end validate_phone;
You may, as indicated in the above want to check whether your phone number is actually numeric first:
create or replace function is_number( P_number varchar2 )
return number is
/* Test a number to see whether it actually is one
return a 1 / 0 rather than boolean so it can also
be used in plain SQL.
*/
l_number number;
begin
l_number := P_number;
return 1;
exception when others then
return 0;
end is_number;
The language you describe is not context-free (in case the length of the prefix consisting of consecutive numbers is arbitrary) and not a regular language, therefore can not be expressed by a regular expression.

Displaying the postfix/prefix expression as a parse tree using C/C++

I have successfully converted infix expression to postfix expression and was also able to evaluate the postfix expression but I am facing problem in generating a parse tree for the same with C/C++
My output :
enter the expression string a+b*c
the expression is correct
the postfix expression is - abc *+
enter the value of a-1
enter the value of b-2
enter the value of c-3
the postfix expression is -abc*+
result= 7
I also require to display: Syntax tree
+
/ \
* a
/ \
b c
Any feedback would be very helpful in my project.
Thanks in Adv.
#LD: Thanks for your consistent help. I need the pseudocode in turbo C. I don't know Ruby.
It's much easier to "draw" them like the following:
+
a
*
b
c
Or, if you want to use simple character graphics (I've changed the + and * operators to Add and Mul, to avoid clashing with the graphics):
Add
+-- a
+-- Mul
+-- b
+-- c
The trick to doing this is possible draw a subtree in isolation (e.g. the mul tree), and then draw it with suitable prefixes when drawing the outer tree.
In fact, if you are familiar with C++ stream buffers, you could create a prefixing stream buffer that handles the prefixes and simply print the inner tree.
The big difference compared to the style you suggested is that your style simply doesn't scale. If, for example the top operator would have two big subtrees, they would have been drawn extremely far apart.
EDIT: A slightly more complex tree could be drawn like this:
Add
+---Sub
| +---Div
| | +---p
| | +---q
| +---y
+---Mul
+---b
+---c
EDIT: On request, here comes some pseudo-code (which, incidentally, is acceptable by a Ruby interpreter). You must, however, use a suitable C++ data structure to represent the tree.
# Return the drawn tree as an array of lines.
#
# node ::= string
# node ::= [string, node, node]
def render_tree(node, prefix0 = "", prefix = "")
if (node.is_a?(String))
puts prefix0 + node # Value
else
puts prefix0 + node[0] # Operator
render_tree(node[1], prefix + "+---", prefix + "| ")
render_tree(node[2], prefix + "+---", prefix + " ")
end
end
render_tree(["Add", ["Sub", ["Div", "p", "q"], "y"], ["Mul", "b", "c"]])

Can I "combine" 2 regex with a logic or?

I need to validate Textbox input as credit card number. I already have regex for different credit cards:
Visa: ^4[0-9]{12}(?:[0-9]{3})?$
Mastercard: ^([51|52|53|54|55]{2})([0-9]{14})$
American Express: ^3[47][0-9]{13}$
and many others.
The problem is, I want to validate using different regex based on different users. For example: For user1, Visa and Mastercard are available, while for user2, Visa and American Express are available. So I would like to generate a final regex string dynamically, combining one or more regex string above, like:
user1Regex = Visa regex + "||" + Mastercard regex
user2Regex = Visa regex + "||" + American Express regex
Is there a way to do that? Thanks,
You did not state your language but for whatever reason I suspect it's JavaScript. Just do:
var user1Regex = new RegExp('(' + Visaregex + ")|(" + Mastercardregex + ')');
// or if es6:
let user1Regex = new RegExp(`(${Visaregex})|(${Mastercardregex})`);
You can also use (?:) for speedier execution (non-capturing grouping) but I have omitted that for readability.
Use the | operator and group all with parentesis ()
^(4[0-9]{12}(?:[0-9]{3})?|([51|52|53|54|55]{2})([0-9]{14})|3[47][0-9]{13})$
If all regex are correct it should work
Not sure which language you are using to implement but you can use a single | to use a logical or most regex. My suggestion would be to store each regex as a string and then concatenate and compile when necessary.
in python it would be something like
visa = "visa_regex"
mastercard = "mastercard_regex"
combined = re.compile(visa + "|" + mastercard)
combine two expressions or more, put every expression in brackets,
and use: *?
This are the signs to combine, in order of relevance:
*? example 1 : (A)*?(B)
| example 2 : A|B
()() example 3 : (A)(B)
()|() example 4 : (A)|(B)