2009年5月5日星期二

有关用C实现汉字的显示3:图形模式下的中英文显示

有了以前的理论,用C实现汉字的显示对于我们来说已经变得不那么难了
那么,现在面临的一个问题是,当一个字符串里有中文字符又有英文字符时,由于一个中文字符占两个字节而一个英文字符只占一个字节,而

且他们的内码不同,如果我们还用前面所描述的方法,打印出来的肯定是乱码一堆,细心的读者会发现在

理论1里的字符串全都是中文字符,那是为了避免这一问题的出现。

  那么,怎么来解决中英文混排显示的问题呢? 其实不难,细心的读者通过阅读理论1的前几段就会发现“...于是我们的DOS前辈想了一个办法,就是将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。而剩下的低128位则留给英文字符使用,即英文的内码...”,这些话里隐含了区分中文字符与英文字符的方法,即:
从字符串中读入一个字节数据,当最高二进制位为1 说明当前字符和下一字符一起构成一个中文字符 下次从该字节的下下字节开始读数据
从字符串中读入一个字节数据,当最高二进制位为0 说明当前字符为一英文字符 下次从该字节的下一字节读数据

  理论很难懂的话就让事实来说明一切吧

/*
*图形模式下的中英文显示
*LO几又VE 16:26 2005-5-25
*字体库下载
*将字体库文件放置于编译目录下[或者更改路径参数]
*hzk16文件下载地址:
*下载字体文件
*/
#include
#include

#define MAXX 640 /*屏幕宽度*/
#define MAXY 480 /*屏幕高度*/
#define WIDTH 20 /*每一汉字宽度*/
#define HIGH 20 /*每一汉字高度*/
#define CHSIZ 2 /*英文字体大小*/

int priChi(unsigned char *); /*中文打印函数,传入参数:中文数组指针 返回值 -1 异常 0 正常*/

int X=0; /*全局变量X Y控制中文打印格式*/
int Y=0;

int main()
{
  char chinese[][60]={/*TC编译器不支持长行 所以将中文字符串以二维形式存放*/
  "我放弃清华计?????!@!a专业的保送资格而选择参加高考的消息震撼",
  "从校长到班主任到各科目任课老师都找我谈过话我有点惊异他们的变",
  "化在我获得全国信息this is a program for type Whinese words ",
  "and english words.djfkjaiejfjas>ifojaewkfjaweifjaokjdsfjiaew",
  "说起这个特别奖还真的挺有意思虽然叫全国决赛但也无非是出几个笔",
  "试题再弄个上机程序编一下限时总共是三小时规定语言是西语言或者",
  "派司卡在我花了半个小时分别用两种语言把该程序完成后我觉得坐在",
  "那实在是浪费我的大好青春于是我决定用汇编语言把它再写一遍本来",
  "我准备用微操作的十六进制码写的但考虑到时间问题只好放弃有人说",
  "是金子总会发光此话诚不欺我啊正当我热火朝天全心投入编程的时候",
  "却不知道自己已经被某人注意了很久了三小时之后我走出考场之后某",
  "人赶紧抓住我很兴奋的叫了一声小朋友这声小朋友直接导致我在数年",
  "后还经常从噩梦中惊醒同时也是我拒绝清华邀请的直接导火索我们把",
  "话题回到事发现场我在吓了很大一跳后把头转了回来一个瘦干老头正",
  "抓着我的手两眼放光的样子还似乎是略带深情的看着我我全身鸡皮疙",
  "瘩顿时争先恐后的向外钻我浑身一个机灵赶紧抖手老头似乎感觉到了",
  "异样送开我的手略带尴尬的道小朋友我自我介绍一下我是清华大学计",
  "算机系的主任受邀到比赛的现场观看顺便看看有没有什么可挖掘的人",
  "才那个你明白我的意思吧这句话很是影响清华学生理解力在我心目中",
  "的地位你这意思不就是认为我是可挖掘的人才吗我点了点头老头看我",
  "能理解显的很兴奋然后开始滔滔不决的向我介绍清华计算机专业的实",
  "力如何如何的雄厚在国内甚至国际是如何如何的有影响力最后满怀深",
  "情的看了我眼严肃的告诉我他将代表清华计算机专业欢迎我去他们那",
  "念书我苦苦忍耐着他的飞溅唾沫委婉的表示这件事非同小可我必须回",
  "家和父母商量一下然后逃也似的离开当然第一个去的地方是卫生间我",
  "的脸啊谁知道老头的唾沫会不会让我的脸起老年斑回到学校的一个礼",
  "拜后我就接到了清华正式邀请这个消息经我班主任的乌鸦嘴迅速在全",
  "校蔓延而后又经过各种渠道迅速汇总到我父母耳朵。"};

  if(-1 == priChi(chinese) )
  {/*打印异常*/
  printf("Press any key to exit...");
  fflush(stdin);
  getch();
  return 1;
}
return 0;
}

int priChi(unsigned char *chi)
{
  unsigned char charc[2];
  unsigned char mat[16][2];
  int i=VGA,j=VGAHI,k;
  int sec,pot;
  FILE *HZK;
  if((HZK=fopen("hzk16","rb"))==NULL) /*打开字体库文件*/
  {/*打开字体库失败*/
  printf("Open style file (hzk16) failed!\n");
  return -1;
  }
  initgraph(&i,&j,""); /*图形模式初始化*/
  settextstyle(0,0,CHSIZ);/*英文字符初始化*/
  while(*chi)
  {/*每循环一次在图形模式下打印一个中文或者英文字符*/
  if(*chi & 0x80) /*最高位为1 -- 中文字符*/
  {
  sec = *chi-0xa0; /*获得中文字符的区码*/
  pot = *(chi+1)-0xa0; /*获得中文字符的位码*/
  fseek(HZK,(94*(sec-1)+(pot-1))*32l,SEEK_SET);
  fread(mat,32,1,HZK);
  for(j=0;j<16;j++)
  for(i=0;i<2;i++)
  for(k=0;k<8;k++)
  if(mat[j][i] & (0x80 >> k)) /*测试为1的位则显示*/
  putpixel(X+i*8+k,Y+j,WHITE);
  chi += 2; /*指针指向下一中文字符*/
  }
  else /*最高位为0 -- 英文字符*/
  {
  charc[0] = *chi; /*为输出英文字符作准备 */
  charc[1] = '\0';
  outtextxy(X,Y,charc);/*在指定位置(图形模式)发送一个字符串*/
  chi ++; /*指针指向下一英文字符*/
  }

  X += WIDTH; /*下一字符的横坐标 */
  if(X >= MAXX) /*满一行 */
  {
  X = 0; /*归零*/
  Y += HIGH; /*下一字符的纵坐标 */
  if(Y >= MAXY) /*满一页 */
  {
  printf("press any key to print other words");
  getch();
  system("cls"); /*清屏*/
  Y = 0; /*归零*/
  }
  }
  }
  getch();
  closegraph(); /*关闭图形系统*/
  fclose(HZK); /*关闭字体文件*/
  return 0;
}

  通过这张帖子,你应该对字符的显示有了更深一层次的认识吧。

没有评论: