zoukankan      html  css  js  c++  java
  • 【转】Delphi货币类型转中文大写金额

    unit TU2.Helper.Currency;
     
    interface
     
    function CurrencyToChineseCapitalCharacter(const AValue: Currency; const ADecimals: Cardinal=4): string;
    function CurrencyToString(const AValue: Currency; const ADecimals: Cardinal=4): string;
     
    implementation
     
    uses System.SysUtils, System.Math;
     
    function CurrencyRound(var U: UInt64; const ADecimals: Cardinal): Integer; inline;
    var
      W: UInt64;
    begin//Bankers-rounding
      Result := 4-ADecimals;
      if Result<0 then
        Result := 0
      else if Result>0 then
      begin
        case Result of
          1:begin   //li
            DivMod(U, 10, U, W);
            if (W > 5) or ((W = 5) and Odd(U)) then
              Inc(U);
          end;
          2:begin  //fen
            DivMod(U, 100, U, W);
            if (W > 50) or ((W = 50) and Odd(U)) then
              Inc(U);
          end;
          3:begin  //jiao
            DivMod(U, 1000, U, W);
            if (W > 500) or ((W = 500) and Odd(U)) then
              Inc(U);
          end;
          4:begin  //yuan
            DivMod(U, 10000, U, W);
            if (W > 5000) or ((W = 5000) and Odd(U)) then
              Inc(U);
          end;
        end;
      end;
    end;
     
    function CurrencyToChineseCapitalCharacter(const AValue: Currency; const ADecimals: Cardinal=4): string;
    const//Currency: [-922337203685477.5807, 922337203685477.5807]
      CCCNegative = '';
      CCCZheng = '';
      CCCNumbers: array[0..9] of Char = ('','','','','','','','','','');
      CCCUnits: array[0..18] of Char = ('', '', '', '', '','','','','',
                                         '','','','亿','','','','','','');
    var
      U, W: UInt64;
      Digits, Idx, ZeroFlag: Integer;
      Negative: Boolean;
      Buff: array[0..38] of Char;
    begin
      U := PUInt64(@AValue)^;
      if U <> 0 then
      begin
        Negative := (U and $8000000000000000) <> 0;
        if Negative then
          U := not U + 1;
        Digits := CurrencyRound(U, ADecimals);
        if U<>0 then
        begin
          //Try skip trailing zero
          repeat
            DivMod(U, 10, U, W);
            Inc(Digits);
          until W<>0;
          Dec(Digits);
          Idx := 38;
          if Digits>=3 then
          begin
            Buff[Idx] := CCCZheng;
            Dec(Idx);
            if Digits>4 then
            begin
              Buff[Idx] := CCCUnits[4];
              Dec(Idx);
              if Digits>17 then
              begin
                Buff[Idx] := CCCUnits[17];
                Dec(Idx);
              end else if Digits>12 then
              begin
                Buff[Idx] := CCCUnits[12];
                Dec(Idx);
              end else if Digits>8 then
              begin
                Buff[Idx] := CCCUnits[8];
                Dec(Idx);
              end;
            end;
          end;
          Buff[Idx] := CCCUnits[Digits];
          Dec(Idx);
          Buff[Idx] := CCCNumbers[W];
          Dec(Idx);
          //Do Split
          ZeroFlag := 0;
          while U<>0 do
          begin
            Inc(Digits);
            DivMod(U, 10, U, W);
            if Digits in [4,8,12,17] then
            begin
              if ZeroFlag>0 then
              begin
                Buff[Idx] := CCCNumbers[0];
                Dec(Idx);
              end else if (ZeroFlag<0) and (Digits>8) then
                Inc(Idx);
              Buff[Idx] := CCCUnits[Digits];
              Dec(Idx);
              if W<>0 then
              begin
                Buff[Idx] := CCCNumbers[W];
                Dec(Idx);
                ZeroFlag := 0;
              end else
                ZeroFlag := -1;
            end else begin
              if W<>0 then
              begin
                if ZeroFlag>0 then
                begin
                  Buff[Idx] := CCCNumbers[0];
                  Dec(Idx);
                end;
                Buff[Idx] := CCCUnits[Digits];
                Dec(Idx);
                Buff[Idx] := CCCNumbers[W];
                Dec(Idx);
                ZeroFlag := 0;
              end else begin
                if ZeroFlag=0 then
                  ZeroFlag := 1;
              end;
            end;
          end;
     
          if Negative then
            Buff[Idx] := CCCNegative
          else Inc(Idx);
     
          //Copy Result
          Digits := 38+1-idx;
          SetLength(Result, Digits);
          Move(Buff[idx], PChar(Result)^, Digits * SizeOf(WideChar));
          Exit;
        end;
      end;
      Result := CCCNumbers[0]+CCCUnits[4]+CCCZheng;
    end;
     
    function CurrencyToString(const AValue: Currency; const ADecimals: Cardinal=4): string;
    const
      NegativeChar = '-';
      DecimalDotChar = '.';
    var
      U: UInt64;
      Digits: Integer;
      Negative: Boolean;
    begin
      U := PUInt64(@AValue)^;
      Negative := (U and $8000000000000000) <> 0;
      if Negative then
        U := not U + 1;
      Digits := CurrencyRound(U, ADecimals);
      Result := UIntToStr(U);
      if Digits<4 then
        Result := Result.Insert(Result.Length+Digits-4, DecimalDotChar);
      if Negative then
        Result := NegativeChar + Result;
    end;
     
    end.

    在Delphi中,为了实现货币数值运算中的严格精度要求,内部把货币类型数据当作一个放大10000倍的64位整数来处理。这样根据64位整数的范围,可以得出货币类型Currency的范围是 [-922337203685477.5807; 922337203685477.5807]。
    货币类型一个最常见的应用场景是金额大写转换,网上都是一些先将货币转字符串后再对字符串处理的代码,而且有些方法在有些情况下不满足金额大写规范,这里给出一个直接转换的方法。

    附: 金额大写规范
    一、人民币大写金额数字到“元”为止的,在“元”之后,应写“整”(或“正”)字;在“角”之后,可以不写“整”(或“正”)字;大写金额数字有“分”的,“分”后面不写“整”(或“正”)字。
    二、阿拉伯数字小写金额数字中有“0”时,人民币大写应按照汉语语言规律。举例如下:
    1. 阿拉伯金额数字中间有“0”时,人民币大写要写“零”字。如¥1409.50,应写成人民币陆壹仟肆佰零玖元伍角。
    2. 阿拉伯金额数字中间连续有几个“0”时,人民币大写金额中间可以只写一个“零”字。如¥6007.14,应写成人民币陆仟零柒元壹角肆分。
    3. 阿拉伯金额数字万位和元位是“0”;或者数字中间连续有几个“0”,万位(或元位)也是“0”,但千位(或角位)不是“0”时;中文大写金额中可以只写一个零字,也可以不写“零”字。如¥1680.32,应写成人民币壹仟陆佰捌拾元零叁角贰分或者写成人民币壹仟陆佰捌拾元叁角贰分。又如¥107000.53,应写成人民币壹拾万柒仟元零伍角叁分或者写成人民币壹拾万零柒仟元伍角叁分。
    4. 阿拉伯金额数字角位是“0”,而分位不是“0”时,中文大写金额“元”后面应写“零”字。如¥16409.02,应写成人民币壹万陆仟肆佰零玖元零贰分,又如¥325.04.应写成人民币叁佰贰拾伍元零肆分。
    ————————————————
    版权声明:本文为CSDN博主「tht2009」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/tht2009/article/details/73287225

    以上为作者原文内容,我对CurrencyToChineseCapitalCharacter函数在Android及Windows10上做了测试,结果正常。Delphi 版本10.3.2.感谢作者的分享!这是一个最有效率的实现方法!

  • 相关阅读:
    操作系统实验报告-信号量的实现和应用
    操作系统实验报告-系统调用
    操作系统实验报告-熟悉实验环境
    Linux下JDK环境变量配置
    BATMAN.adv系列07 过度泛洪的遏制策略与网络重组
    BATMAN.adv系列06 协议栈结构
    BATMAN.adv系列05 数据结构分析
    BATMAN.adv系列04 TVLV包
    BATMAN.adv系列01:BATMAN.adv IV 概述
    Kudu、Hudi和Delta Lake的比较
  • 原文地址:https://www.cnblogs.com/kinglandsoft/p/11510558.html
Copyright © 2011-2022 走看看