金钱(金额)格式化,每三位加上逗号分隔,Python + PHP 写法

这是我给公司的 Python 招聘准备的一道笔试题,之前看过 PHP 版本的答案,觉得很巧妙,这里把几种解法列出来。

考虑了小数的处理。

1. 字符串分片

1.1. 先算出片段数,再分片、拼接

def money_format(money):
    money_parts = money.split('.')
    integer_part = money_parts[0]
    integer_part_length = len(integer_part)
    n = (integer_part_length - 1) // 3 + 1
    parts = [integer_part[(i - n) * 3:integer_part_length - (n - i) * 3 + 3] for i in range(n)]
    money_parts[0] = ','.join(parts)
    return '.'.join(money_parts)
  • split() 方法分离整数和小数部分,最后再 join() 到一起;
  • 利用取整运算 //求片段数,先减一再加一;
  • 分片时 start 索引取负值可避免分片不足三个的处理;stop 取正值好取到最后一个字符。

1.2. 先反转再分片、拼接,再反转回来

def money_format(money):
    money_parts = money.split('.')
    integer_part = money_parts[0][::-1]
    split_parts = [integer_part[i:i + 3] for i in range(0, len(integer_part), 3)]
    money_parts[0] = ','.join(split_parts)[::-1]
    return '.'.join(money_parts)
  • 也有利用正则进行分片的:split_parts = filter(None, re.split(r'(.{1,3})', integer_part))
  • [::-1] 表示从最后位到第零位往后一位,每次向后移动一位(分片(slice)第 stop 位不包含在结果),效果相当于反转。
    附上分片的索引正负值对照:
正(包括0)
/ -(len(str)+1)
0 -len(str)
1 -(len(str)-1)
... ...
len(str)-2 -2
len(str)-1 -1
len(str) /

2. 字符串按字符循环

def money_format(money):
    money_parts = money.split('.')
    count = 0
    res = ''
    for i in range(len(money_parts[0])-1, -1, -1):
        count += 1
        if count == 4:
            count = 1
            res = ',' + res
        res = money_parts[0][i] + res
    money_parts[0] = res
    return '.'.join(money_parts)
  • 倒序循环,也就是个位开始,注意 range(start, stop, step) 方法的使用;
  • 在循环到逗号后面一位的数字时再加上逗号,免得出现 ,100,000 这样的问题

3. PHP 解法

PHP 自带 money_format() 方法,需要 strfmon,时区相关。
不用自带的方法,用字符串处理的函数:

<?php
function money_comma($money){
    $money_parts = explode('.', $money);
    $money_parts[0]=strrev(implode(',', str_split(strrev($money_parts[0]), 3)));
    return implode('.', $money_parts);
}
?>

概览

比较简单的题目,基础不牢地动山摇啊。