String manipulation of type String substitution in mathematical expression

Imagine something like

exp(49/200)+(x-49/200)

I want to pass as argument of the function "roundn" whatever operation that is not an addtion or a subtraction So my expresion became

roundn(exp(roundn(49/200,n)),n)+(x - roundn(49/200,n)

Well the expression I want to manipulate is this:

exp(49/200)+exp(49/200)*(x-49/200)+1/2*exp(49/200)*(x-49/200)^2+1/6*exp(49/200)*(x-       49/200)^3+1/24*exp(49/200)*(x-49/200)^4+1/120*exp(49/200)*(x-49/200)^5+1/720*exp(49/200)*(x-49/200)^6+1/5040*exp(49/200)*(x-49/200)^7+1/40320*exp(49/200)*(x-49/200)^8+1/362880*exp(49/200)*(x-49/200)^9+1/3628800*exp(49/200)*(x-49/200)^10+1/39916800*exp(49/200)*(x-49/200)^11

I´m looking for a method (That include whatever program) not based in language programming, as much batch or somithing like that...


Solution 1:

Try this:

ro='roundn('    # roundn open
rc=',n)'        # roundn close
fun='exp\('
expression='exp(49/200)+(x-49/200)'
echo "$expression" |
perl -pe "s/$fun[^)]*\K\)/)$rc/g; s/(?<!\^)[0-9\/*]+[0-9]/$ro\$&$rc/g; s/$fun[^)]*/$ro\$&/g"

which should give you:

roundn(exp(roundn(49/200,n)),n)+(x-roundn(49/200,n))

Your longer expression should result in:

roundn(exp(roundn(49/200,n)),n)+roundn(exp(roundn(49/200,n)),n)*
(x-roundn(49/200,n))+roundn(1/2,n)*roundn(exp(roundn(49/200,n)),n)*
(x-roundn(49/200,n))^2+roundn(1/6,n)*roundn(exp(roundn(49/200,n)),n)*
(x-roundn(49/200,n))^3+roundn(1/24,n)*roundn(exp(roundn(49/200,n)),n)*
(x-roundn(49/200,n))^4+roundn(1/120,n)*roundn(exp(roundn(49/200,n)),n)*
(x-roundn(49/200,n))^5+roundn(1/720,n)*roundn(exp(roundn(49/200,n)),n)*
(x-roundn(49/200,n))^6+roundn(1/5040,n)*roundn(exp(roundn(49/200,n)),n)*
(x-roundn(49/200,n))^7+roundn(1/40320,n)*roundn(exp(roundn(49/200,n)),n)*
(x-roundn(49/200,n))^8+roundn(1/362880,n)*roundn(exp(roundn(49/200,n)),n)*
(x-roundn(49/200,n))^9+roundn(1/3628800,n)*roundn(exp(roundn(49/200,n)),n)*
(x-roundn(49/200,n))^10+roundn(1/39916800,n)*roundn(exp(roundn(49/200,n)),n)*
(x-roundn(49/200,n) ^11

Explanation

  • /exp\([^)]*\K\)/)$rc/g - close exp(), add roundn close
    • for strings that start with "exp(" and end with ")"
    • \K makes the "exp(" a zero-width match so only the closing paren is replaced
  • s/(?<!\^)[0-9\/*]+[0-9]/$ro\$&$rc/g - strings of digits with mult and div, surround with roundn open and roundn close
    • strings of digits that don't start with "^" but may contain "/" or "*"
    • must be two or more total characters - there's probably a better way to do this
    • carat is negative look-behind (zero-width) so it's not included when the replacement is made
  • s/exp\([^)]*/$ro\$&/g - open exp(), add roundn open
    • before "exp(" followed by zero or more characters that are not ")", add roundn open
  • $ro, $rc and $fun are shell variables
    • wrapping the Perl script in double quotes allows these variables to be expanded
  • $& contains the entire match except for the zero-width portions
    • escaping it is probably not necessary, but I did it just in case - to keep from confusing the shell

It wouldn't be too hard to make this work if there are more than one function. However, it will probably completely fall apart if they are nested.

Edit:

Here is a Perl script version:

$ro = "roundn(";
$rc = ",n)";
$fun = "exp\\(";
while (<>) {
    s/$fun[^)]*\K\)/)$rc/g;
    s/(?<!\^)[0-9\/*]+[0-9]/$ro$&$rc/g;
    s/$fun[^)]*/$ro$&/g;
    print
}

Run it like this:

perl script.pl < data.txt