编码概述与Apache/PHP/HTML/Javascript中的编码

程序就是数据结构+算法,还有个重要的问题,就是编码!编码是信息从一种形式或格式转换为另一种形式的过程,有诸如字符/文字/语义/PCM等多种编码。
这篇文章只限于字符编码(Character encoding),作为程序员或是多数计算机工作者,你可能研究或看过很多编码ASCII/GB(K)/Unicode(utf8/utf16/utf32)/BIG5/ISO等,但还未搞清楚它到底是什么东东,它们有什么区别和联系,if so,可以继续看下文啦。

简约的前置总结:ASCII是美标,用一个字节表示字母/符号;GBK是国标,用两个字节表示汉字;UTF-8是UNICODE的改进版,兼容几乎所有语言符号,最为流行通用。

ASCII,美国信息交换标准编码,简称“美标”。大家知道,美国抢占了计算机与互联网的先机,美标自然地成为了国际上大部分电脑的通用编码,它规定用从0到127的128个数字来代表信息的规范编码,其中包括33个控制码、1个空格码、94个形象码(英文字母,阿拉伯数字,标点符号等)。我们平时阅读的英文电脑文本,就是以形象码的方式传递和存储的。

GB2312,老美的美标虽通用,但不适合博大精深的中文。1981年我国开始实施的一套国家标准GB2312,把六千余汉字、标点符号、外文字母等,整个字符集分成94个区,每区有94个位。例如“中”字在方阵中处于第54区第48位,它的区位码就是5448。然而GB编码文字较少,致使GBK的出现。

GBK,国G标B扩展K,向下兼容GB-2312编码,向上支持ISO 10646.1国际标准,共收录汉字21003个、符号883个、提供1894个造字码位,简、繁体字融于一库。GBK 采用双字节表示,总体编码范围为 8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE 之间,剔除 xx7F 一条线。总计23940个码位,共收入 21886 个汉字和图形符号。(另外,BIG5码是针对繁体汉字的汉字编码)
ISO1993年,国际标准ISO10646 定义了通用字符集(Universal Character Set, UCS)。 UCS 是所有其他字符集标准的一个超集。

UNICODE的渊源:中日韩等国家使用的语言中字符多达几千个,当计算机普及到此时,原来字符采用的单字节编码(最多只可容纳2^8=256个字符),既然一个字节不够,人们就采用两个字节,但其中的ASCII码等仍用单字节表示。问题出现了:因为每当涉及到双字节字符串的处理时,总是要判断当中的一个字节到底表示的是一个字符还是半个字符,如果是半个字符,那是前一半还是后一半?
最后两个标准组织合作使Unicode诞生,Unicode对每个字符都固定使用两个字节即16位表示,于是当处理字符时,不必担心只处理半个字符。Unicode在网络、Windows系统和很多大型软件中得到应用。

UTF-8:为了提高等宽字节的Unicode的编码效率,于是出现了UTF-8编码,也是迄今为止最为通用流行的编码,UTF-8可以根据不同的符号自动选择编码的长短。比如英文字母可以只用1个字节就够了。UTF-8的编码是这样得出来的,以”汉”这个字为例:
“汉”字的Unicode编码是\u6c49,然后把\u6c49通过UTF-8编码器进行编码,最后输出的UTF-8编码是汉

未完待续。。。

Don't Repeat Yourself - 编程开发原则

1. Do not repeat yourself(重构、抽象...)

2. 工具能做的麻烦事,不要自己做(格式化、语法检查...)

IDE能做的事儿,不要浪费自己时间去做。
把时间用在代码逻辑、性能考虑上。

3. 接口方法,只做应该做的事,不多不乱,保持原数据结构/顺序。

例子:
任务页面有召集人(多个)的列表,是后台运营人员填写的,有时第一次访问时顺序有混乱,之后访问右正常了。觉得很奇怪,看代码知道了 原来是缓存搞的鬼!

背景:
微博的内容产品几乎都有好友/粉丝 与 物 的关系,所以通过array(uid,uid,uid,...)取用户详细信息的方法,是早已抽象好的,逻辑是:对传进来的array进行缓存查找,得到已缓存的条目未命中的uid列表,再以此查库将返回结果追加到已缓存的条目,返回结果。

策略不错,但有个小问题,参数传进来可能是有顺序的,所以期望的结果集的顺序应该是与参数一致的。
有两个办法,1改接口、2重新排序,因为作为调用方不便改接口,所以重新排序!

怎么排呢,经同事指正,几行代码:

$users = Dr_User::get_user_infos($uids, false);//结果集已经乱序了

$flip_users = array_flip($uids);//反转uid列表,array(uid=>0,uid=>1,...),再遍历users存到对应键上
foreach ($users as $user) {
    $flip_users[$user['id']] = $user;
}
$users = $flip_users;
unset($flip_users);

结论:如果很多调用方都有保持顺序的需求,接口的设计就该添加一个参数以控制结果是否保持顺序。

4. 务必打开所有错误显示,包括NOTICE级

5. 变量的检查,统一在view controller里做

6. 明确开发/生产环境...

...

Tips

  1. 新增/修改时,sql语句慎用replace,当字段中有主键和唯一键时,若已有记录,修改的实际操作是:将原纪录删除,新插入纪录,这显然不是期望的处理方式。
  2. 在做客户端API时,有时需要一个默认的图片card,不希望它跳转或作为普通图片可查看大图,只是让它作为默认显示(something like 背景图)
'pic_items' => array(
    '0' => array(
        'pic' => 'http://example.com/pic.jpg',
        'scheme'=>'sinaweibo://javascript:void(0);',
    ),
),

类似浏览器js的写法,scheme为sinaweibo://javascript:void(0);就好了。

堆排序\链表实现局部排序

以前面试时被问一个问题:有10万个乱序的数,要前5个最大(或最小)的数?
作为一个没好好学算法的人,还没有算法时间、空间复杂度的概念,只提出了冒泡、快速排序等,然后取前5。这显然不是合理的做法。

读了几本书,有一点点心得,下面介绍两个做法:
假设:输入为[31,5,12,24,41,63,7,61,42,21,9,123,24...] ,总数为N=100000,要求前M=5个最大的数

  1. 对10万个建立二叉堆,然后应用堆排序5次,即取出前5个最大(或最小)的数。
    只是一个可行的方法,在此不敖述,具体可参见《数据结构与算法分析:C语言描述》、《数据结构(C语言版)》严蔚敏等书中的堆排序。

  2. 考虑:能否维护一个数据结构用来存储排好序的5个数,要求如果输入数大于5个中最小的数,就将其插入至正确位置,并删除最小的数。这样对输入进行一次遍历,即可找出最大的5个数。
    此处想到的是用单链表,首先对输入中前5个数字升序排序,插入空的链表中。

//简单冒泡排序,输入少,对整体性能影响可忽略不计
for(int j=1; j<M; j++){
    for(int k=0; k<M-j; k++){
        if(input[k]>input[k+1]){
            tmp = input[k];
            input[k] = input[k+1];
            input[k+1]=tmp;
        }
    }
}
for(int i=0; i<M; i++){
    Insert(input[i],L,P);//依次插入链表
    P = P->Next;
}

图片 1.png

Position Tmp,TmpCell;
for( ; i<N; i++){ //对其余输入进行一次遍历
    P = Header(L); //表头
    do{
        Tmp = P;//暂存前驱元,保存位置
        P = P->Next;//第一个元素
        if( input[i] <= P->Value ){ //小于第一个元素或者后面的某一个元素
            if(P != L->Next){ //input[i]大小介于第一个元素与此位置的元素
                Insert(in[i],L1,Tmp); //插入
                TmpCell = L1->Next;
                L1->Next = TmpCell->Next;
                free( TmpCell ); //挤出第一个元素,也就是5+1=6个中最小的元素
            }
            break;
        }else if(input[i] > P->Value && IsLast( P, L )){ //如果大于最后一个(也就是最大的)元素
            Insert(in[i],L,P); //插入到最后
            TmpCell = L->Next; L->Next = TmpCell->Next; free(TmpCell); //删除第一个元素(6个中最小的)
            break;
        }
    } while( !IsLast(P, L) );
}

插入可能是这样的:
图片 2.png

删除首元可能是这样的:
图片 3.png

小结:当输入大数据量,而只需前m个最大(最小)值时,应用链表不失为一个好办法,它只对输入进行一次遍历,时间复杂度O(N),空间也只不过额外是一个含6个元素的链表大小而已。
欢迎指教。

USTB校园网自动登录chrome插件

请允许我自诩Geek一名,面对computer,连一秒都不愿等待,校园网登录页要等5s着实忍不了,所以抽空写了自动登录的插件。
先作声明:
1.此插件支持chrome和360极速浏览器
2.此插件只是本地存储,不会泄露您的密码,请放心使用
3.此插件不会影响您的ipv6地址

安装使用步骤:
1.浏览器地址栏输入 chrome://extensions/ 以打开扩展程序页面
2.下载附件autologin,将附件拖入页面以安装
2.png
3.刷新校园网登录页面,右上角LA(login automaticly)按钮处,输入自己的账号密码,点击“save”、“关闭中”以开启
3.png
4.OK了

由于chrome官方的安全策略,windows下的chrome可能会提示“已停用不支持的扩展”,解决办法详见chrome插件出故障的解决方案.rar

想说的话:
(校园网5s可能是官方折衷的做法,但牺牲每个同学每次登录的5s,并不是解决问题的好方式)
插件主要用了一晚上做出来,又一上午对细节调整完成,因为自己不愿等那5s,结果花了好几个小时。
登录校园网每个同学每次登录都要等上5s,所以希望我的几小时工作可以为大家省去无数个5s。

PHP的GD库freetype编译安装问题及解决办法

首先说明:

  1. 我的环境是Mac OS X,大家知道mac是基于unix,所以从源代码编译安装三步曲:./configure 、 make 、 make install 是都知晓的。
  2. 编译安装三步曲,是可以无限重复进行的。当然有时你要make clean一下。

在一些带验证码、做水印、一些图片处理的PHP项目中,要用到GD库(从PHP 4.3.0开始,绑定到PHP源代码的ext里),在./configure时,使用 --with-gd安装。通常GD库主要有libpng\libjpeg\freetype2\t1lib这四个依赖,而libpng需要zlib(unix/linux系统都会有这个库,不用自己下载安装)。
libpng\libjpeg\ freetype2 \t1lib 这四个库,就要自己先安装好
三种方式:

  1. 从他们的官网中下载稳定版,从源码安装,安装到/usr/local(./configure --prefix=/usr/local)
  2. yum apt-get等方式安装(我的mac没装这几个命令,所以我没有采用这种方式)
  3. 这个方式仅限Mac:Homebrew ———— The missing package manager for OS X,可去其github看文档,安装后几个简单命令,就把这些依赖的库安装好了,非常方便。

现在,我们已经解决了GD的所有依赖,只要在./configure时加上以下几个配置项:

--with-gd --with-zlib --with-png-dir=/usr/local --with-jpeg-dir=/usr/local --with-freetype-dir=/usr/local --with-t1lib=/usr/local 

再 sudo make 、 sudo make install 就完事了!
gd.png

遇到的一些问题:

  1. Mac是自带PHP的,版本稍旧一点且源码也没有了,不如把自带的干掉,重新编译安装一个(比如PHP 5.5)!系统默认的PHP安装在/usr,我们自己通常安装在/usr/local里。
    彻底删除自带的PHP:
cd /private/etc/
sudo rm -rf php-fpm.conf.default php.ini php.ini.default
cd /usr/bin/
sudo rm -rf php php-config phpdoc phpize
cd /usr/include
sudo rm -rf php
cd /usr/lib
sudo rm -rf php
cd /usr/sbin
sudo rm -rf php-fpm
cd /usr/share
sudo rm -rf php
cd /usr/share/man/man1
sudo rm -rf php-config.1 php.1 phpize.1
cd /usr/share/man/man8
sudo rm -rf php-fpm.8
  1. 因为不断试用关于GD的这几个配置项,我编译安装三步曲起码进行了十多次。你会发现第一次编译安装时间很长,之后重复编译安装很快就完成了,是因为有一些步骤就跳过了。所以改了一些配置项,phpinfo()中的预期的GD的信息却没有。所以重复三步曲前,make clean 进行一下就ok了。

我的配置项:./configure --prefix=/usr/local/php --enable-mbstring --with-apxs2=/usr/sbin/apxs --with-mysql --with-pdo-mysql --enable-zip --with-mysqli --with-curl=/usr/local/opt/curl
说明:
--with-apxs2=/usr/sbin/apxs 这个配置项是针对Apache2.x版本,=[DIR]为apxs命令的位置
--with-curl=/usr/local/opt/curl 详见curl安装