如何使用AWK、sed或Perl进行这样的替换?

7

希望使用以下替换规则将乘法符号“*”替换为“张量”,并将幂符号“^”替换为“p_张量”:

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

但是当符号“*”在数字和a(i)之间,例如3*a(i),我们应该保留符号“*”。

因此,举个例子:

    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)))
    ...

现在我想使用AWK、sed或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))

你有什么想法吗?

替换后的预期结果应该是

    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))

为什么您要将一些 * 替换为 tensor,而另一些则不替换呢?例如,第一个 3*a(3)^2 似乎应该是 tensor(3,p_tensor(2,a(3)) - ceyko
是的,我应该提到,“张量”仅用于替换符号“*”,它是两个a(i)之间的二元运算符。 - Osiris Xu
我想不出一个简单的方法来做这件事,特别是那个特殊情况...至少没有任何干净的方式。你可能需要研究将原始表达式解析为表达式树,然后在必要时将其转换为使用你的操作。 - ceyko
4
由于涉及到括号,你很可能需要设置一种解析器来对输入进行分词,并逐个处理每个标记。 - user554546
@JackManey 有什么想法可以建立一个解析器来对输入进行分词,并逐个处理每个标记吗? - Osiris Xu
1个回答

7

正则表达式无法进行任意嵌套,也无法进行优先级和结合性。需要使用解析器;但是,您可以从以下内容开始接近:

Perl:

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

这个方法可以让你接近目标,只需要一个层级。额外的嵌套可以通过添加递归定义的模式来“伪造”,这些模式可以达到你所需的最大嵌套深度(实际上很少...在实践中,表达式很少超过3-4个层级,这对你来说可能已经足够了)。

试试这个方法:

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

或类似的东西。


能否说明一下Perl替换规则是如何将"6a(1)^2(5a(2)^2-2a(4))"完全转化为"6tensor(p_tensor(2,a(1)),(5p_tensor(2,a(2))-2a(4)))"的?使用当前脚本会被翻译成"6p_tensor(2,a(1))(5p_tensor(2,a(2))-2*a(4))"。 - Osiris Xu
1
我不确定你在遵循什么规则...你给出的产品规则涉及到a(i)这种形式的东西。如果你说你需要将各种任意产品转化为张量调用,那么你将需要一个解析器,不幸的是。你可以用perl编写这样的东西,但它会很丑陋(你必须预先计算括号等)。有一些非常好的工具可供使用。请参见GNU bison或ANTLR。 - Tony K.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接