文档章节

【转】Delphi货币类型转中文大写金额

o
 osc_5yejhemb
发布于 2019/09/12 10:31
字数 1221
阅读 37
收藏 0

行业解决方案、产品招募中!想赚钱就来传!>>>

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.感谢作者的分享!这是一个最有效率的实现方法!

 

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
SQLServer实现split分割字符串到列

网上已有人实现sqlserver的split函数可将字符串分割成行,但是我们习惯了split返回数组或者列表,因此这里对其做一些改动,最终实现也许不尽如意,但是也能解决一些问题。 先贴上某大牛写的s...

cwalet
2014/05/21
9.5K
0
树莓派(Raspberry Pi):完美的家用服务器

自从树莓派发布后,所有在互联网上的网站为此激动人心的设备提供了很多有趣和具有挑战性的使用方法。虽然这些想法都很棒,但树莓派( RPi )最明显却又是最不吸引人的用处是:创建你的完美家用...

异次元
2013/11/09
5.2K
8
表单验证插件--Jquery表单验证插件

目前支持对以下格式的值进行验证: cnum-(纯数字), char-(纯字母), zwen-(中文), bysc-(字母开头), mail(邮箱), yzbm(邮政编码) 其中的‘’表示长度,比如“zwen1-5”表示中文1-5位的长度。同...

huanganiu
2013/01/23
4.4K
0
代码生成器--Codgen

Codgen是一个基于数据库元数据模型,使用freemarker模板引擎来构建输出的代码生成器。freemarker的数据模型结构通常来说都是一个Map树状结构模型,codgen也不例外,它的数据模型这棵树的根节...

黄天政
2013/01/29
1.4W
2
MySQL全文搜索引擎--mysqlcft

MySQL在高并发连接、数据库记录数较多的情况下,SELECT ... WHERE ... LIKE '%...%'的全文搜索方式不仅效率差,而且以通配符%开头作查询时,使用不到索引,需要全表扫描,对数据库的压力也很...

张宴
2012/11/29
1.6W
2

没有更多内容

加载失败,请刷新页面

加载更多

低代码平台,让企业开发不再是难事

近几年,企业面临数字化转型带来的压力,为了快速适应行业变化和赶超竞争对手,在高级技术人才缺乏的情况下,低代码开发获得了企业的青睐。 何为低代码开发,低代码开发平台(LCDP)是无需编...

osc_veyfyz58
7分钟前
0
0
【科创人独家】华旦天使张洁:风口是创业者的造物,投资本质是件农活

在投资界活跃着一批乘风破浪的姐姐们,江湖人敬称一声“花姐”的华旦天使投资创始人张洁是个中代表:言谈飒爽,举止利落,洞察力十足。 技术背景创业者 宜:创新、洞察 忌:轴、轻视销售 科创...

osc_lc4icfkt
9分钟前
0
0
霍尼韦尔(中国)推出数字化劳动力管理解决方案套件,以支持健康合规性和远程操作

休斯敦霍尼韦尔(中国)近期宣布了一个完整的模块化软件解决方案,以帮助工业公司在员工返回工作场所时强制遵守关键的健康和安全要求,包括体温检查和自动进入管理流程,更多信息尽在振工链。...

osc_ju8o7gji
9分钟前
0
0
萤石云摄像头调整码流,画面模糊的处理

近期在将萤石云合并到监控主机时发现画面只有750左右,原以为是海康威视主机的问题,必竟两个产品系列,后我又购买了萤石云主机进行测试还是一样。经过与售后沟通他们给出了调整画面的方案,...

osc_5h5udyht
11分钟前
0
0
Oracle 锁排查SQL

查询锁SQL或ASH报告 select sql_text from v$sql where hash_value in (select sql_hash_value from v$session where sid in (select session_id from v$locked_object)); 查询TX锁 set line......

osc_qgfjs4a5
12分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部