.关于货币大写的探索

尝试了一下货币的大写的方法,自己从论坛上看到,到自己亲手实践,已经可以实现上述的需求,中间思路和算法也更换了几次写出来程序的雏形,有待优化的地方,但是作为自己的思路,把自己的算法记录下来,待以后进一步改进。

 
 
     1、自己的算法
 
 
create or replace function lcw_get_money(money in number) return varchar2 is
  max_num   number := 0;
  v_num     number := 0;
  v_char    varchar2(200);
  retcode number:=0;
  errbuf varchar2(200);
  Result varchar2(200);
  v_error exception;
begin
  if length(money)>9 then
   raise v_error;
  end if;
  max_num:=length(money);
  v_num := max_num;
  loop
     v_char:=substr(money, v_num, 1); 
      case
      when v_num = max_num and substr(money, v_num, 1)<>0 then
        result := v_char || '元整' || result;
      when v_num = max_num and substr(money, v_num, 1)=0 then
        result := '元整' || result;
      when (v_num = max_num-1 or v_num = max_num-5)  and substr(money, v_num, 1)<>0 then
        result := v_char || '拾' || result;
       when (v_num = max_num-1 or v_num = max_num-5) and substr(money, v_num, 1)=0 then
        result := v_char|| result;
      when (v_num = max_num-2 or  v_num = max_num-6)  and substr(money, v_num, 1)<>0 then
        result := v_char || '佰' || result;
      when (v_num = max_num-2 or  v_num = max_num-6)  and substr(money, v_num, 1)=0 then
        result := v_char|| result;
        when (v_num = max_num-3 or  v_num = max_num-7) and substr(money, v_num, 1)<>0 then
        result := v_char || '仟' || result;
       when v_num = max_num-3 and substr(money, v_num, 1)=0 then
        result := v_char || result;
       when v_num = max_num-4 and substr(money, v_num, 1)<>0 then
        result := v_char || '万' || result;
        when v_num = max_num-4 and substr(money, v_num, 1)=0 then
        result := '万'|| result;
        when v_num = max_num-8 and substr(money, v_num, 1)<>0 then
        result := v_char || '亿' || result;
        when v_num = max_num-8 and substr(money, v_num, 1)=0 then
        result := '亿'|| result;
        else  retcode:=2;
    end case;
      v_num := v_num - 1;
    exit when v_num=0;
  end loop;
  select translate(regexp_replace(regexp_replace(result,'0+(元|万)','\1'),'0+','0'),'0123456789','零壹贰叁肆伍陆柒捌玖')
    into Result
    from dual;
    return(Result);
  exception
    when v_error then
     raise_application_error(1,'超出了计算范围');
  when others then
        retcode := 2 ;
        errbuf := sqlcode||': '||sqlerrm ;
        raise_application_error(2,errbuf);
end lcw_get_money;
 
PS: 想办法完美解决了恼人的0的问题,但是程序可读性随强,但是还没有融入巧妙的算法,属于自己认识水平有限的问题,还要继续努力。
 
  2、同事的解法
 
create or replace function xf_get_money(money in VARCHAR2)
   return varchar2 is
     c_money  VARCHAR2(12);
     b_string VARCHAR2(80);
     m_string VARCHAR2(60) := '分角圆拾佰仟万拾佰仟亿';
     n_string VARCHAR2(40) := '壹贰叁肆伍陆柒捌玖';
     n         CHAR;
     len       NUMBER(10);
     i         NUMBER(10);
     tmp       NUMBER(12);
     is_zj     BOOLEAN;
     z_count   NUMBER(10);
     l_money   NUMBER;
     l_money1  NUMBER;
     l_sign    VARCHAR2(10);
   BEGIN
     l_money1 :=to_number(money);
     l_money :=abs(money);
     IF l_money1 < 0 THEN
       l_sign := '负' ;
     ELSE
       l_sign := '';
     END IF;
     tmp     := round(l_money, 2) * 100;
     c_money := rtrim(ltrim(to_char(tmp, '999999999999')));
     len     := length(c_money);
     is_zj := TRUE;
     z_count := 0;
     i       := 0;
     WHILE i < len LOOP
       i := i + 1;
       n := substr(c_money, i, 1);
       IF n = '0' THEN
         IF len - i = 6 OR len - i = 2 OR len = i THEN
           IF is_zj THEN
             b_string := substr(b_string, 1, length(b_string) - 1);
             is_zj   := FALSE;
           END IF;
           IF len - i = 6 THEN
             b_string := b_string || '万';
           END IF;
           IF len - i = 2 THEN
             b_string := b_string || '圆';
           END IF;
           IF len = i THEN
             b_string := b_string || '整';
           END IF;
           z_count := 0;
         ELSE
           IF z_count = 0 THEN
             b_string := b_string || '零';
             is_zj   := TRUE;
           END IF;
           z_count := z_count + 1;
         END IF;
       ELSE
         b_string := b_string || substr(n_string, to_number(n), 1) ||
                     substr(m_string, len - i + 1, 1);
         z_count  := 0;
         is_zj  := FALSE;
       END IF;
     END LOOP;
     b_string := l_sign || b_string ;
     RETURN b_string;
EXCEPTION
    WHEN OTHERS THEN
       RETURN(SQLERRM);
END;
 
PS:程序写的比较简洁,巧妙的使用了算法,减低了编程的劳动强度,但是对其对0的处理方法,依然表示还有疑惑,留待以后继续考证研究。

 

   经过中午的推敲,咱明白了同事的做法的技巧思路在于考虑加0策略,而我自己思路在于减0,由于需要加0的情况较少,所以此题更适合采用加0算法。于是咱就用新学的raise_application_error 的函数进行了,从右向左的扫描,成功的完成如上的需求:

 

   3、改良过的程序

 

create or replace function lcw_convert_money(money in number) return varchar2 is
  money_1 number;
  max_num   number := 0;
  m_char varchar2(18):='壹贰叁肆伍陆柒捌玖';
  n_char varchar2(22):='分角圆拾佰仟万拾佰仟亿';
  v_num     number := 0;
  v_char    varchar2(200);
  v_judge number;
  Result varchar2(200);
begin
  money_1:=money*100;
  max_num:=length(money_1);
  v_num := max_num;
  case when max_num>11 then
    raise_application_error(-20988,'超出了函数的运算范围!');
    else
    for i in 1..v_num loop
     v_char:=substr(money_1, v_num,1);
     case when v_char=0 then
          case when v_num=max_num or max_num-v_num=2 or max_num-v_num=6 then
               case when v_num=max_num then
                 result:= '整';
                    when max_num-v_num=2 then
                 result:='圆'||result;
                    when max_num-v_num=6 then
                 result:='万'||result;
               end case;
           else case when v_judge=0 then
                 result:='零'||result;
                 v_judge:=1;
                else null;
                 end case;
           end case;
        else result:=substr(m_char,v_char,1)||substr(n_char,i,1)||result;
             v_judge:=0; 
     end case;
     v_num := v_num - 1;
    exit when v_num=0;
  end loop;
    return(Result);
    end case;
  exception
  when others then
     return(sqlcode||':'||sqlerrm);
end lcw_convert_money;

 

经过测试可以顺利完成如上需求,并且中间经过确认case else逻辑判断是并行的,比if..else执行效率要高,也是对咱细节的优化吧。

 

 

posted @ 2012-07-11 16:36  刘伟聪  阅读(244)  评论(0编辑  收藏  举报