现在的位置: 首页 > 综合 > 正文

小学期总结四:一夜发白《千字文》

2017年11月10日 ⁄ 综合 ⁄ 共 2517字 ⁄ 字号 评论关闭

背景
在古代中国,《三字经》、《百家姓》、《千字文》被合称为三、百、千,都是非常重要的启蒙教育课本,广为流传。而其中问世最早的《千字文》更凭借其优美的文字、华丽的辞藻成为中华传统文化的一个重要组成部分,得到了人们的普遍重视和喜爱。

《千字文》的作者,是梁武帝时代官拜散骑员外郎的周兴嗣。历来在正史上的记载,就这样一笔带过,但据私家笔记的野史记载,内容不是这样简单了。周兴嗣同梁武帝本来便是文字之交的朋友,在萧齐时代,还在朝廷上有过同僚之谊。到了梁武帝当了皇帝,那就变成君臣的关系。由朋友变君臣,说是关系不错,其实,伴君如伴虎,反是最糟糕的事,周兴嗣有一次不小心得罪了梁武帝,梁武帝一怒之下,想杀他或很严厉地处分他,到底还是于心不忍,只好下令把先关起来再说。但梁武帝又说了一句话,你不是文才很好吗?你能在一夜之间,把一千个不同的字,写一篇好文章,就赦你无罪。因此,周兴嗣就在一夜之间,挖空心思,写了这篇《千字文》。文章写好了,可是在一夜之间,头发、眉毛、胡子也都白了!大家要注意,用一千个不同的中文字,一夜之间,写出有关宇宙、物理、人情、世故的文间,等于写了一篇非常精简的“中国文化纲领要点”,虽然,只写到南北时期的梁朝为止,实在也太难了。梁武帝本人,才华文学都自命不凡,看了周兴嗣一夜之间之间所写的《千字文》,也不能不佩服。周兴嗣因此得到宽恕,而且还特加赏赐。

——摘自南怀瑾《原本大学微言》

现代人,一生中有机会通读千字文的机会是非常少的,很多理工科的大学生,完全没有听说过这篇神奇的文章,自然也会抱着“怀疑一切”的态度问,真的有这么神吗,真的一个重复的字都没有吗?耳听为虚,眼见为实,我们就来检验一下千字文中是不是真的没有重复的字。

不过在动手之前,先让我们花上几分钟的时间,读读《千字文》吧:简体中文版、正体中文版。

任务
请编写一个程序,从输入中读取一篇中文文章,并统计出该文章中 ASCII 字符以外的重复出现的每一个字重复出现的次数。

文章使用 UTF-8 编码,可能会出现任何可以用 UTF-8 编码表示的字符(不限于中文)。

文章中所有的字符在 UCS-2 能够表示的范围内,即字符的 Unicode 值用两个字节就可以表示。

输入
一篇文章,总字数不限、每行字符数不限。每个字重复出现的次数不超过 60000 次。

输出
按照 Unicode 编码从小到大的顺序,输出文章中 ASCII (0~127) 字符以外的每一个重复出现过的字重复出现的次数。每行包含三项内容,首先是重复的字符(以 UTF-8 编码输出),然后是该字符的 Unicode 编码值(十六进制输出,字母均使用小写,长度不足4位数的用0补齐),最后输出该字符的重复次数。

如果文章中没有出现重复的字,则输出“No repeat!”。

要做这道题必须先弄懂 UTF-8 编码和Unicode的编码方式,这篇文章写的很不错

<a href="http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html">http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html</a>

弄懂了编码方式,就容易了。

#include <stdio.h>
struct hanzi
{
	int val;
	unsigned char s[5];
}f[65536];

int main()
{
	unsigned char c,d,e,ff;
	int unic,i,aa=0;
	for (i = 1; i <= 65535; i++){
		f[i].val = 0;
	}

	while (scanf("%c", &c) != EOF){
		if ((c >> 4) < 8){
			continue;
		}
		else if ((c >> 4) == 15){
			d = getchar();
			e = getchar();
			ff = getchar();
			unic = ((c & 7) << 18) + ((d & 63) << 12) + ((e & 63) << 6) + (ff & 63);
			f[unic].val++;
			f[unic].s[0] = c;
			f[unic].s[1] = d;
			f[unic].s[2] = e;
			f[unic].s[3] = ff;
			f[unic].s[4] = '\0';
		}
		else if ((c >> 4) == 14){
			d = getchar();
			e = getchar();
			unic = ((c & 15) << 12) + ((d & 63) << 6) + (e & 63);
			f[unic].val++;
			f[unic].s[0] = c;
			f[unic].s[1] = d;
			f[unic].s[2] = e;
			f[unic].s[3] = '\0';
		}
		else if ((c >> 4) >= 12){
			d = getchar();
			unic = ((c & 31) << 6) + (d & 63);
			f[unic].val++;
			f[unic].s[0] = c;
			f[unic].s[1] = d;
			f[unic].s[2] = '\0';
		}
	}
	for (i = 1; i <= 65535; i++){
		if (f[i].val >1){
			printf("%s 0x%04x %d\n", f[i].s,i,f[i].val);
			aa = 1;
		}
	}
	if (aa == 0)
		printf("No repeat!\n");
			
	return 0;
}

注意字符要定义成 unsigned char

输入一个判断一个比较方便,占用内存较少,文件输入结束标志EOF

位运算:前5位归零 后3位不变 &7,,,左移6位 <<6

存重复的汉字,用哈希,结构体,用Unicode值做下标

全局结构体初始化,不要直接在外面初始化,要在函数内用for循环来初始化

注意调试时不要再console中直接输入,这样输的好像不是utf-8编码

用函数 FILE *freopen(const char *filename,const char *type, FILE *stream);

将程序的输入和输出重定向到事先创建的以UTF-8为编码的文本文件中

具体就是在函数中的最前面加入

freopen("D://in.txt","r",stdin);
freopen("D://out.txt","w",stdout);
scanf("%*c%*c%*c");

因为utf-8文件前三个字符是自带的,所以要把它们吃掉

抱歉!评论已关闭.