Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do such substitutions with AWK or sed or Perl?

Want to substitute multiplication symbol "*" with "tensor", and the power symbol "^" with "p_tensor" using following substitution rules:

    a(k)^n --> p_tensor(n,a(k))
    a(i)*a(j) --> tensor(a(i),a(j)), when i=/=j

But when the symbol "*" is between a number and a(i), such as 3*a(i), we should keep the symbol "*" as what it is.

so for example,

    5*a(i)*a(j)*(a(k1)+3*a(k2)) --> 5*tensor(tensor(a(i),a(j)),a(k1)+3*a(k2))
    a(i)^2*a(j)^2  --> tensor(p_tensor(2,a(i)),p_tensor(2,a(j)))
    ...

Now I want to reformat the following expression using AWK or sed or Perl:

    3*a(3)^2+6*a(1)^2*(5*a(2)^2-2*a(4))+6*a(2)*a(4)+6*a(1)*(-4*a(2)*a(3)+a(5))

Any ideas how?

The expected result after substitution should be

    3*p_tensor(2,a(3))+6*tensor(p_tensor(2,a(1)),(5*p_tensor(2,a(2))-2*a(4))+6*tensor(a(2),a(4))+6*tensor(a(1),(-4*tensor(a(2),a(3))+a(5))
like image 216
Osiris Xu Avatar asked Dec 13 '12 04:12

Osiris Xu


1 Answers

Regular expressions cannot do arbitrary nesting, nor can then do precedence and associativity. Parsers are required for that; however, you can get close enough by starting with this:

Perl:

while(<>) {
   s/(a\(\d+\))\^(\d+)/p_tensor($2,$1)/g;
   s/(a\((\d+)\))\*(a\((\d+)\))/tensor($1, $3)/g if $2 != $4;
   print;
}

which is close, and gets you a single level. The extra nesting can then be "faked" by adding additional recursively defined patterns that go to whatever max nesting depth you need (often not many...expressions are rarely 3-4 levels deep in practice, which may be fine for you).

Try it with:

echo "3*a(3)^2+6*a(1)^2*(5*a(2)^2-2*a(4))+6*a(2)*a(4)+6*a(1)*(-4*a(2)*a(3)+a(5))" | perl t.pl

or something similar.

like image 179
Tony K. Avatar answered Sep 25 '22 17:09

Tony K.