3.数字字符串格式化 | 豆包MarsCode AI 刷题

109 阅读5分钟

题解

本题要求编写一个函数 solution,将用户输入的不带千分位逗号的数字字符串转换为带千分位逗号的格式,同时保留小数部分,并移除可能存在的前导零。下面将详细解释如何实现这一功能,并讨论代码中涉及的关键步骤和注意事项。

问题分析

首先,我们需要处理以下几个方面:

  1. 移除前导零:输入的数字字符串可能包含无用的前导零,例如 "0000123"。这些零在数值上没有意义,需要在格式化前去除。
  2. 处理特殊情况:在移除前导零后,可能出现字符串为空或以 '.' 开头的情况,例如 ".456"。此时,需要在字符串前添加 '0',以保证数字格式的正确性。
  3. 分割整数和小数部分:数字字符串可能包含小数部分,需要将其与整数部分分开,以便分别处理。
  4. 添加千分位逗号:在整数部分,每隔三位添加一个逗号,从低位(个位)开始。

解决方案

基于上述分析,我们可以按照以下步骤实现所需的功能:

1. 移除前导零

首先,使用 find_first_not_of('0') 函数找到第一个非零字符的位置。如果字符串全为零,则设定字符串为 "0"

cpp
Copy code
size_t non_zero_pos = s.find_first_not_of('0');
std::string num_str;
if (non_zero_pos == std::string::npos) {
    num_str = "0";
} else {
    num_str = s.substr(non_zero_pos);
}

解释

  • non_zero_pos 用于记录第一个非零字符的位置。
  • 如果 non_zero_posnpos,说明字符串全为零。
  • substr 函数用于截取从第一个非零字符开始的子串。

2. 处理特殊情况

在移除前导零后,如果字符串为空或以 '.' 开头,需要在前面添加 '0'

cpp
Copy code
if (num_str.empty() || num_str[0] == '.') {
    num_str = '0' + num_str;
}

解释

  • num_str.empty() 检查字符串是否为空。
  • num_str[0] == '.' 检查字符串的第一个字符是否为小数点。
  • 如果满足上述条件之一,使用字符串连接操作在前面添加 '0'

3. 分割整数和小数部分

使用 find('.') 函数查找小数点的位置,并分割整数部分和小数部分。

cpp
Copy code
std::string int_part, frac_part;
size_t dot_pos = num_str.find('.');
if (dot_pos != std::string::npos) {
    int_part = num_str.substr(0, dot_pos);
    frac_part = num_str.substr(dot_pos); // 包括 '.'
} else {
    int_part = num_str;
    frac_part = "";
}

解释

  • dot_pos 用于记录小数点的位置。
  • 如果存在小数点,将字符串分割为整数部分 int_part 和小数部分 frac_part
  • substr(0, dot_pos) 获取从起始位置到小数点前的字符串,即整数部分。
  • substr(dot_pos) 获取从小数点开始到字符串末尾的子串,即小数部分,包括小数点。
  • 如果不存在小数点,则小数部分为空。

4. 添加千分位逗号

为方便从低位开始处理,我们首先将整数部分字符串反转。

cpp
Copy code
std::reverse(int_part.begin(), int_part.end());

解释

  • reverse 函数用于将字符串的内容反转。
  • 反转后,原来的个位在字符串的起始位置。

然后,遍历反转后的整数部分,每隔三位添加一个逗号。

cpp
Copy code
std::string grouped_int;
for (size_t i = 0; i < int_part.length(); ++i) {
    if (i > 0 && i % 3 == 0) {
        grouped_int += ',';
    }
    grouped_int += int_part[i];
}

解释

  • 使用循环遍历每个字符,索引 i0 开始。
  • i 不为零且能被 3 整除时,添加一个逗号。
  • 将当前字符添加到 grouped_int 字符串中。

完成遍历后,再次将字符串反转回正确的顺序。

cpp
Copy code
std::reverse(grouped_int.begin(), grouped_int.end());

解释

  • 经过反转和添加逗号处理后,再次反转字符串,以恢复原来的顺序。

5. 组合结果

最后,将格式化后的整数部分与小数部分组合,得到最终的结果。

cpp
Copy code
std::string result = grouped_int + frac_part;

解释

  • 直接使用字符串连接操作,将整数部分和小数部分拼接。

注意事项

  1. 处理全零的情况:如果输入字符串全为零,例如 "0000",经过前导零移除后,字符串会为空。此时,我们将字符串设为 "0"
  2. 处理只有小数部分的情况:例如输入 ".456",移除前导零后字符串以 '.' 开头。根据代码逻辑,我们会在前面添加 '0',使其变为 "0.456"
  3. 处理没有整数部分的情况:类似于上一点,确保整数部分至少为 '0'
  4. 小数部分的保留:在处理过程中,小数部分保持不变,不进行任何格式化处理。
  5. 效率和鲁棒性:代码使用了标准库函数,避免了手动处理字符串的复杂性,提高了代码的可读性和可靠性。

测试样例分析

样例1

输入"1294512.12412"

  • 移除前导零:无前导零,字符串保持不变。
  • 处理特殊情况:不需要添加 '0'
  • 分割:整数部分 "1294512",小数部分 ".12412"
  • 反转整数部分"1294512" 反转为 "2154921"
  • 添加逗号:遍历 "2154921",结果为 "215,492,1"
  • 反转回去:结果为 "1,294,512"
  • 组合"1,294,512.12412"

输出"1,294,512.12412"

样例2

输入"0000123456789.99"

  • 移除前导零"123456789.99"
  • 处理特殊情况:不需要添加 '0'
  • 分割:整数部分 "123456789",小数部分 ".99"
  • 反转整数部分"123456789" 反转为 "987654321"
  • 添加逗号:遍历 "987654321",结果为 "987,654,321"
  • 反转回去:结果为 "123,456,789"
  • 组合"123,456,789.99"

输出"123,456,789.99"

样例3

输入"987654321"

  • 移除前导零:无前导零,字符串保持不变。
  • 处理特殊情况:不需要添加 '0'
  • 分割:整数部分 "987654321",小数部分为空。
  • 反转整数部分"987654321" 反转为 "123456789"
  • 添加逗号:遍历 "123456789",结果为 "123,456,789"
  • 反转回去:结果为 "987,654,321"
  • 组合"987,654,321"

输出"987,654,321"