Edgar Hoo Blog

PHP函数输出HTML时的多余空行

在企图将Edgar Hoo Home Page的静态页面的重用代码函数化,以期改版少费力,却发现虽调用PHP函数所输出的HTML代码同原HTML代码一模一样,但除Opera (10 alpha)、Safari (3.2)将两者解释相同之外,而主流的IE系、FF (3.1 beta 2)及Chrome (1.0)竟将前者在顶部多解释出一行空行。

为便说明问题,现作简易页面。

原HTML代码如下(php-function-html-output-blank-lines.html):

  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
  • http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <html xmlns="http://www.w3.org/1999/xhtml">
  • <head>
  • <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  • <meta http-equiv="Content-Language" content="UTF-8" />
  • <title>EdgarHoo.com Lab</title>
  • <link href="pfhobl.css" rel="stylesheet" rev="stylesheet" type="text/css" media="all" />
  • </head>
  • <body>
  • <div id="wrapper">
  •     <div id="header">
  •         <h1>EdgarHoo.com Lab</h1>
  •     </div>
  • </div>
  • </body>
  • </html>

CSS代码如下(php-function-html-output-blank-lines.css):

  • *{
  •     margin:0;
  •     padding:0;
  • }
  • body{
  •     color:#fff;
  •     background:#000;
  •     text-align:center;
  • }
  • #wrapper{
  •     width:800px;
  •     height:auto;
  •     margin:0 auto;
  • }
  • #wrapper #header{
  •     height:50px;
  •     background:#f00;
  • }

PHP函数文件(php-function-html-output-blank-lines-include.php),代码如下:

  • <?php
  • function head(){
  • ?>
  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
  • http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <html xmlns="http://www.w3.org/1999/xhtml">
  • <head>
  • <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  • <meta http-equiv="Content-Language" content="UTF-8" />
  • <title>EdgarHoo.com Lab</title>
  • <link href="style.css" rel="stylesheet" rev="stylesheet" type="text/css" media="all" />
  • </head>
  • <body>
  • <div id="wrapper">
  • <?php
  • }
  • function foot(){
  • ?>
  • </div>
  • </body>
  • </html>
  • <?php
  • }
  • ?>

PHP文件(php-function-html-output-blank-lines.php),如下:

  • <?php
  • require('inc.php');
  • head();
  • ?>
  • <div id="header">
  • <h1>EdgarHoo.com Lab</h1>
  • </div>
  • <?php
  • foot();
  • ?>

此次不作截图,有兴趣的同学可自行使用相关浏览器测试。

测试地址:原版HTMLPHP函数化后的HTML

@ Dec. 13, 2008 SCUTA

循环下降语法分析

本文源自笔者的课程《编译原理》的实验二,原题如下:

编写识别由下列文法所定义的表达式的递归下降语法分析器。

E -> E+T | E-T | T

T -> T*F | T/F |F

F -> (E) | i

输入:每行含一个表达式的文本文件。

输出:分析成功或不成功信息。

(来源:海南大学儋州校区计算机系)

采用PHP编码,代码如下:

  • /*
  • Item Name: Recursive of the Decline Grammar Analysis
  • Description: Compilation Principle Experiment 2nd
  • Version: 1.0
  • Author: Edgar Hoo
  • Author URI: http://EdgarHoo.com
  • Last Updated: Dec. 1, 2008 @ SCUTA
  • CopyRight 2008 BY-NC-SA
  • */
  • @ $fp = fopen("rdga.txt", 'rb');
  • if (!$fp){
  • echo '没有文件!</body></html>';
  • exit;
  • }
  • $array = file("rdga.txt");
  • $n = count($array);
  • $err = 1;
  • if ($array[0] == '') echo '文件没有内容!';
  • for ($i=0;$i<$n;$i++){
  •     $order = trim($array[$i]);
  •     check($order,&$err);
  • }
  • function check($order,&$err){
  •     $l = strlen($order);
  •     for ($j=0;$j<$l;$j++){
  •         $x = substr($order,$j,1);
  •         if (!($x=='+' || $x=='-' || $x=='*' || $x=='/' || $x=='(' || $x==')' || $x=='i'))
  •         $err=0;
  •         if ($err==0) break;
  •     }
  •     if ($err==0) echo $order.'含有非法字符!<br />';
  •     else{
  •         $j=0;
  •         $x = substr($order,$j,1);
  •         recogE($order,&$x,&$j,&$err);
  •         if ($err==1){
  •             if ($j==$l) echo $order.'符合文法。<br />';
  •             else echo $order.'不符合文法。<br />';
  •         }
  •     }
  • }
  • function recogE($order,&$x,&$j,&$err){
  •     if ($err==1){
  •         recogT($order,&$x,&$j,&$err);
  •         recogE1($order,&$x,&$j,&$err);
  •     }
  • }
  • function recogT($order,&$x,&$j,&$err){
  •     if ($err==1){
  •         recogF($order,&$x,&$j,&$err);
  •         recogT1($order,&$x,&$j,&$err);
  •     }
  • }
  • function recogE1($order,&$x,&$j,&$err){
  •     if ($err==1){
  •         if ($x=='+' || $x=='-'){
  •             ++$j;
  •             $x = substr($order,$j,1);
  •             recogT($order,&$x,&$j,&$err);
  •             recogE1($order,&$x,&$j,&$err);
  •         }
  •         else if ($x!='' && $x!=')'){
  •             echo $order.'不符合文法。<br />';
  •             $err=0;
  •         }
  •     }
  • }
  • function recogT1($order,&$x,&$j,&$err){
  •     if ($err==1){
  •         if ($x=='*' || $x=='/'){
  •             ++$j;
  •             $x = substr($order,$j,1);
  •             recogF($order,&$x,&$j,&$err);
  •             recogT1($order,&$x,&$j,&$err);
  •         }
  •         else if ($x!='' && $x!=')' && $x!='+' && $x!='-'){
  •             echo $order.'不符合文法。<br />';
  •             $err=0;
  •         }
  •     }
  • }
  • function recogF($order,&$x,&$j,&$err){
  •     if ($err==1){
  •         if ($x=='('){
  •             ++$j;
  •             $x = substr($order,$j,1);
  •             recogE($order,&$x,&$j,&$err);
  •             if ($x==')'){
  •                 ++$j;
  •                 $x = substr($order,$j,1);
  •             }
  •             else if ($x==''){
  •                 echo $order.'不符合文法。<br />';
  •                 $err=0;
  •                 ++$j;
  •                 $x = substr($order,$j,1);
  •             }
  •         }
  •         else if ($x=='i') {
  •             ++$j;
  •             $x = substr($order,$j,1);
  •         }
  •         else {
  •             echo $order.'不符合文法。<br />';
  •             $err=0;
  •         }
  •     }
  • }
  • fclose($fp);

测试地址:循环下降语法分析器

@ Dec. 6, 2008 SCUTA

识别器的实现

本文源自笔者的课程《编译原理》的实验一,原题如下:

假设一个语言允许使用十六进制数,其规定是:必须以数字打头,必须以H结尾,数中允许使用的字母为A,B,C,D,E, F(分别表示10~15)。该语言的标识符为字母开头的字母数字串。试设计一个DFA,使它能识别标识符、无符号的十进制和十六进制整数(假定各单词之间用界限符或空格分开),并编制相应的识别程序。

输入:学生自行确定符号串的输入形式,如键盘输入、文本文件、字符数组等。

输出:标识出规范的符号串与不合规范的符号串。

(来源:海南大学儋州校区计算机系)

要求如下:

A、根据给定的语言求出其文法;

B、将该文法转换成正规式;

C、由正规式构造NFA;

D、将NFA转换成DFA,并将其最小化;

E、根据最小化的DFA编写词法分析程序。

按说这个实验该用C语言编程,但最近学习JavaScript、PHP,正好借此题目练习。

根据题意,笔者认为十六进制整数不含小写字母(包括H),十六进制整数首字符为0的情况下第二字符不能为数字,无符号的十进制整数除0外首字符不能为0。

笔者编JS代码如下:

  • /*
  • Item Name: Recognizer of Realize
  • Description: Compilation Principle Experiment 1st
  • Version: 1.0
  • Author: Edgar Hoo
  • Author URI: http://EdgarHoo.com
  • Last Updated: Nov. 23, 2008 @ SCUTA
  • CopyRight 2008 BY-NC-SA
  • */
  • function recog(){
  • var test = document.myform.mytest.value;// 取得待测字符串
  • var tl = test.length;// 定义字符串长度
  • var s=0;// state
  • for (i=0;i<tl;i++){
  •  ti = test.charAt(i);// 字符串第i个字符
  •  if (ti==' ' || ti==' ') s=6;// 去除半角及全角空格
  •  else {
  •   switch(s){
  •     case 0: if (ti==0) s=1;
  •       else if (ti>=1 && ti<=9) s=2;
  •       else if ((ti>='A' && ti<='Z') || (ti>='a' && ti<='z')) s=3;
  •       else s=6;
  •       break;
  •     case 1: if (ti>='A' && ti<='F') s=4;
  •       else if (ti=='H') s=5;
  •       else s=6;
  •       break;
  •     case 2: if (ti>=0 && ti<=9) s=2;
  •       else if (ti>='A' && ti<='F') s=4;
  •       else if (ti=='H') s=5;
  •       else s=6;
  •       break;
  •     case 3: if ((ti>=0 && ti<=9) || (ti>='A' && ti<='Z') || (ti>='a' && ti<='z')) s=3;
  •       else s=6;
  •       break;
  •     case 4: if ((ti>=0 && ti<=9) || (ti>='A' && ti<='F')) s=4;
  •     else if (ti=='H') s=5;
  •     else s=6;
  •     break;
  •   }
  •  }
  • if (s==6) break;
  • }
  • if (s==0) alert("请输入待测字符串!");
  • else if (s==1 || s==2) alert(test+"是十进制数。");
  • else if (s==3) alert(test+"是标识符。");
  • else if (s==5) alert(test+"是十六进制数。");
  • else if (s==4 || s==6) alert(test+"是不合规范字符串。");
  • }

因为采用提交HTML表单的形式输入待测字符串,而JS将表单中的空格转换成“+”,但在实际测试中,程序却将空格判断为数字,所以,在循环中首先判断去除空格。本以为如果采用在JS代码中添加待测字符串,则不需要添加去除空格的代码,而事实再次证明JS同样认为空格是数字。

用PHP编码,只要稍作改动即可,PHP没有空格问题,减少几行代码,完整代码如下:

  • $test = $_GET['mytest'];
  • $tl = strlen($test);
  • $s = 0;
  • $i = 0;
  • for ($i=0;$i<$tl;$i++){
  •  $ti = substr($test,$i,1);
  •   switch ($s){
  •     case 0: if ($ti=='0') $s=1;
  •       else if ($ti>='1' && $ti<='9') $s=2;
  •       else if (($ti>='A' && $ti<='Z') || ($ti>='a' && $ti<='z')) $s=3;
  •       else $s=6;
  •       break;
  •     case 1: if ($ti>='A' && $ti<='F') $s=4;
  •       else if ($ti=='H') $s=5;
  •       else $s=6;
  •       break;
  •     case 2: if ($ti>='0' && $ti<='9') $s=2;
  •       else if ($ti>='A' && $ti<='F') $s=4;
  •       else if ($ti=='H') $s=5;
  •       else $s=6;
  •       break;
  •     case 3: if (($ti>='0' && $ti<='9') || ($ti>='A' && $ti<='Z') || ($ti>='a' && $ti<='z')) $s=3;
  •       else $s=6;
  •       break;
  •     case 4: if (($ti>='0' && $ti<='9') || ($ti>='A' && $ti<='F')) $s=4;
  •       else if ($ti=='H') $s=5;
  •       else $s=6;
  •       break;
  •   }
  •  if ($s==6) break;
  • }
     
  • if ($s==0) $out = '请输入待测字符串!';
  • else if ($s==1 || $s==2) $out = $test.':是十进制数。';
  • else if ($s==3) $out = $test.':是标识符。';
  • else if ($s==5) $out = $test.':是十六进制数。';
  • else if ($s==4 || $s==6) $out = $test.':是不合规范字符串。';

因为本站空间默认启用get_magic_quotes_gpc()函数,所以在输出字符串之前要使用stripslashes():

  • $out = stripslashes($out); echo $out;

测试地址:JSJS-spPHP

附:

(1).文法:按题意,十六进制整数如0AH、11H、1AH、1A0BH等由以数字打头,并以H结尾的字符串,不含a、b等小写字母;标识符如a0、ab、A1a等由A至Z、a至z、0至9并以字母开头的字母数字串;无符号的十进制整数如0、11、123等由0至9之间数字组合组成,而00、001等则不属于无符号的十进制整数。

由以上可得出文法,表示如下:G(S) = (VN, VT, P, S)

其中,VN = { S, X', Y', Z', M', N’,W’, a’, b’, c’, d’, e’, f’, g’,h’}

VT = { 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z}

a’= 0

b’=1|2|3|4|5|6|7|8|9

c’ = A|B|C|D|E|F

d’ =a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|G|H|I|G|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z

S → X’ | Y’ | Z’

X’ → a’ H | b’ H | a’ c’ M’ H | b’ M’ H

M’ →e’ | e’ M’

e’ → a’ | b’ | c’

Y’ →f’ |f’ N’

f’ →c’| d’

N’ → g’ | g’ N’

g’ →a’ | b’ | c’ | d’

Z’ →a’ | b’ | b’ W’

W’ → h’ | h’ W’

h’ → a’ | b’

上述表示中,X’为十六进制整数,Y’为标识符,Z’为无符号十进制整数。

(2).正规式:由于上文文法已为正规文法,所以根据转换规则,步骤如下:

M’ → e’| e’ M’     =>   M’ →e’ * e’

N’ → g’ | g’ N’    =>   N’ →g’ * g’

W’ → h’ |h’ W’   =>  W’ → h’*h’

所以,转换成正规式为:S=a’ H |b’ H | a’ c’ e’ * e’ H| b’ e’ * e’ H| f’ |f’ g’ * g’| a’ |b’ |b’ h’ *h’

代入可得:

S=a’ H| b’ H| a’ c’ (a’ |b’ |c’)*(a’ |b’ |c’)H |b’ (a’ |b’ |c’)*(a’ |b’ |c’)H| (c’ |d’)| (c’ |d’)(a’ |b’ |c’ |d’)*(a’ |b’ |c’ |d’)| a’ |b’ | b’ (a’ |b’)*(a’ |b’)

(3).NFA:

初始NFA图:

初始NFA图

最终NFA图:

最终NFA图

(4).DFA:对应以上NFA图,用造表法表示如下:

造表法表示

由上表得出DFA图:

DNA图

其中,状态2和状态6等价,状态3和状态8等价,状态4、状态9和状态7等价,化简后得最小DFA图:

最小DNA图

Updated @ Nov. 30,2008 SCUTA

-----这是分割线-----

Flickr 1/2/3/4/5

QQ 2009 Preview 4

之前,笔者也使用过非正版的QQ,倒不是为了去探测朋友们是否隐身或身在何方,而是要屏蔽掉可恶的广告或新闻。

关于隐身,实在没必要去探测,既然人家隐身了就是不想让你知道在线,知道了又能怎么样,进一步讲,这是人家的私隐。

至于IP地址,更没必要,因为笔者的首席QQ号中的朋友们,都是熟识的,他们有几个窟,了然于胸,能逃到哪里去。如果彼此陌生,除了其他QQ号招待外,笔者是不会顿生兴趣去“探索”的。

本以为QQ 2009会承袭QQ 2009 Preview 3的风格,无条件自定义是否需要迷你首页,但笔者错了,Preview 4便将此功能划归会员专有功能。

QQ 2009 Preview 4 截图

年关将至,如果QQ 2009正式版在明年初发布的话,笔者对此不报希望了。越接近正式版,腾讯的赚钱大口开的越大。QQ面板头部、底部的其他产品按钮不仅仍然无法自定义是否显示,在Previewe 3中可以取消的为数不多的按钮也不能取消了。

相比Preview 3,失去的天气报告重新出现,且报告今、明、后三天。

QQ 2009 Preview 4 天气报告截图

点击上面任何一天,均转到其自家的soso.com搜索相应城市天气页面。

最显著的是好友资料卡的变化:

QQ 2009 Preview 3(305) 好友资料卡截图

Preview 3(305)的好友资料卡。

QQ 2009 Preview 3(450) 好友资料卡截图

Preview 3(450)的好友资料卡。

QQ 2009 Preview 4(346) 好友资料卡截图

Preview 4(346)的好友资料卡。

虽然Preview 4恢复了Preview 3(305)的外表,但取消了“丰富资料”这一选项。“丰富资料”的内容一路下来逐步减少,最终被取消,界面干净许多。舍得抛弃。连将鼠标放置好友昵称上方出现的小资料卡片也取消了其他“丰富资料”,仅存QQ秀、昵称、账号、个性签名,城市及城市天气。怎么QQ也要走简洁路线了?

QQ 2009 Preview 4 小资料卡截图

对笔者而言,“丰富资料”中QQ空间预览最为重要,可以随时关注某些朋友们的动态,确实仍有朋友扎根QQ空间。取消了QQ空间的预览,那怎样才能进入好友的QQ空间呢?除右击好友列表里好友头像选择进入之外,在聊天页面也出现点击按钮。

QQ 2009 Preview 4 聊天界面截图

QQ这么做,似乎有助于保护用户私隐,减少向陌生人查看资料时展示过多的个人信息。

@ Nov. 25, 2008 SCUTA

-----这是分割线-----

怪事来了,昨晚发完上文后,偶然用其他QQ号登录,发现Preview 4的界面居然变了。

QQ 2009 Preview 4 截图

而首席QQ登录后,界面仍然没有变化。

怎么同一台电脑,同一个QQ版本,登录之后,却不一样的界面。不知何解?难道是参加体验的缘故。大概如此了。

Updated @ Nov. 26,2008 SCUTA

-----这是分割线-----

QQ 2009 Preview 4(520)好友资料卡截图。

QQ 2009 Preview 4(520) 截图

Updated @ Dec. 6,2008 SCUTA

-----这是分割线-----

Flickr 1/2/3/4/5/6/7/8/9

我的电脑生活A-Z

在自己拥有PC机之后,电脑、网络才成为生活的一部份,不可缺少。

不幸的,大陆会成为全球首个确认网瘾是精神病的国家。所以,以此标准,笔者彻头彻尾的是精神病者。

如果离开电脑,笔者几近一无是处,因为笔者仅有的所谓特长、能力全都基于电脑。

现在来晒晒让笔者陷于不拔的那些有名号但没法拿在手里的物。

A——Adobe。没法不提,其旗下Photoshop、Dreamweaver、Flash、Reader,个个精明强干,即便替代掉DW,不玩Flash,另两个实在找不到替身。

B——Blog。前段日子不少人扬言这个家伙要死了。怎么可能呢?至少笔者的博客才开始起步。SNS,对笔者没什么吸引力。只要个人发布平台需要存在,blog就不会死。

C——纯净二笔。一个偏门之极的输入法,同时也是笔者目前PC机上仅安装的输入法。为什么选用这输入法呢?因为笔者懒惰,又要优质服务,它像五笔一样几乎没有重码,像拼音输入法一样简单。

D——Douban。如果非要说豆瓣也是SNS的话,笔者收回“SNS,对笔者没什么吸引力”这句话。每看影视、每读书籍,免不了上去搜寻一番。豆瓣小组,闲暇逛逛,别有风味。九点,总能看到精彩的博文。广场,目前唯一让笔者不钟意的豆瓣服务。自从来了豆瓣,它一举取代天涯成为笔者的首选社区。天涯,早已久违。

E——Editor。Notepad、Notepad 2最为常用。之前网页编程多用DW,DW的可视化编辑反而不太会用,觉其笨重,占用内存大,目前改用Notepad++,所以Notepad 2也快退休了。

F——FlashFXP。因为习惯,一直使用FlashFXP上传下载FTP内容。正尝试改用FileZilla。

G——Gmail。笔者不是Google依赖症患者,顶多轻微依赖。Gmail优秀的用户体验、强大的功能,一旦被缠上,一发不可收拾。

H——xHTML+CSS。用这个公式来代表WEB前端标准开发,目前笔者专注的领域。

I——IIS。因为暂时没法放弃ASP,只好继续延用。当然相应的还有PHP、MySQL、phpMyAdmin。

J——Jiangmin。已经好几个月机子上没装杀毒软件、防火墙了,大概会如此持续下去。不过,之前,江民的使用时间最长,体验不差。

K——Kugou。自从千千静听某段时间无法弥补的漏洞之后,一直使用酷狗,除了广告烦点,大体不错。但前几日,貌似最新版的酷狗频繁未响应,只好重新千千静听,好像没漏洞了。

L——PowerWord Lite。谷歌金山词霸合作版,如果没有Google的网络词典,恐怕早已被笔者抛弃,运行之后,一大堆的广告令人厌烦,导致打开速度极慢。不然有道词典是个不错的选择。

M——Media Player Classic。暴风影音,播放器少不得,影视乃一大娱乐项目。新版的暴风影音取消了只剩一个播放框的设置,而此点是笔者最为需求的功能,所以,目前采用完美解码来模拟暴风影音,体验良好。

N——Nero。资料一多,硬盘容不下,刻录十分必要,Nero自然首选。

O——Opera。目前笔者的默认浏览器。占用内存小,不常崩溃,界面自定义,快速拨号导致笔者从Firefox倒戈相向。虽说Firefox拥有众多插件带来不少方便,但也占用更大内存,且笔者经常使用beta版,不少插件基本处于睡眠状态。

P——PPlive。影视下载下来固然不错,可速度缓慢。面对同样的缓慢网速,PPlive却能够不卡,真是万幸。收看娱乐节目,非它不可。

Q——QQ。即使笔者不乐意使用QQ,也得继续使用。

R——RSS。订阅可以免去众多站点奔波劳碌之苦,Google Reader,很好的选择,尤其被GFWed的内容。

S——Google Search。是指Google.com,而非Google.cn,将Opera的语言设为zh-TW,就能够正常使用,而不跳转。

T——Thunder。又是一个即爱且恨的家伙,少用为妙。

U——Wopti Utilities。杀毒软件可以不要,防火墙可以不要,优化大师却不能不要。笔者不装杀毒软件、防火墙多时,优化大师配合360、Winddows清理助手、恶意软件清理助手,再小心些,基本无大碍。

V——Vopt。电影下的多,刻的多,删的多,硬盘整理很必要。

W——WordPress。即是架设博客的好东西,也是学习PHP、WEB前端的好东西。

X——Windows XP。基础的基础。不过有尝试Linux的念头。

Y——Yen.ChunFu.org。个人站点,包括blog.ChunFu.org、EdgarHoo.com,生活一部份。

Z——7-Zip。解压缩文档,怎么能没有它。

@ Nov. 20, 2008 SCUTA