shell编程/字库裁剪——编程过程
Posted 窗户
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell编程/字库裁剪——编程过程相关的知识,希望对你有一定的参考价值。
版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖。如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7704085.html 作者:窗户 QQ:6679072 E-mail:6679072@qq.com
之所以想用shell实现,是因为shell是UNIX/LINUX的工作语言,可以实现很强大的功能,所以借此话题顺带讲一下shell编程的思路。可是现实是,很多人在搞linux的同时,却写不出一个稍微复杂那么一点点的shell程序,甚至包括一些运维人员。在chinaunix的shell版里,基本会成周期性的问一些相同的简单问题,我们称之位月经贴。我实在不知道,难道是这个世界变化了,我们以前所遵守的一些东西已经过时了?从我的经验来,学习一些shell还是很有必要的,我验证很多时候都使用shell,因为方便。
shell是胶水语言,里面按理可以用其他所有的程序做零件,但传统上来说,我们还是使用POSIX下定义的一些工具,这些算传统的工具。就嵌入的编程语言来说,awk/sed/bc这些算是shell“本家”的,而python/perl这些,不太像是shell本家的。
我们构思我们的shell的功能,首先要准备的基本材料有如下:
(1)GB2312字库,字库的字体尺寸;
(2)ASCII字库,字库的字体尺寸;
(3)一个文本文件,里面包含了所有要使用的汉字。
以上的准备材料应该已经基本充足,但有的时候会要涉及到多种字体乃至多种尺寸,可在本文所给出程序的基础上扩展。另外,第三个文件我当时使用的时候是直接对于显示所用的C语言文件处理所得,截取两个双引号之间的部分即可,之所以不选择C语言文件里所有的GB2312编码汉字,是因为可能会包含注释。
那么处理出来应该是一个完整的C语言文件,我们根据第一节中的讨论,自然也可以想的出来这个C语言文件中包含了:
(1)所有ASCII可见字符的字体数组,编码连续即可。
(2)所用汉字的编码数组,编码从小到大。
(3)所用汉字的字体数字,按照编码从小到大的顺序。
(4)给出一个函数,取给定ASCII的字体的首地址。
(5)给出一个函数,取给定汉字的字体的首地址,使用二分查找法。
其中,(2)、(3)两个数组用结构体的方式合为一个数组,C语言的可读性更强一些。
那么,和其他的编程一样,我们先确定这个程序的框架:
#!/bin/bash #http://www.cnblogs.com/Colin-Cai #ASCII字库文件 ascii_font=ASC16 #ASCII字符高 ascii_height=16 #ASCII字符宽 ascii_width=8 #汉字字库文件 chinese_font=CHS16.FON #汉字高 chinese_height=16 #汉字宽 chinese_width=16 #算出每个ASCII字符字体字节数 let ascii_bytes=ascii_height*ascii_width/8 #算出每个汉字字体字节数 let chinese_bytes=chinese_height*chinese_width/8 chinese_example=sample.txt code_and_offset() { } print_font() { } filter() { } chinese_font_to_c() { } ascII_font() { } create_func() { } { code_and_offset ${chinese_example}; print_font ${chinese_font} ${chinese_bytes}; } | filter | chinese_font_to_c ${chinese_bytes} ascII_font ${ascii_font} ${ascii_bytes} create_func ${ascii_bytes} ${chinese_bytes}
我们选择了16X16的汉字字库以及16X8的ASCII字库。
最开始定义一堆变量,当然,也可以采用命令行的方式,可能更加灵活一些,不过写的复杂了一些。最后三行就是产生C语言代码的,其中第二行是产生ASCII字符字体数组,相对简单一些,最后一行是生成那两个C语言函数,这基本上是C语言是什么样,这个地方就差不多长什么样,当然如果二分法不懂,或者写个半天写不出来,建议应该回头补一补数据结构,它是基础 。
第一行是产生汉字编码、字体数组的,这个过程会比较复杂一些,我希望code_and_offset ${chinese_example}从提取出我所希望的汉字,并且编码从小到大,以便后面处理。比如加入我希望裁剪的汉字文本是“人工智能真厉害”,那么这个的输出应该是
flag 185 164 2259
flag 186 166 2355
flag 192 247 3000
flag 196 220 3349
flag 200 203 3708
flag 213 230 4957
flag 214 199 5020
前面加一个flag是为了和print_font输出区分开来,以便过管道处理的时候可以方便的区分输入的意思。
printt_font是想把整个字库文件变成可见字符,然后切割成一个完整的汉字字体一行。这个用od单条命令就可以很方便的生成如下格式:
...
00 00 18 00 18 00 18 00 18 00 18 00 18 00 18 00 18 00 18 00 18 00 00 00 18 00 18 00 00 00 00 00
00 00 02 40 02 40 02 40 02 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 02 20 02 20 02 20 02 20 3f fc 04 40 04 40 04 40 04 40 3f fc 08 80 08 80 08 80 08 80 00 00
00 00 38 38 10 10 08 20 04 40 02 80 02 80 01 00 01 00 0f e0 01 00 01 00 01 00 01 00 03 80 00 00
00 00 18 04 24 08 24 10 24 20 24 40 24 80 19 00 02 60 04 90 08 90 10 90 20 90 40 90 00 60 00 00
00 00 06 00 09 00 10 80 10 80 09 00 0a 00 04 00 1c 00 22 70 41 20 40 a0 40 44 21 a4 1e 18 00 00
00 00 10 00 10 00 10 00 20 00 20 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 0c 00 10 00 20 00 40 00 40 00 80 00 80 00 80 00 80 00 80 00 80 00 40 00 40 00 20 00 10 00 0c
60 00 10 00 08 00 04 00 04 00 02 00 02 00 02 00 02 00 02 00 02 00 04 00 04 00 08 00 10 00 60 00
00 00 01 00 01 00 01 00 21 08 11 10 09 20 05 40 03 80 02 80 04 40 08 20 10 10 00 00 00 00 00 00
...
然后这两者的输出过一个管道,处理成每一行都是一个不同的所需要的汉字,filter做了这样一个过滤。
185 164 00 00 00 08 7f fc 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 04 ff fe 00 00 00 00
186 166 02 00 01 00 7f fe 41 02 9f f4 01 00 1f f0 01 00 7f fc 01 00 1f f0 10 10 10 10 10 10 1f f0 10 10
192 247 00 08 3f fc 20 00 20 04 3f fe 22 00 22 08 23 fc 22 08 22 08 22 08 22 08 44 08 44 88 88 50 10 20
196 220 10 80 10 88 24 98 44 a0 fe c0 02 84 7c 84 44 7c 44 00 7c 88 44 98 44 a0 7c c0 44 82 54 82 48 7e
200 203 01 00 01 00 01 00 01 00 01 00 01 00 01 00 02 80 02 80 02 80 04 40 04 40 08 20 10 10 20 0e 40 04
213 230 01 00 01 08 7f fc 01 00 1f f0 10 10 1f f0 10 10 1f f0 10 10 1f f0 10 10 ff fe 08 20 10 18 20 08
214 199 20 00 22 04 3f 7e 48 44 08 44 ff c4 10 44 14 7c 22 44 42 10 9f f8 10 10 1f f0 10 10 1f f0 10 10
最后再过一个管道,生成C语言代码表示为结构体数组。
最近回头再想想管道的思维,觉得这才是一个很关键的分解,mapreduce虽然google已经不太好意思谈它了,我们也未必要觉得这是大数据的经典,一个这么粗糙的模型却被吹了十来年,感觉像浮夸风。但mapreduce这样的思想其实早已伴随我们几十年,其实这里面也有管道流的思想。甚至有次在论坛上看到有人提出,并行基本就两种基本手段,一种流水线,另一种mapreduce,想想似乎也有点道理。
扯远了,先分了块之后,再为每个函数填上代码,反复测试,这也是一个有点复杂的过程,我程序中使用了大量的awk,因为它处理文本的确很方便。代码不重要,过程中的想法才重要。
#!/bin/bash #http://www.cnblogs.com/Colin-Cai #ASCII字库文件 ascii_font=ASC16 #ASCII字符高 ascii_height=16 #ASCII字符宽 ascii_width=8 #汉字字库文件 chinese_font=CHS16.FON #汉字高 chinese_height=16 #汉字宽 chinese_width=16 #算出每个ASCII字符字体字节数 let ascii_bytes=ascii_height*ascii_width/8 #算出每个汉字字体字节数 let chinese_bytes=chinese_height*chinese_width/8 chinese_example=sample.txt code_and_offset() { od -An -v -t u1 $1 | xargs -n 1 | awk \' $1 < 161 { next } { GBH = $1 getline GBL = $1 x = (GBH-161)*94+(GBL-161) print "flag", GBH, GBL, x } \' | sort -n -k2 -n -k3 -u } print_font() { od -w$2 -An -v -tx1 $1 } filter() { awk \'BEGIN { i = 0 j = 0 n = 0 } $1 == "flag" { GBH[$4] = $2 GBL[$4] = $3 i++ next } n in GBH { print GBH[n], GBL[n], $0 if(++j >= i) exit(0) } { n++ } \' } chinese_font_to_c() { awk \'BEGIN { flag = 0 printf("typedef struct{\\n\\tunsigned char GBH;\\n\\tunsigned char GBL;\\n\\tunsigned char font[\'$1\'];\\n} chinese_font_t;\\n\\n"); } { if(flag == 0) { printf("static const chinese_font_t chinese_font[] = {\\n") flag = 1 } else { printf(",\\n") } printf("\\t{ 0x%x, 0x%x, { ", $1, $2) printf("0x%s", $3) for(i=4;i<=NF;i++) { printf(", 0x%s", $i) } printf("}}") } END { printf("\\n};\\n\\n") }\' } ascII_font() { od -w$2 -An -v -tx1 $1 | awk \'BEGIN { flag = 0; } NR>=33&&NR<=127 { if(flag == 0) { printf("static const unsigned char ascii_font[] = {\\n") flag = 1 } else { printf(",\\n") } printf("\\t0x%s", $1) for(i=2;i<=NF;i++) { printf(", 0x%s", $i) } } END { printf("\\n};\\n\\n") }\' } create_func() { cat <<EOF #define NULL ((void*)0) const unsigned char *find_ascii_font(unsigned char c) { if(c<(unsigned char)32 || c>(unsigned char)126) return NULL; return ascii_font+(int)(c-32)*$1; } #define chinese_cnt (sizeof(chinese_font)/sizeof(chinese_font_t)) const unsigned char *find_chinese_font(unsigned char GBH, unsigned char GBL) { int x, y, mid; unsigned short key, key2; key = (unsigned short)GBH<<8; key |= (unsigned short)GBL; x = 0; y = chinese_cnt; while(x<=y) { mid = (x+y)/2; key2 = (unsigned short)chinese_font[mid].GBH<<8; key2 |= (unsigned short)chinese_font[mid].GBL; if(key<key2) y = mid-1; else if(key>key2) x = mid+1; else return chinese_font[mid].font; } return NULL; } EOF } { code_and_offset ${chinese_example}; print_font ${chinese_font} ${chinese_bytes}; } | filter | chinese_font_to_c ${chinese_bytes} ascII_font ${ascii_font} ${ascii_bytes} create_func ${ascii_bytes} ${chinese_bytes}
对于上述“人工智能真厉害”,所生成的C语言文件如下
typedef struct{ unsigned char GBH; unsigned char GBL; unsigned char font[32]; } chinese_font_t; static const chinese_font_t chinese_font[] = { { 0xb9, 0xa4, { 0x00, 0x00, 0x00, 0x08, 0x7f, 0xfc, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00}}, { 0xba, 0xa6, { 0x02, 0x00, 0x01, 0x00, 0x7f, 0xfe, 0x41, 0x02, 0x9f, 0xf4, 0x01, 0x00, 0x1f, 0xf0, 0x01, 0x00, 0x7f, 0xfc, 0x01, 0x00, 0x1f, 0xf0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f, 0xf0, 0x10, 0x10}}, { 0xc0, 0xf7, { 0x00, 0x08, 0x3f, 0xfc, 0x20, 0x00, 0x20, 0x04, 0x3f, 0xfe, 0x22, 0x00, 0x22, 0x08, 0x23, 0xfc, 0x22, 0x08, 0x22, 0x08, 0x22, 0x08, 0x22, 0x08, 0x44, 0x08, 0x44, 0x88, 0x88, 0x50, 0x10, 0x20}}, { 0xc4, 0xdc, { 0x10, 0x80, 0x10, 0x88, 0x24, 0x98, 0x44, 0xa0, 0xfe, 0xc0, 0x02, 0x84, 0x7c, 0x84, 0x44, 0x7c, 0x44, 0x00, 0x7c, 0x88, 0x44, 0x98, 0x44, 0xa0, 0x7c, 0xc0, 0x44, 0x82, 0x54, 0x82, 0x48, 0x7e}}, { 0xc8, 0xcb, { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x80, 0x02, 0x80, 0x02, 0x80, 0x04, 0x40, 0x04, 0x40, 0x08, 0x20, 0x10, 0x10, 0x20, 0x0e, 0x40, 0x04}}, { 0xd5, 0xe6, { 0x01, 0x00, 0x01, 0x08, 0x7f, 0xfc, 0x01, 0x00, 0x1f, 0xf0, 0x10, 0x10, 0x1f, 0xf0, 0x10, 0x10, 0x1f, 0xf0, 0x10, 0x10, 0x1f, 0xf0, 0x10, 0x10, 0xff, 0xfe, 0x08, 0x20, 0x10, 0x18, 0x20, 0x08}}, { 0xd6, 0xc7, { 0x20, 0x00, 0x22, 0x04, 0x3f, 0x7e, 0x48, 0x44, 0x08, 0x44, 0xff, 0xc4, 0x10, 0x44, 0x14, 0x7c, 0x22, 0x44, 0x42, 0x10, 0x9f, 0xf8, 0x10, 0x10, 0x1f, 0xf0, 0x10, 0x10, 0x1f, 0xf0, 0x10, 0x10}} }; static const unsigned char ascii_font[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xd6, 0xd6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, shell编程基础