C实现通用字符串格式化

【9-16】这个程序与前一个练习相似,但它更为通用。它按照一个指定的格式字符串对一个数字字符串进行格式化,类似许多BASIC编码器所提供的“print using”语句。函数的原型如下:

int format(char *format_string, char const *digit_string);

digit_string中的数字根据一开始在format_string中找到的字符从右到左逐个复制到format_string中。注意被修改后的format_string就是这个处理过程的结果,当你完成时,确定format_string依然是以NUL字节结尾的。根据格式化过程中是否出现错误,函数返回真或假。

格式字符串可以包括下列字符:

#  在两个字符串中都是从右向左进行操作,格式字符串中的每个#字符都被数字字符串中的下一个数字取代,如果数字字符串用完,格式字符串中所有剩余的#字符由空白代替(但存在例外,请参见下面对小数点的讨论)。

, 如果逗号左边至少有一位数字,那么它就不作修改。否则它由空白取代。

.   小数点始终作为小数点存在。如果小数点左边没有一位数字,那么小数点左边的那个位置以及右边直到有效数字为止的所有位置都由0填充。

下面的例子说明了对这个函数的一些调用的结果。符号◌用于表示空白。

为了简化这个项目,你可以假定格式字符串所提供的格式总是正确的。最左边至少有一个#符号,小数点和逗号的右边也至少有一个#符号。而且逗号绝不会出现在小数点的右边,你需要进行检查的错误只有:

a  数字字符串中的数字多余格式字符串中的#符号

b  数字字符串为空

发生这两种错误时,函数返回假,否则返回真。如果数字字符串为空,格式字符串在返回时应未作修改。如果你使用指针而不是下标来解决问题,你将会学到更多的东西。

 提示:开始时让两个指针分别指向格式字符串和数字字符串末尾,然后从右向左进行处理,对于作为参数传递给函数的指针,你必须保留它的值,这样你就可以判断是否到达了这些字符串的左端。


这个题目的需求很复杂,不过题目也给出了解题的思路提示:

1、首先用2个指针分别指向格式字符串尾部和要转换的字符串尾部。

       然后从右至左依次使用数字字符串字符替换格式字符串对应位置为#的字符。

       遇到为逗号“,”,跳过,因为格式字符串和数字字符串都是一样的。

2、如果格式字符串还未处理完毕,说明数字字符串比格式字符串短,需要空格和0。

      剩余的格式字符串位置如果是#,则直接替换为空格。

      如果是小数点,就比较麻烦,首先小数点后面到实际的位数前要补0,前面的步骤已经替换成空格了,可以直接使用一个循环将小数点后面的空格全部替换为0即可。然后再再小数点左侧替换为0。

这个问题的思路核心主要有2点:

1、将#替换为对应位置的数字,格式字符串和数字字符串任意一个字符串检索结束即替换结束。

2、如果是格式字符串还未检索替换完,就代表数字字符串短,需要做补空格和0的操作。补空格比较简单,直接把剩余的#换成空格即可,但是如果遇到了小数点,就很麻烦,需要小数点前后分开处理。

#include <stdio.h>
#include <string.h>


typedef short int int16_t;
typedef int int32_t;


#define TRUE 1
#define FALSE 0
#define NUL '\0'

int format(char *format_string, char const *digit_string) {
    char *patternp, *digitp;
    if(format_string == NULL || digit_string == NULL) {
        return FALSE;
    }

    //分别指向format_string和digit_string尾部
    patternp = format_string + strlen(format_string) - 1;
    digitp = digit_string + strlen(digit_string) - 1;
    if(digitp < digit_string) {
        return FALSE;
    }

    //替换#为相应位置的数字,逗号跳过、
    while(patternp >= format_string && digitp >= digit_string) {
        if(*patternp == '#') {
            *patternp-- = *digitp--;
            continue;
        }
        patternp--;
    }

    //如果格式字符串还未到最左边,即格式字符串长于数字字符串
    while(patternp >= format_string) {
        //如果遇到小数点,需要处理替换空格为0
        if(*patternp == '.') {
            char *p0;
            //逗号到实际的实际的数字之前将空格替换为0
            for(p0 = patternp + 1; *p0 == ' ';  *p0++ = '0'){
                ;
            }

            //逗号左侧补0
            *--patternp = '0';
            --patternp;
            continue;
        }
        //左边补充空格
        *patternp-- = ' ';

    }

    //如果还剩有数字字符串就出错,返回FALSE
    return digitp < digit_string;
}


int main() {

    char format_str[15] = "#####";
    int rs = format(format_str, "12345");
    printf("%d, %s\n", rs, format_str);


    strcpy(format_str, "#####");
    rs = format(format_str, "123");
    printf("%d, %s\n", rs, format_str);


    strcpy(format_str, "##,###");
    rs = format(format_str, "1234");
    printf("%d, %s\n", rs, format_str);

    strcpy(format_str, "##,###");
    rs = format(format_str, "123");
    printf("%d, %s\n", rs, format_str);

    strcpy(format_str, "##,###");
    rs = format(format_str, "1234567");
    printf("%d, %s\n", rs, format_str);


    strcpy(format_str, "#,###,###.##");
    rs = format(format_str, "123456789");
    printf("%d, %s\n", rs, format_str);

    strcpy(format_str, "#,###,###.##");
    rs = format(format_str, "1234567");
    printf("%d, %s\n", rs, format_str);

    strcpy(format_str, "#,###,###.##");
    rs = format(format_str, "123");
    printf("%d, %s\n", rs, format_str);


    strcpy(format_str, "#,###,###.##");
    rs = format(format_str, "1");
    printf("%d, %s\n", rs, format_str);


    strcpy(format_str, "#####.#####");
    rs = format(format_str, "1");
    printf("%d, %s\n", rs, format_str);

    return 0;
}

输出:

1, 12345
1,   123
1,  1,234
1,    123
0, 34,567
1, 1,234,567.89
1,    12,345.67
1,         1.23
1,         0.01
1,      0.00001

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值