如无特别说明,以下题目均可用各种技术方案来解答。

Posted by & filed under 每日一题.

【四脚猫】每日一题(2015年05月11日): 如何采用awk或其他命令工具实现数据转换?

有个sjm.txt的原始数据格式如下:

1
2
3
4
5
6
7
8
17/Apr/2015:09:29:24 +0800
17/Apr/2015:09:30:26 +0800
17/Apr/2015:09:31:56 +0800
18/Apr/2015:09:34:12 +0800
18/Apr/2015:09:35:23 +0800
19/Apr/2015:09:23:34 +0800
19/Apr/2015:09:22:21 +0800
20/Apr/2015:09:45:22 +0800

期望结果:

1
2
3
4
5
6
7
8
2015-04-17 09:29:24+0800
2015-04-17 09:30:26+0800
2015-04-17 09:31:56+0800
2015-04-18 09:34:12+0800
2015-04-18 09:35:23+0800
2015-04-19 09:23:34+0800
2015-04-19 09:22:21+0800
2015-04-20 09:45:22+0800

 

以下是参考答案:

 

Posted by & filed under 每日一题.

【四脚猫】每日一题(2015年05月08日):  PHP二维数组按照指定的元素特点如何排序?

 

排序后的结果是:

 

以下是Diven提供的解法,这个方法很通用,非常赞!


以下是千里提供的解法,纯手工打造,没用用php自带函数,功力很深厚!

 

以下是一种简单的方法,但是不通用

 

 

Posted by & filed under 每日一题.

【四脚猫】每日一题(2015年05月07日): 如何用PHP替换文件的内容?

test.txt 内容如下

1
2
3
4
5
111,2222
333,4444
555,7777

......

如果$goods_id的值 等于其中一行前面的值 那么转换成后面的输出,比如 $goods_id=111,那么进行替换后,

这行就变成$goods_id=2222,整体如下结果:

1
2
3
4
5
$goods_id=2222
333,4444
555,7777

......

 

 

 

参考答案:

 

 

Posted by & filed under 每日一题.

【四脚猫】每日一题(2015年05月06日): 如何用php实现微信公众号自定义菜单?

 

 

 

 

 

 

Posted by & filed under 每日一题.

【四脚猫】每日一题(2015年05月05日): 编写一个函数,将2个数字相加,不使用+运算符。

分析:这又是一道考察发散思维的很有意思的题目。当我们习以为常的东西被限制使用的时候,如何突破常规去思考,就是解决这个问题的关键所在。

看到的这个题目,我的第一反应是傻眼了,四则运算都不能用,那还能用什么啊?可是问题总是要解决的,只能打开思路去思考各种可能性。首先我们可以分析人们是如何做十进制的加法的,比如是如何得出5+17=22这个结果的。实际上,我们可以分成三步的:第一步只做各位相加不进位,此时相加的结果是12(个位数5和7相加不要进位是2,十位数0和1相加结果是1);第二步做进位,5+7中有进位,进位的值是10;第三步把前面两个结果加起来,12+10的结果是22,刚好5+17=22。

前面我们就在想,求两数之和四则运算都不能用,那还能用什么啊?对呀,还能用什么呢?对数字做运算,除了四则运算之外,也就只剩下位运算了。位运算是针对二进制的,我们也就以二进制再来分析一下前面的三步走策略对二进制是不是也管用。

5的二进制是101,17的二进制10001。还是试着把计算分成三步:第一步各位相加但不计进位,得到的结果是10100(最后一位两个数都是1,相加的结果是二进制的10。这一步不计进位,因此结果仍然是0);第二步记下进位。在这个例子中只在最后一位相加时产生一个进位,结果是二进制的10;第三步把前两步的结果相加,得到的结果是10110,正好是22。由此可见三步走的策略对二进制也是管用的。

接下来我们试着把二进制上的加法用位运算来替代。第一步不考虑进位,对每一位相加。0加0与 1加1的结果都0,0加1与1加0的结果都是1。我们可以注意到,这和异或的结果是一样的。对异或而言,0和0、1和1异或的结果是0,而0和1、1和0的异或结果是1。接着考虑第二步进位,对0加0、0加1、1加0而言,都不会产生进位,只有1加1时,会向前产生一个进位。此时我们可以想象成是两个数先做位与运算,然后再向左移动一位。只有两个数都是1的时候,位与得到的结果是1,其余都是0。第三步把前两个步骤的结果相加。如果我们定义一个函数AddWithoutArithmetic,第三步就相当于输入前两步骤的结果来递归调用自己。
有了这些分析之后,就不难写出如下的代码了:

 

 

Posted by & filed under 每日一题.

【四脚猫】每日一题(2015年05月04日): 如何用gd库画出五角星? 提交你的代码看看。

 

Posted by & filed under 每日一题.

【四脚猫】每日一题(2015年04月21日): 智商测试,求答案!

QQ图片20150424112140

 

【公布答案】
①答1的朋友,您能够纵观全局,具备统帅三军的能力,在工作和生活中一定是一个很沉稳的人![酷]
②答96的朋友,您做事情很专注,很注重细节,逻辑思维能力较强,生活中是一个一丝不苟很严谨的人。[悠闲]
③答32、48、64,72的等等乱七八糟数字的朋友,您的思维很活跃,与众不同这是您的优势,但是我还是想吐槽一下:你的数学是语文老师教的吗       !
④正确答案:请看图片第一行内容,1=4,那么4 当然=1了,纵观全局才能一览无余。[憨笑][憨笑][憨笑]

Posted by & filed under 技术干货.

一·命名非常重要
对代码名称进行有意义命名,而不是随意使用字母或无意义或容易产生奇异的英文进行命名,例如:

1
2
3
4
5
6
7
8
9
10
11
function a($a,$b){
if(is_numeric($a)){
return intval($a);
}
$c=explode(#’,$a);
if(isset($c[$b])){
return intval($c[$b]);
}else{
return intval($c[count($c)-1]);
}
}

这段代码的命名没有意义,直接看代码没有办法知道这个方法具体要做什么,更不知道需要传入的参数有哪些,分别是什么意思,而且当代码长度变长之后变量数量增多,自己容易记混变量名意义,给自己编码造成很大的错误概率。另外在过一段时间后再看代码无法记起当时所想,不利于后期维护。如果代码和他人交接,想想你和一个编码命名毫无意义的人交接的情景吧,好吧,你肯定想到了,你的无意义的命名肯定会让你的代码被交接人维护时候问候你无数次的。

1
2
3
4
5
6
7
8
9
10
11
function get_int_whit_vip($str,$vip){
if(is_numeric($str)){
return intval($str);
}
$str_arr = explode('#',$str);
if(isset($str_arr[$vip])){
return intval($str_arr[$vip]);
}else{
return intval($str_arr[count($str_arr)-1]);
}
}

这段代码和刚刚的代码是相同的效果,但是命名会让你很容易知道这是一个根据vip等级获得一个次数数字的方法,传入的参数是一个字符串和vip等级,字符串格式为#分割的数字,也有可能就是一个单一的数字。这样子很容易就能看出来这个代码的作用。日后维护和自己编写的时候都会比较容易处理。
命名注意事项:1.有实际意义。2.使用统一编码规范,是$str_arr下划线风格还是$strArr驼峰风格,项目中保持编码的一直规范性。3.不使用拼音作为名称,使用有意义的英文。4.不使用语言的关键字,虽然在php中类似于$error_log,$count这样的命名是支持的,但是不要使用。

二·适当的使用注释
注释加的要合理,最好的注释就是代码本身,通过使用有意义的命名,使代码自身可读性增强,在逻辑非常复杂难以理解的地方加上注释说明来达到可以通过注释了解算法设计的目的。在函数开始处增加注释信息,使函数可以只是看注释信息就知道函数作用,方便调用。在类的功能和使用方法上增加注释,写清用处和维护人,以方便使用以及出问题后可以快速找到对应的维护人信息,对于一个文件多人维护的情况,方法注释就很重要了,最好方法注释上可以写上这个方法的维护人,以方便出问题时修改。但是过多的注释会使代码混乱,增加代码长度,所以不建议很容易读懂的地方增加注释信息。

三·变量需要初始化 (十分重要)
注:这个问题我自己工作中遇到过,因为开发时候着急没有进行初始化就直接使用,当时有一个变量有时候有有时候没有(根据判定条件动态更新),完后在本应该没有的地方也产生了这个值,当时差了很多地方,打印了无数的日志,最后发现时没有初始化造成的数据重叠,这个教训深刻呀!!!!
在php中程序默认是允许变量不进行声明初始化而直接使用的,但是这样会造成一定的问题。例如:

1
2
3
4
5
$page=$_GET[‘page’];
if(1==$page){
$user_page = $page;
}
echo $user_page;

这段代码在$page不等于1的情况下会找不到$user_page的值而出现运行的异常,如进行声明则

1
2
3
4
5
6
page=$_GET[‘page’];
$user_page = 0 ;
if(1==$page){
$user_page = $page;
}
echo $user_page;

无论是否等于1都会有一个很确定的输出。类似的例子还有很多。另外例如下面这种情况:

1
2
3
4
5
6
7
$input_arr = array(array('a'=>1,'b'=>2,'c'=>3),array('a'=>2,'b'=>3,'d'=>5),array('b'=>9,'c'=>3));
foreach($input_arr as $key=>$val){
foreach($val as $k=>$v){
$output[$k] = $v;
}
var_dump($output);
}

在这个例子中我们本来是相输出每一个子集的结果,即理想结果应该是:

1
2
3
4
5
6
7
8
9
10
11
array (size=3)
'a' => int 1
'b' => int 2
'c' => int 3
array (size=3)
'a' => int 2
'b' => int 3
'd' => int 5
array (size=2)
'b' => int 9
'c' => int 3

但是这个运行的结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
array (size=3)
'a' => int 1
'b' => int 2
'c' => int 3
array (size=4)
'a' => int 2
'b' => int 3
'c' => int 3
'd' => int 5
array (size=4)
'a' => int 2
'b' => int 9
'c' => int 3
'd' => int 5

原因是每次进行循环之前没有进行初始化,使得数据产生了累加,结果数值错误,我自己在工作中不注意就是犯得这种错误,即使自己知道应该声明但是也有个别没有注意到的时候,这个是需要特别谨慎的一个点。得到理想结果的代码如下:

1
2
3
4
5
6
7
8
$input_arr = array(array('a'=>1,'b'=>2,'c'=>3),array('a'=>2,'b'=>3,'d'=>5),array('b'=>9,'c'=>3));
foreach($input_arr as $key=>$val){
$output=array();
foreach($val as $k=>$v){
$output[$k] = $v;
}
var_dump($output);
}

所以每次使用变量之前对变量进行初始化声明是很重要的。很多时候代码很长在前面直接使用的变量在后面没有初始化声明就不注意再次使用,造成数据混乱的情况,在开发中复现和调试修改都是非常麻烦的事情。

四·1==$a
常量写在变量前面,这一点和很多人平时的编码习惯有比较大的区别,正常的思维方式是某一个变量值等于某一个常量值时候进行什么操作,所以很容易就会出现如下写法:

1
2
3
4
5
6
$page = mt_rand(0,1);
if($page ==1){
echo ‘Hello’;
}else{
echo ‘page error’;
}

但是如上代码不注意就回写成如下代码:

1
2
3
4
5
6
$page = mt_rand(0,1);
if($page =1){
echo ‘Hello’;
}else{
echo ‘page error’;
}

这个时候有些编译器会警告你if那行有问题,但是有很多编译器是不会警告的,在这种情况下永远输出的都是’Hello’,这种错误在编译的时候是不会报错的,所以查起来难度也是很大的,毕竟只是一个=和==的区别。但是如下这种写法的话在编译的时候编译器直接就会报错,变异不通过直接定位进行修改,也就不会有后面的编码麻烦了。

1
2
3
4
5
6
$page = mt_rand(0,1);
if(1=$page ){
echo ‘Hello’;
}else{
echo ‘page error’;
}

所以在编写程序的时候将常量放在变量的前面可以避免很多不必要的错误,减少时间开支。

五·防御式编程
在编程中,很多数据是通过外界获取的数据,如果不加以验证就直接使用的话可能会造成错误,不要说客户端是你们自己的,客户端上写的数据直接传过来的就没有问题,或者是说前端js已经验证过的数据就不用验证了,可以相信的拿着使用,这样的话一旦数据被人截取篡改或者是数据不完整就会导致整个程序的错误,甚至有可能直接就会被别人改掉数据库信息。所以不要相信任何一个外界获取的数据,包括在数据库中取得的数据。所有数据在使用前都要进行必要的数据验证,比如isset(),is_numeric(),is_array()等这类的验证,对程序的运行效率消耗较小,但是可以很好的保护程序的健壮性。对于正则表达式而言,可以使用简单验证的情况下个人不太建议使用正则匹配,虽然正则非常厉害,但是会对程序的运行资源有一个较大的开销,关于正则的深入研究,将会有另外一篇文章来描述。对于防御性编程而言,合理验证,保证程序的健壮性但是不要过度验证使得程序臃肿,运行效率低下。

六·可控的环境参数
在很多时候我们所编写的程序会跑在什么样的环境下我们不得而知,有时我们写的一些方法所需要的一些环境参数是我们不可提前预知的,在这种情况下可以自己使用显示的声明方式来对环境参数进行声明控制。对于路径最好是在程序的访问入口文件处通过define(‘ROOT’,dirname(__FILE__));这种方式来获得项目的绝对路径来进行文件操作,所有的给予文件的操作使用绝对路径方式可以避免多个文件对一个文件或者一个文件对多个文件的时候的路径问题。对于一些对于环境参数有要求的模块自己给定一个系统默认值,另外自定义错误警报的级别也可以减少因为服务器未定义某些级别的错误造成的日志缺失查找程序错误的时候的困难。
对于自己所运行的服务器是在自己完全可控的情况,个人建议只使用入口文件定义绝对路径,另外两项直接自己修改服务器的默认属性,这样可以一定量的减少程序的开销。

七·PHP结束标记
对于php的结束标记是否需要写出的这个问题,如果是纯php代码,最后的结束标记最好不要写,因为当其余的文件对其进行引入的时候有可能会因为结束标记之后的部分有某些字符而造成不可预知的错误。

八·if的使用技巧之“给定初始值”
代码在进行if判定之前给定一个有意义的初始值,这个值可以使else时候的值,这样的话可以减少一定的代码量,使代码简洁,另外也可以在一些情况下减少一次赋值操作,提高一定的效率。例如:

1
2
3
4
5
6
7
$long = 0;
$rand = mt_rand(0,5);
if($rand>3){
$long=5;
}else{
$long=1;
}

则可写成:

1
2
3
4
5
$long=1;
$rand = mt_rand(0,5);
if($rand>3){
$long=5;
}

九·if的使用技巧之“用”&&” 替换 if”
上面的代码可以使用&&来进一步减少代码量,例如:

1
2
3
$long=1;
$rand = mt_rand(0,5);
$rand>3 && $long=5;

这样代码中直接省略了if的操作,节约了操作步骤,同时减少了代码量。但是这种写法在以下的情况下要注意:

1
2
3
4
5
6
$num_1 = 1;
$num_2 = 1;
$rand = mt_rand(0,5);
$rand>3 && $num_1=5 && $num_2=7;
var_dump($num_1);
var_dump($num_2);

这段代码当rand>3的时候运行会出现问题,其运行结果会如下:

1
2
boolean true
int 7

会出现这个原因的问题主要是因为运算符的优先级问题,在程序中=的优先级低于&&且是从右往左的,所以当rand>3的时候真正的运行顺序会是如下这样:

1
2
3
$num_2=7 //$num_2=7,所以$num_2的值是正确的
5&&$num_2 // 即5&&2 ,结果为true
$num_1 = (5&&$num_2=7); //即 $num_1 =true,所以$num_1的值错误为了true

如果想用上面这种形式实现连续赋值操作的话,就要使用()来进行分割,即如下代码:

1
$rand>3 && ($num_1=5) && ($num_2=7);

另外如果使用&&和||配合的话,可以实现伪原子性操作,例如(((a=1)&&(b=2)) || (a=0)&&(b=0));不过这种操作还是推荐使用if语句去完成,因为如果后半截在恢复时某一个出了问题会比较麻烦,虽然理论上前面可以修改成功的变量后面也可以成功,不过还是有一定的危险性导致部分无法恢复。
十·if的使用技巧之“用三元运算符替换if”
使用三元运算符和使用&&的目的都是一样的,减少代码量,这里就不再过多陈述。

十一·if的使用技巧之“去掉多此一举的if”
很多时候我们会写出如下的代码:

1
2
3
4
5
if(1==$a){
return true;
}else{
return false;
}

其实这种写法完全没有任何的意义,可以直接简化为:

1
return (1==$a);

对于这种本身返回值就是bool值的数据再次进行判断返回bool值完全是没有意义的,如果你想取反操作,例如:

1
2
3
4
5
if(1==$a){
return false;
}else{
return true;
}

也完全可以直接写成:

1
return !(1==$a);

十二·表驱动法
对于很多时候我们需要用N多个if,elseif,elseif…来达到连续判定完后取出某个值的效果,例如:

1
2
3
4
5
6
7
8
$data = array();
if(‘login’==$type){
$data = array(‘uid’=>1,’pwd’=>123);
}elseif(‘register’==$type){
$data = array(‘username’=>max,’new_pwd’=>432);
}elseif(‘put_info’==$type){
$data = array(‘something’=>’’Hello);
}

向上面这样的连续判断效率较低,有些人会说改成switch case 的写法,效率会高过if,但是依然是十分的繁琐,如下:

1
2
3
4
5
6
7
8
9
10
11
12
$data = array();
switch($type){
case ‘login’ :
$data = array(‘uid’=>1,’pwd’=>123);
break;
case ‘register’:
$data = array(‘username’=>max,’new_pwd’=>432);
break;
case ‘put_info’:
$data = array(‘something’=>’’Hello);
break;
}

但是这样写依然会比较麻烦,且运行效率也不会太高,当数据量较大的时候速度会比较慢,如上程序改成如下样式:

1
$data_arr = array(‘login’=>aarray(‘uid’=>1,’pwd’=>123),‘register’=>array(‘username’=>max,’new_pwd’=>432),‘put_info’=>array(‘something’=>’’Hello));

使用的时候只要是

1
isset($data_arr[$type]) && $data = $data_arr[$type];

就可以取到数据,在php中数组使用的是hashtable,时间复杂度是O(1),运行速度远远高于以上两种,另外书写起来也更简便的多。如果传入的参数是开始未定义的也不会运行查找浪费大量的系统资源。

十三·使用更精悍短小的代码
函数的最佳最大长度是150行代码,这样的代码比较便于维护,也方便修改,对于某些过于集中的算法函数,可能长度会大于这个长度。不过尽量还是不要超过,短小的才是美好的,短小的便于理解也便于修改,而功能相对单一的代码也就意味着可以复用它的地方会更多,有更好的复用性,另外当程序出问题的时候,测试起来也会相对简单好定位,便于维护修改。

十四·避免使用幻数
幻数,简单来说既是我们所说的硬编码,当程序中多处用到了一个值的时候,最好将这个值做成一个变量,使全局中就这一份,当需要修改的时候,可以只修改这个一文件,而不用挨个文件修改,想想如果一个值在100个或者更多的文件中用到,而你没有做成全局的变量,你会怎么样呢?不要说不可能,最简单的一个例子:

<meta http-equiv=”Content-Type” content=”text/html; charset=gb2312″ />

这段代码大家肯定很熟悉,现在让你修改一下编码,改成utf-8的,你怎么办呢。两种处理方式,一种是做模板,需要修改的时候就一份,另外一种是直接编码就是一个全局的变量,我只修改一个值,如果你用了幻数,你的工作量有了。这个是个很典型的例子,其实还有很多的值都是需要做成变量而我们直接使用的幻数。

十五·中间结果赋值给变量
当一个表达式中嵌套层数过多,逻辑过于复杂的时候,将其拆分成一块块的,将其每一块的结果赋值给中间变量,这样可以降低程序的阅读难度和提高可维护性。

十六·复杂的逻辑表达式做成布尔函数
当某一个判断比较复杂的时候,可以考虑将其做成一个布尔函数,不要怕这个函数里面的代码少,很多时候这样写可以使你的逻辑更容易维护,另外碰到相同逻辑判定的地点还可以直接复用,不需要一处修改处处修改。

十七·永远不要复制粘贴雷同的代码
大段相同的代码实现类似的但是略有不同的程序功能的时候,我们很容易就回进行复制完后修改,其实这种做法会有很大的问题,例如,一个功能段,几十个地方使用了它,完后发现有了一点点的问题需要修改里面的一部分代码,这个时候就会出现问题,挨个文件改麻烦不说,如果一旦有漏改的情况,那么将会造成比较麻烦的错误。其较好的做法是利用参数来区别不同的调用方法,例如加一个$type=’login’这样的参数值,默认给一个默认参数,这样即使原来掉用过这个方法的地方不做修改也可以得到正确的结果,当出问题的时候只需要修改一个地方整个项目都进行了修改。
类似于复制雷同代码一样,永远不要直接修改线上服务器代码,因为你不知道有多少台服务器要改,你也不知道你会不会漏改,另外,你会不会被累趴下也不得而知,做一份代码,其余的事情交给运维去处理就好了,毕竟服务器那么多你去改这个有点太不靠谱了。

十八·备份源代码文件
看了这么久了,真心不容易呀,终于到了最后一条了,咱们写代码也是如此,点灯熬油无数个夜晚终于大功告成了,结果发现代码丢失了,别和我说不可能,我遇到过,一个朋友自己写的游戏,和运营都说好了,结果发现硬盘损坏数据都丢失了,悲催哀哉,所以最后一个建议,代码处处留档,最好有一个网上的空间存代码,如果你的代码不想让人看的话那些项目维护网站就算了,你要是自己有线上服务器可以存一份,个人比较推荐存在云盘里,我的很多代码存在百度云空间里,这样的好处是自己的电脑挂掉了也不会有事,另外用的时候比较方便可以拿到,保密性也还不错,当然,你也可以多存几个网络存储上。
啰啰嗦嗦说了这么多,希望对大家有所帮助。