2 条题解

  • 4
    @ 2025-10-10 22:25:41

    本题在字符统计的基础上,需要统计汉字,而汉字属于所谓的宽字符.

    要处理本题,我们只需要一个头文件 <wchar.h> 和它提供的一些新方法.

    但在此之前,我们需要对本地化环境进行设置,以确保代码在被提交后,能正常的读入汉字.

    我们使用头文件

    #include <locale.h>
    

    并在 main() 函数中使用 setlocale() 方法对本地化环境进行设置(题目的提示中要求本地化环境使用 "C.UTF-8"):

    setlocale(LC_ALL, "C.UTF-8");
    

    宽字符的类型为 wchar_t,其中 ttype(类型)的意思. 我们首先用其创建一个宽字符串:

    wchar_t a[1024] = {};
    

    宽字符数组的长度只要略大于最长长度(1000)即可.

    接下来,我们进行代码主体部分的编写.

    读取

    题目要求我们读取一行字符串,并限定了其长度(1n10001\leqslant n\leqslant1000),因此我们考虑使用 fgets 的宽字符版本 fgetws 进行读取.

    fgets 一样,fgetws 也有三个参数,其结构如下:

    wchar_t *fgetws(wchar_t *ws, int n, FILE *stream);
    

    第一个参数 wchar_t *ws 是我们希望往哪个宽字符串中读取数据,第二个参数 int n 是字符串的最大长度,第三个参数 FILE *stream 是从哪里读取.

    我们使用 fgetws 进行读入:

    fgetws(a, 1001, stdin);
    

    其中,最长长度设置为 1001 是保证在字符串长度为 1000 时,仍能正常以空字符 '\0' 结尾. 而 stdin 则是标准输入流,用于从键盘接收输入.

    至此,读取部分就结束了.

    计数

    我们使用四个互相区分的计数变量

    int n1 = 0, n2 = 0, n3 = 0, n4 = 0;
    

    按照题目中的顺序,它们分别记录中文字符个数、英文字符个数、数字字符个数、其他字符个数.

    为了获取读入字符串的长度,我们使用 <wchar.h> 提供的另一个类似于 strlen() 的方法,即 wcslen().

    for (int i = 0; i < wcslen(a); i ++) {
        
    }
    

    以上 for 循环将在输入的宽字符串 a 中为我们逐位提取字符.

    在其内部,我们可以开始统计字符了:

    首先是汉字,根据题目的提示,汉字的范围可以是 a[i] >= L'一' && a[i] <= L'龟',其中的 L 用在字符前,表示此字符是一个宽字符. 我们直接使用即可:

    if (a[i] >= L'一' && a[i] <= L'龟') {
        n1 ++;
    }
    

    其余字符同理,将其整合后得到:

    if (a[i] >= L'一' && a[i] <= L'龟') {
        n1 ++;
    } else if ((a[i] >= L'a' && a[i] <= L'z') || (a[i] >= L'A' && a[i] <= L'Z')) {
        n2 ++;
    } else if (a[i] >= L'0' && a[i] <= L'9') {
        n3 ++;
    } else if (a[i] != L'\n') {
        n4 ++;
    }
    

    注:在判断其他字符时,为什么要判断 a[i] != L'\n'?这是因为我们不希望将换行符作为有效的能进入计数的字符. 而至于为何不使用换行符作为结尾的标志来提取字符(比如一个一个字符往下找,直到找到 L'\n' 后判断结束),这是因为我们不知道代码在进行测试时,读入的数据有没有换行符,这同样也是不使用空字符 L'\0' 作为结尾标志的原因(空字符前会包含字符串内的所有字符,包括那个不确定存不存在的换行符).

    这就是计数部分的核心代码了.

    计数结束后,将其输出即可.

    代码

    以上就是本题实现的所有细节,完整代码如下(仅供参考,不要直接复制后提交):

    #include <stdio.h>
    #include <locale.h>
    #include <wchar.h>
    wchar_t a[1024] = {};
    int main() {
        setlocale(LC_ALL, "C.UTF-8");
        fgetws(a, 1001, stdin);
        int n1 = 0, n2 = 0, n3 = 0, n4 = 0;
        for (int i = 0; i < wcslen(a); i ++) {
            if (a[i] >= L'一' && a[i] <= L'龟') {
                n1 ++;
            } else if ((a[i] >= L'a' && a[i] <= L'z') || (a[i] >= L'A' && a[i] <= L'Z')) {
                n2 ++;
            } else if (a[i] >= L'0' && a[i] <= L'9') {
                n3 ++;
            } else if (a[i] != L'\n') {
                n4 ++;
            }
        }
        printf("%d\n%d\n%d\n%d", n1, n2, n3, n4);
        return 0;
    }
    
    • 0
      @ 2025-10-11 0:17:53

      152520221 刘正潇 同学题解的基础之上进行一些补充:

      1.有关读取:

      部分同学可能会使用wscanf(const wchar_t *format, ...) (scanf的变形,适用于宽字符),这种方式会导致部分测试点无法通过,因为测试数据可能包含空格,wscanf在读取字符串时以空格为结束标志,含有空格的字符串将无法完全读入。

      2.关于for循环:

      152520221 刘正潇 同学使用wcslen()函数读取字符串长度实现循环退出,除此方法以外,判断当前元素是否为'\0'(字符串结尾标识,此处也解释了为什么要定义大于样本数据的数组)实现循环的退出也是可行的,因为在接下来的判断中我们会排除'\n',对计数无影响

      for (int a=0;i[a]!='\0';a++)
      

      3.关于判断类型:

      部分同学可能想使用isdigit()和isalpha()判断数字和字母,此方法不可行,其无法正确判断宽字符(详情自行查阅编码表和函数判断原理),应类比汉字的判断使用区间判定

      参考代码

      注意,本代码仅作参考,强烈不建议复制屎山!!

      #include<stdio.h>
      #include<wchar.h>
      #include<locale.h>
      int main()
      {
          setlocale(LC_ALL,"C.UTF-8");
          int chinese=0,english=0,digit=0,other=0;
          wchar_t i[1001];
          fgetws(i,1001,stdin);
          for (int a=0;i[a]!='\0';a++) {
              if (i[a]>=L'a'&&i[a]<=L'z'||i[a]>=L'A'&&i[a]<=L'Z')
              {
                english++;
              }
              else if (i[a]<=L'9'&&i[a]>=L'0')
              {
                digit++;
              }
              else if (i[a]>=L'一'&&i[a]<=L'鿿')
              {
                chinese++;}
              else if (i[a]!=L'\n')
              {
                other++;
              }
          }
          printf("%d\n%d\n%d\n%d\n",chinese,english,digit,other);
          return 0;
      }
      
      • 1

      信息

      ID
      103
      时间
      1000ms
      内存
      256MiB
      难度
      9
      标签
      (无)
      递交数
      1747
      已通过
      132
      上传者