免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 5834 | 回复: 16

[原创] 表达式求值程序 by AWK  关闭 [复制链接]

论坛徽章:
0
发表于 2006-04-13 20:50 |显示全部楼层
今天看到论坛中有人问: awk如何计算命令行的输入?
仔细想了想用awk确实不好做。因为awk中没有像其它语言
中的eval函数,于是自己试着编了一个eval函数,用来进
行表达式求值。
   用stack对运算符号及数值进行处理是这个脚本的关键。
由于时间有限,我只实现了+-*/%五种运算。代码写的比较
粗糙,欢迎大家批评指正。


用法(表达式必须以"@"结束):


  1. echo "(3-1)*2.3-8.5%3-(9.12+2*3)/2@" | awk -f eval
  2. echo 1+2+3*2 @| awk -f eval
  3. awk -f eval <( seq 1 100|tr "\n" "+"|sed 's/+/@/100' )
复制代码



代码:


  1. #! /usr/bin/awk
  2. # simple expression evaluator awk version
  3. # author : dbcat at chinaunix.net
  4. # email: deeperbluecat@gmail.com
  5. # usage: example :
  6. # echo "(3-1)*2.3-8.5%3-(9.12+2*3)/2@" | awk -f eval
  7. # echo 1+2+3*2 @| awk -f eval
  8. # awk -f eval <( seq 1 100|tr "\n" "+"|sed 's/+/@/100' )
  9. # expression must be end with "@"
  10. # have fun




  11. BEGIN{

  12. # 运算符集合
  13. symbol="+-*%/()@";


  14. # 构造运算符优先级关系
  15. oppr["++"]=">";oppr["+-"]=">";oppr["+*"]="<";oppr["+/"]="<";oppr["+%"]="<";oppr["+("]="<"; oppr["+)"]=">";oppr["+@"]=">";
  16. oppr["-+"]=">";oppr["--"]=">";oppr["-*"]="<";oppr["-/"]="<";oppr["-%"]="<";oppr["-("]="<"; oppr["-)"]=">";oppr["-@"]=">";
  17. oppr["*+"]=">";oppr["*-"]=">";oppr["**"]=">";oppr["*/"]=">";oppr["*%"]="<";oppr["*("]="<"; oppr["*)"]=">";oppr["*@"]=">";
  18. oppr["/+"]=">";oppr["/-"]=">";oppr["/*"]=">";oppr["//"]=">";oppr["/%"]="<";oppr["/("]="<"; oppr["/)"]=">";oppr["/@"]=">";
  19. oppr["%+"]=">";oppr["%-"]=">";oppr["%*"]=">";oppr["%/"]=">";oppr["%%"]=">";oppr["%("]="<"; oppr["%)"]=">";oppr["%@"]=">";
  20. oppr["(+"]="<";oppr["(-"]="<";oppr["(*"]="<";oppr["(/"]="<";oppr["(%"]="<";oppr["(("]="<"; oppr["()"]="=";
  21. oppr[")+"]=">";oppr[")-"]=">";oppr[")*"]=">";oppr[")/"]=">";oppr[")%"]=">";                oppr["))"]=">";oppr[")@"]=">";
  22. oppr["@+"]="<";oppr["@-"]="<";oppr["@*"]="<";oppr["@/"]="<";oppr["@("]="<";oppr["@%"]="<";                oppr["@@"]="=";


  23. }



  24. {
  25.    gsub(/[-*%+()/@]/," & ",$0);
  26.    expression=$0;
  27. }



  28. END{
  29. # 分解表达式
  30. split(expression,Ex," ");

  31. print evaluate(Ex);

  32. }






  33. # 表达式求值函数

  34. function evaluate(Ex,OP,OF,c,k,t,x,str,y,r)
  35. {
  36.     k=1;
  37.     push(OP,"@");
  38.     c=Ex[k];
  39.     while(c!="@" || gettop(OP)!="@")
  40.       {
  41.         if(index(symbol,c)==0)
  42.           {         
  43.             push(OF,c);
  44.             k=k+1;
  45.             c=Ex[k];
  46.             
  47.           }else
  48.           {
  49.             t=priority(oppr,gettop(OP),c);
  50.             if(t=="<")
  51.              {
  52.                push(OP,c);
  53.                k=k+1;
  54.                c=Ex[k];
  55.                
  56.              }else if(t=="=")
  57.              {

  58.                pop(OP);
  59.                k=k+1;
  60.                c=Ex[k];
  61.              }else{
  62.                
  63.                str=pop(OP);
  64.                y=pop(OF);
  65.                x=pop(OF);
  66.                r=calculate(x,str,y);
  67.                push(OF,calculate(x,str,y));
  68.      
  69.             }
  70.         
  71.           }

  72.       }
  73.   return gettop(OF);
  74. }


  75. # 二元运算函数

  76. function calculate(x,st,y)
  77. {
  78.     if(st=="+")
  79.       return x+y;
  80.     else if(st=="-")
  81.       return x-y;
  82.     else if(st=="*")
  83.       return x*y;
  84.     else if(st=="%")
  85.       return x%y;
  86.     else if(st=="/")
  87.       return x/y;
  88. }


  89. # 优先级别比较

  90. function priority(oppr,op1,op2)
  91. {
  92.    return oppr[op1""op2];
  93. }


  94.   # 取栈顶

  95. function gettop(arr,k,t)
  96. {
  97.     k=0;
  98.     for(t in arr)
  99.      {
  100.         k++;
  101.      }
  102.     return arr[k-1];
  103. }

  104. #  进栈函数

  105. function push(arr,x,t,k)
  106. {
  107.   k=0;
  108.   for(t in arr)
  109.    {
  110.       k++;
  111.    }
  112. arr[k]=x;

  113. }

  114. #  出栈函数

  115. function pop(arr,va,t,u)
  116. {
  117.   u=0;
  118.   for(t in arr)
  119.     {
  120.       u++;
  121.     }
  122.   va=arr[u-1];
  123.   delete arr[u-1];
  124.   return va;
  125. }


复制代码

论坛徽章:
0
发表于 2006-04-13 21:01 |显示全部楼层
dbcat你真厉害!

我也问了一个问题:
我知道怎么逐行读取一个文件,但怎么逐字读取一个文件?

帮帮我。

论坛徽章:
0
发表于 2006-04-13 21:06 |显示全部楼层
你想干虾米?

论坛徽章:
0
发表于 2006-04-13 21:11 |显示全部楼层
原帖由 dbcat 于 2006-4-13 21:06 发表
你想干虾米?

我想知道方法。暂时还没想到有什么用,是一个字符一个字符地去读,就是相当于:
cat 1.txt>2.txt的功能。

[ 本帖最后由 xlink 于 2006-4-13 21:14 编辑 ]

论坛徽章:
0
发表于 2006-04-13 21:14 |显示全部楼层
我猜用dd可以

论坛徽章:
0
发表于 2006-04-13 21:24 |显示全部楼层
原帖由 dbcat 于 2006-4-13 21:14 发表
我猜用dd可以

dd好象是用来cp文件的,我不是想去cp一个文件。
如果把一个文件全部读进一组变量里,你想想,多好的事情。

论坛徽章:
0
发表于 2006-04-13 22:21 |显示全部楼层
谢谢 dbcat 费心写出的这个函数,我在windows下只有 GAWK 能够通过, awk95、nawk、mawk 都不能通过。
你的代码我现在还看不懂,看来我自己是不能通过简单修改来满足最初的需求了。先收藏起来,努力学习吧。

论坛徽章:
0
发表于 2006-04-13 23:02 |显示全部楼层
原帖由 xlink 于 2006-4-13 21:24 发表

dd好象是用来cp文件的,我不是想去cp一个文件。
如果把一个文件全部读进一组变量里,你想想,多好的事情。


dd是可以的,小弟试了一下,不过又缺陷

  1. #  while char=`dd bs=1 count=1 2>/dev/null`; do echo $char; done <file
复制代码

由于小弟学艺不精,导致当dd读完了整个文件后,还在继续读,望高手指点

用awk实现了一下,请试试

  1. # awk 'BEGIN { FS="" } { for (i=1;i<=NF;i++) print $i }' file
复制代码

论坛徽章:
1
荣誉会员
日期:2011-11-23 16:44:17
发表于 2006-04-14 11:19 |显示全部楼层
dbcatMM is A awk's master ~ ^_^

论坛徽章:
0
发表于 2006-04-14 11:42 |显示全部楼层
如果把乘阶运算符“^” , 和"sin cos exp ...." 加进去就好了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP