2. 工具模块的实现

此项目设计一个工具模块主要是将处理文字相关的功能提取出来,独立编写,独立测试。

英文的一个字符在内存中都是占用一个字节,在控制台终端中也是显示一个字符的宽度。

汉字的编码有两种:

中文的一个汉字,在 UTF8 编码时占用3个字节,在控制台终端中是显示 2 个字符的宽度。而在 GB 系列编码时大多占用 2 个字节,在控制台终端中同样是显示 2 个字符的宽度。因此需要特殊处理一下。

为了在控制台终端上能够兼容两种不同的编码。本项目编写了一个 名为 tools 的模块,相关文件有 tools.ctools.h

  1. 函数 is_utf8_code 用来返回当前编译环境是哪种编码,如果是 UTF8 编码则返回 1 , 否则返回 0。
  2. 函数 get_display_width 用于计算并返回 字符串 s 在当前环境下显示占用的宽度(以字符为单位)。
  3. 函数 center_to_display_width 是将原字符串 swidth 显示宽度生成一个新字符串并存入 target 指向的地址中,左右两则用空格填充非内容部分。

完整代码如下:

文件 tools.c

#include <string.h>
#include "tools.h"

// 测试当前文件的编码,如果是 UTF8 编码,则中文两个字占 6 字节,如果是 GBK 则占 4 字节
static int is_utf8_code(void)
{
    if (strlen("中文") == 6)
        return 1;
    return 0;
}

/* 返回字符串s的显示宽度,中文占两个英文字符的宽度
   如:
      "abc" -->3
      "中文" --> 4
      "ABC中文" --> 7
*/
int get_display_width(const char * s)
{
    int display_width = 0;
    int is_utf8 = is_utf8_code();
    // 计算字符串 s 占用屏幕控制台终端的宽度。
    while (*s) {
        if (*s >= 0 && *s <= 127) {  // 英文编码
            display_width++;  // 英文占一个字符宽
            s++;
        } else if (is_utf8) {  // 中文 UTF8 编码
            display_width += 2;  // 中文占两个字符宽
            s += 3;  // UTF8 编码一个汉字占 3 字节内存
        } else { // 中文 GBK 编码
            display_width += 2;
            s += 2;  // GBK 编码一个汉字占 2 字节内存
        }
    }

    return display_width;
}

/* 将字符串s的左右两端添加空格,使其达到 width 的显示宽度,存入 target 中
   如:
      s = 'ABC中文', width = 10
      返回:' ABC中文  '
*/
void center_to_display_width(const char * s, int width, char * target)
{
    // 得到当前字符的显示宽度
    int s_width = get_display_width(s);
    // 计算需要补充的空格数
    int fill_blank_count = width - s_width;

    // 计算左侧需要填充的空格数
    int left_blank = fill_blank_count / 2;
    // 计算右侧需要填充的空格数
    int right_blanks = fill_blank_count - left_blank;
    // 使用指针指向 target 的内容
    char * ptar = target;
    int i;

    if (fill_blank_count < 0) {  // 宽度小于 字符串宽度
        strcpy(target, s);
        return;
    }
    // 将 target 的左侧填充 fill 空格
    for (i = 0; i < left_blank; i++, ptar++) {
        *ptar = ' ';  // 填充空格
    }
    // 将 s 追加到 target 后面
    while(*s) {
        *ptar = *s;
        s++;
        ptar++;
    }
    // 将 target 的右侧填充空格
    for (i = 0; i < right_blanks; i++, ptar++) {
        *ptar = ' ';  // 填充空格
    }
    *ptar = '\0';   // 尾零
}

文件 tools.h

#ifndef __TOOLS_H
#define __TOOLS_H

/* 返回字符串s的显示宽度,中文占两个英文字符的宽度*/
int get_display_width(const char * s);

/* 将字符串s的左右两端添加空格,使其达到 width 的显示宽度,存入 target 中*/
void center_to_display_width(const char * s, int width, char * target);

#endif  // __TOOLS_H