PHP 求助 阿拉伯数字转中文数字

回复列表(27|隐藏机器人聊天)
  • @Ta / 2022-04-27 / /
    被禁言
    用户被禁言,发言自动屏蔽。
  • @Ta / 2022-04-28 / /

    @无期徒刑,简单优化下,看来这正则确实比纯数组遍历耗时间。另外,该正则已可去除“一十”开头的“一”

    function better_convert_to_chinese_by_regex(int $n): string
    {
        if ($n <= 0) return '零';
        $r = '';
        $n = (string)$n;
        $s = '#B#A#G#C#B#A#F#C#B#A#E#C#B#A#D#C#B#A#';  // 64位 PHP 最大整数也就19位十进制
    
        for ($i = strlen($s) - 1, $j = strlen($n); $j > 0; $i -= 2) {
            $s[$i] = $n[--$j];
        }
        $d = preg_replace_callback(
            '/(?J)^[^1-9]*(?(?=1A)1)|(?<z>0)[0ABC]*(?:(?=[1-9])|(?<z>(?=[D-J]|$)))|'.
            '(?<b>[D-J])(?<z>0)[0A-L]*(?:(?=[1-9])|(?<z>$))/',
            fn($m) => ($m['b'] ?? '') . ($m['z'] ?? ''),
            $s,
        );
        for ($i = 0, $l = strlen($d); $i < $l; $i++) {
            $r .= unnamed[ord($d[$i]) - ord('0')];
        }
    
        return $r;
    }
    

    耗时如下,速度比纯数组版本差一点儿,但可读性好些,更容易修改(算了,可读性就那样,这正则我也要理解半天)

    $ time php main.php < 65536_nums.txt >/dev/null
    
    real    0m0.837s
    user    0m0.688s
    sys     0m0.141s
    

    那几个数字的测试:

    $ xargs -n1 <<<"100 101 120217 812368 1024842940147 $(((1 << 63) - 1))" | php main.php
    100 一百
    101 一百零一
    120217 十二万零二百一十七
    812368 八十一万二千三百六十八
    1024842940147 一兆零二百四十八亿四千二百九十四万零一百四十七
    9223372036854775807 九百二十二京三千三百七十二兆零三百六十八亿五千四百七十七万五千八百零七
    

    Python去掉开头“一十”的“一”后的版本一致:

    $ diff <(python3 main.py < 65536_nums.txt | sed 's/ 一十/ 十/') <(php main.php < 65536_nums.txt)
    $
    
  • @Ta / 2022-04-27 / /

    @无期徒刑,这也用不到啥算法吧,关键有大佬贡献了核心正则,理解思路就容易改了

    技能的东西慢慢积累呗,比如这两天也学了点PHP

  • @Ta / 2022-04-27 / /

    @无期徒刑,我对比了下 那个C#正则 和 你的PHP版本,发现结果有出入

    数字 你的PHP输出 C#正则输出
    101000 一十万一千 一十万一千
    101001 一十万一千零一 一十万一千零一
    101010 一十万一千零一十 一十万一千零一十
    101011 一十万一千零一十一 一十万一千零一十一
    101100 一十万一千一百 一十万一千一百
    101101 一十万一千一百零一 一十万一千一百零一
    101110 一十万一千一百一十 一十万一千一百一十
    101111 一十万一千一百一十一 一十万一千一百一十一

    要重新思考下。。

  • @Ta / 2022-04-27 / /

    @无期徒刑中文数字_百度百科说:

    1. 阿拉伯金额数字万位和元位是"0",或者数字中间连续有几个"0",万位、元位也是"0",但千位、角位不是"0"时,中文大写金额中可以只写一个零字,也可以不写"零"字。如¥1680.32,应写成人民币壹仟陆佰捌拾元零叁角贰分,或者写成人民币壹仟陆佰捌拾元叁角贰分,又如¥107000.53,应写成人民币<u>壹拾万柒仟元零伍角叁分</u>,或者写成人民币<u>壹拾万柒仟元伍角叁分</u>。

    两者好像都可以,不算错误。。

    本来那个C#版本就是转换成中文金额的,被改成转普通中文数字了。。

    你看你要是不接受的话,再动手改改吧

  • @Ta / 2022-04-29 / /
    被禁言
    用户被禁言,发言自动屏蔽。
  • @Ta / 2022-04-29 / /

    @无期徒刑,数组遍历版有更新(在13楼和17楼),测下来速度相比原来有5%~10%的提升,

    但牺牲了点可读性(反正本来就没有多少了)

    具体一点儿是将求商求余换成位运算(看来PHP不会自动优化这些啊),

    以及更充分利用了已知信息,减少重复冗余逻辑判断

  • @Ta / 2022-04-29 / /
    被禁言
    用户被禁言,发言自动屏蔽。
添加新回复
回复需要登录