Loading...

饭否/做啥应用之共同的好友

Filed under: 编程, 网络 — 深柳堂主 @ 2008-11-22 09:00:38 Comments

饭友布丁丁丁提过这样一则饭否应用的创意:找出自己和另外任一饭友之间共同的好友。今天我使用php将其粗略地实现了。步骤如下。

  1. 假设两位饭友分别为ffA和ffB。
  2. 通过饭否API得到ffA的好友列表,保存每个好友的ID至数组friendIDsA中,备用。
  3. 同理,得到ffB的好友列表ID数组friendIDsB中,备用。
  4. 求friendIDsA和friendIDsB的交集,保存至数组friendsList表中。
  5. 输出列表friendsList。

在实现时,具体细节:

  1. 使用GET的方法将需要处理的饭否ID传递给程序,而不是使用对话框、文本框的方式。
  2. 下载饭否好友列表,用到了curl函数。curl作为下载利器,很好用。
  3. 分析、获取好友信息,用到了xpath函数。xpath在xml中快速定位,很好用。另外可参阅《饭否消息解析之从minidom到xpath》一文。
  4. 获取A和B的交集时,使用了array_intersect函数。本函数是求两数组的交集。
  5. 在处理时,遇到“仅对好友公开类型”的饭友,将其略过。
  6. 输出列表时,界面仍然比较粗糙。本人对于网页的框架、CSS都知之甚少,也就不献丑了。

使用方法:先查一下两个人的饭否ID,然后修改下面的链接:
http://iregex.org/fanfou/friends.php?a=zhasm&b=passingby,更换其中的zhasm和passingby为您感兴趣的饭否ID。

另,”做啥”的也做出来了,格式如http://iregex.org/zuosa/friends.php?a=rexxer&b=alex

显示效果:如下图。


  1. Tears


  2. 令糊葱

  3. 如小果

  4. 妖娆男

  5. 流连

  6. 小北Roy

  7. 饭而不否

  8. 蛮子

  9. 如是如来

  10. 撕烤者

  11. 程小秸

  12. 王金牙儿

源代码:

<?php
function getFriendList($id)
{
    $url="http://api.fanfou.com/users/friends.xml?id=".$id; 
    //print $url;
    $ch = curl_init($url); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
    $output = curl_exec($ch); 
    curl_close($ch);
    $xml=simplexml_load_string($output);
    $result=$xml->xpath("//id");
    return $result;
}
 
function myGenerate($id)
{
    $url="http://api.fanfou.com/users/show.xml?id=".$id; 
    //print $url;
    $ch = curl_init($url); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
    $output = curl_exec($ch); 
    curl_close($ch);
    if ($output=="验证失败")
    {
        return;
    }
    $xml=simplexml_load_string($output);
    $name=$xml->xpath("//user/name");
    $img=$xml->xpath("//profile_image_url"); 
    $line="<li><a href=\"http://fanfou.com/$id\"><img src=\"$img[0][0]\" style=\"margin:0px 10 px 10px; border: 1px solid rgb(255, 255, 255); \"><br />$name[0]</a><br /><br /></li>";
    print $line; 
}
 
function myPrint($list)
{
    print "<ol>";
    foreach ($list as $value) 
    {
        myGenerate($value);
    }
    print "</ol>";
}
print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />";
//to ensure the encoding system to be utf-8.
$a=$_GET["a"];
$b=$_GET["b"];
$my=getFriendList($a);
$his=getFriendList($b);
$our=array_intersect($my,$his);
myPrint($our);
?>

有多少人在收听你的广播

Filed under: 编程, 网络 — 深柳堂主 @ 2008-10-21 00:19:11 Comments

MS之前已经引用过一次了,我再不厌其烦地引用一次——

“譬如咱们这次同船的许多人,没有一个认识的。不知道他们的来头,为什么不先不后也乘这条船,以为这次和他们聚在一起是出于偶然。假使咱们熟悉了他们的情形和目的,就知道他们乘这只船并非偶然,和咱们一样有非乘不可的理由。这好像 开无线电。你把针在面上转一圈,听见东一个电台半句京戏,西一个电台半句报告,忽然又是半句外国歌啦,半句昆曲啦,鸡零狗碎,凑在一起,莫名其妙。可是每 一个破碎的片段,在它本电台广播的节目里,有上文下文并非胡闹。你只要认定一个电台听下去,就了解它的意义。我们彼此往来也如此,相知不深的陌生人——”柔嘉打个面积一寸见方的大呵欠。像一切人,鸿渐恨旁人听自己 ” 说话的时候打呵欠,一年来在课堂上变相催眠的经验更增加了他的恨,他立刻闭嘴。柔嘉道歉道:“我累了,你讲下去呢。”鸿渐道:“累了快去睡,我不讲了。”柔嘉怨道:“好好的讲咱们两个人的事,为什么要扯到全船的人,整个人类?”鸿渐恨恨道:“跟你们女人讲话只有讲你们自己,此外什么都不懂!你先去睡罢,我还要坐一会呢。”柔嘉佯佯不睬地走了。鸿渐抽了一支烟,气平下来,开始自觉可笑。

其实大家不论是在twitter,饭否,还是做啥,都像方鸿渐说的那样,都只是一句句支离破碎的电台广播而已。在频繁换台的陌生人耳朵里,随意泛听时,或许会有只言片语引起注意;只有认定你的频道收听下去,才能连贯地读懂你的心脉,理解你的悲欢。今天我的话题就是,在blog上显示你的饭否或“做啥”听众数量。

这本不是我的创意。是前天我无谓中浏览一位饭友的博客时,发现了http://twittercounter.com/提供了这样的服务,能将你在twitter中的followers的数量以图像形式显示出来,例如本人的图片是TwitterCounter for @zhasm。可是我最常用的饭否却没有类似网站提供类似服务。我思考了一下,觉得不太难,自己也可以实现。

实现思路:

  1. 通过现有的饭否API http://api.fanfou.com/users/show.xml?id=zhasm 来获得当前饭否用户的信息,其中的ID就是所要统计的用户的ID,听众数量在followers_count节点中。其结构是:<followers_count>(\d+)</followers_count>。
  2. 使用网页语言(我用的是PHP)来获得该数值,并将其转换成图片。基本要求是即时更新,即,不是只生成当前听众数量统计,当数量有变动时,还能随时更新。
  3. 提供在线的图片输出服务。

由于饭否的API比较完备,第一步没问题;第二步我没有使用php的xml解析函数,而是使用了比较顺手的正则表达式来获取该数值;生成图片的模板,我参考了feedsky的。其三维效果是通过明暗的线条来实现的。为省事,将中文改为英文了。至于在线的图片输出,我慷慨地使用了自己博客所在的cph空间,将网页放在http://zhasm.com/fanfou/里面。效果如图:

饭否听众统计图片使用方法很简单,因为功能也很简单:)。具体如下:

  1. 取得你的饭否ID。如果你的饭否链接是http://fanfou.com/regex,而你的饭否用户名是正泽,则你的ID是regex,而不是正泽。值得一提的是,我写的听众统计功能,暂时还不支持中文ID。
  2. 取得图片。图片位置在
    http://zhasm.com/fanfou?id=regex


    http://iregex.org/fanfou?id=regex
    推荐国内的用户使用前者(zhasm对应cph主机),国外的用户使用后者(iregex.org对应dreamhost主机)。
  3. 您可以在blog中这样调用(请酌情将YourfanfouID换成相应值):
    <a href="http://fanfou.com/YourfanfouID" title="个性提示语,例如hello world,当鼠标移动到链接上时显示的文字" target="_blank">
    <img src="http://zhasm.com/fanfou?id=YourfanfouID" />
    </a>

实现此功能后,我将此消息群发到fanfou、twitter、jiwaide、zuosa、plurk上。zuosa的老大alex发现了我的消息,委托我为zuosa也写一个。

我阅读了zuosa的api文档,发现对应的函数并没有提供followers_count功能;与alex沟通,zuosa两天后就在http://api.zuosa.com/users/show.xml加上了本功能。而我原有的php脚本也无需改动太多,只需要修改两行就能服务于zuosa,一条是api接口,另一条是正则式解析的位置。根据alex要求,将followers修改为粉丝;同时去掉了原来数值的前导0。现在效果如下:

类似,做啥听众统计图片使用方法如下:

  1. 取得你的做啥ID。如果你的做啥链接是http://zuosa.com/rexxer,而你的饭否用户名是zhasm,则你的ID是rexxer,而不是zhasm。值得一提的是,我写的听众统计功能,暂时还不支持中文ID。
  2. 取得图片。图片位置在
    http://zhasm.com/
    zuosa?id=rexxer

    http://iregex.org/zuosa?id=rexxer
    推荐国内的用户使用前者(zhasm对应cph主机),国外的用户使用后者(iregex.org对应dreamhost主机)。
  3. 您可以在blog中这样调用(请酌情将YourZuosaID换成相应值):
    <a href="http://zuosa.com/YourZuosaID" title="个性提示语,例如hello world,当鼠标移动到链接上时显示的文字" target="_blank">
    <img src="http://zhasm.com/zuosa.com?id=YourZuosaID" />
    </a>

目前的不足之处是,不支持中文ID;没有提供更详细的定制功能。还有什么不足之处呢,请留言告之。

2008.10.23更新:
应alex要求,新增一种风格,如图所示:,使用方法不变,图片路径改为http://zhasm.com/zuosa/2?id=YOUR_ZUOSA_ID。

2008.10.27更新:
将alex要求的方式做为默认,格式如,使用方法不变,图片路径改为http://zhasm.com/zuosa?id=YOUR_ZUOSA_ID。

关于饭否消息打包下载的限制以及对于饭否分享功能的建议

Filed under: 编程 — 深柳堂主 @ 2008-07-01 21:48:19 Comments

真是多事之秋。也罢,莫谈国是。说一说饭否得了。

今天与饭否的官方沟通过饭否服务器的限制问题。起因是,本人正在写的饭否应用程序,是①,通过抓取饭否页面;②,使用正则表达式解析所需要内容实现的。最近在读取饭否页面的过程中, 发现读取一定数量的fanfou页面之后,就无法登录fanfou了。今天得到的答复是,在10分钟内抓取不得超过100页。这个确定的答案让我很满意。我不是说,10分钟100页是多是少,而是说,有定量的标准可以参考时,觉得更加有把握。

既然10分钟100页,折合每6秒1页。这个数字还是有些保守。因为我每10秒读取1页连续抓100页时,仍然会被封IP。现在我每下载1页,就sleep(15),居然可以长时间下载。替一位朋友下载了所有的饭否公信和分享,合计300多页,这个过程很顺畅,当然,也很漫长。鉴于饭否消息的特点,第一次抓取的时间,是无法快起来的。但是,一旦第一次已经把之前所有的消息下载过后,再次下载就会很快,只需“同步”一下即可,只下载最新消息,而无需重新下载全部消息。这样就能在本地完整保留所有的饭否消息,从而进行诸如查询、导出、统计之类的操作。

在没有得到饭否官方提供的最大负载数据之前,我是这样变通操作的:被封IP后重启一下ADSL猫,一分钟后即可再次登录饭否。原因是ADSL会重新获得随机IP。当然,现在可以合理地设置抓取间隔,不被封锁,才是更好的选择。

关于打包下载饭否消息的方法,其实不止使用专用程序一条途径。还见过使用其它工具(使用迅雷等批量下载网页,再使用textforever之类的工具析取的。对于这样饭友,我想和您握手。因为,咱们的思路是一样的,都是先下载,再析取。只不过使用的工具不同而已。

本人写的新版抓饭程序何时公布?对不起,暂缓。如果您对脚本感兴趣,我可以把脚本发给您,并告诉您怎么使用。完整的程序需要更长一段时间,包括脚本的完善、数据库操作、界面的更新……等等等等。

打包下载分享的数据库版本还没写出来,原因同上。

对于饭否分享,我有以下2条建议:

  1. 建议“已经删除”和“不公开”这两个属性分开。在批量删除时容易误伤不说,不公开的还有公开的可能,万一原消息主人再度公开,还可以再次下载。
    难度:低。
  2. 建议在分享中加入digg思想。这个意见,拂汗提过一次。我觉得很好。发布一条消息后,每当有人分享一次,该消息的digg计数就++,删除分享一次,该消息的digg计数就–。一个人的popularity权重与所有digg计数来挂钩,从而激励大家多发有意义的言论。同时,该digg计数也给想要删除该消息的主人以参考:当想删除时,会有提示:“该消息已被N个人分享,您真的要删除吗?”
    难度:较高。因为需要涉及原有表的alert操作,手术较大。再加上原有分享消息是否重新计算,等等。

中文编程之我见

Filed under: 编程 — 深柳堂主 @ 2008-04-08 14:59:24 Comments

读了饭友创亿无限的文章《我对中文内核的一些想法》之后,谈一下自己的见解。本文皆为个人观点,必有偏激、先入为主之处。欢迎讨论、争论。

总体说来,我全面提倡英文编程,同时,对中文编程也充满了兴趣。先说一下英文编程的便利条件。

  1. 打字方便。无须安装输入法,26+10个字母数字组合就能胜任99%的输入任务。而且,做成IDE时也方便,可以输入几个字母时由程序自动提示后边的内容,减少工作量,提高准确性。中文编程的话,不是不行,而是工作量更大些。试想,你使用拼音或字形输入法时,不但有输入法的提示,还有随之而来的编程提示。当然你可以选择不提示。

    不过,方便与否是一种主观唯心的感受。你当然可以拥有自己认为方便的设置。

  2. 编码统一。除非涉及到输入输出,否则一般情况下不必考虑是utf8还是gbk,抑或gb18030。全部使用半角字符,也省得来回切换。虽然中文编程中也可以使用全角半角混用(不规范),或者只用全角,总而言之是麻烦事。
  3. 英文的更具有通用性。你可以说,中文是全球第一大语言,也可以说,使用中文的编程人数正在处于上升趋势。但是,英语程序人员的范围广,编程资料也更多用英语写成,这是无可否认的。MSDN是用英语写的,Linux内核使用英文来写备注,印度的程序员大部分使用英语(这个例子有些极端了呵呵,他们的官方语言之一就是英语,因此他们在使用英语的编程资料时更有得天独厚的优势,相对于官方语言并非英语的程序员来说)。
  4. 标准化。标标准化是提高效率的捷径。功能标准化(发布标准API),有利于减少重复劳动,降低前期时间、研发成本,语言标准,有利于更好地沟通。如果我们是为了一切做到大而全、小而全而非得成立和采用自己的标准,则不啻是重复发明车轮。
  5. 便于推广。有人说了,MSDN也有中文版。不错,它是为了把它的技术推广给使用中文的用户罢了。“用户使用什么语言,我们就推广什么语言版本的服务。”这一概念很符合市场营销的思想。推而广之,我们的产品,如果想让老美、老英,或东边那个小岛国,以及其它国家的用户使用的话,也会努力做到使用客户所使用的语言。这一点在OEM中体现得尤为明显。即使你的库是以lib、dll形式发布,其说明文档总得翻译成人家能看得懂的语言吧?即使后台代码可以使用中文编程,前台界面你总得翻译成人家能看得懂的语言吧?当然,如果编程只是自娱自乐,不必与人交流,不必推向市场,或者不必推广到更广大的市场,那就悉请尊便了,使用火星文也没人说NO,使用旧石器语言也无可厚非。
  6. 使用英语不等于不爱国。在泛爱国论抬头的年代,言行稍微偏激就会被扣上“卖国贼”的tag。awflasher有一篇类似的文章,写道:“有些人,说着英语,却在默默地为祖国贡献。”

相比之下,中文编程还有很长的路要走。不是很长,是太长的路。

  1. 敌众我寡。之前所有的语言都是以英语为关键词的,英语已经占据了编程语言的每个角落,每种语言都有数种方言,都有许多IDE,广泛应用于底层、界面、数据库、文本、语音、网络、移动设备,诸如此类。可以说是上至原子弹,下至卖鸡蛋。作为跟进者,中文编程不是向c语言、汇编语言、perl、python、php等等语言中的某一个来挑战,而是要向全部语言来挑战。中文编程语言,能搜索到的有易语言、以前常常活跃在aogosoft.com却经常被冷落的“邱明中文汇编”(邱明的网站已经无法登录)、O汇编语言(OASM)、中蟒(基于python),只是散兵游勇,廖若晨星。首先从敌人数量上来说,绝对是敌众我寡,在横向与无法与之抗衡。
  2. 敌强我弱。从语言历史上来说,以英语为关键词的编程语言,老的有了几十年的历史,中的也有十多年历史。经历了多次改朝换代、性能优化,达到的高度不是中文编程在一两年、三五年内所能赶上的(换句话说,如果指望在三年达到别人三十年才能达到的高度,就需要在三年内做完人家在三十年内所做的努力的基础上,再有所超越)。而中文编程只是在某些领域能够正常运行而已,无法超越过同类英文类编程语言。在纵向上,亦输了一局。

中文编程的出路。但是历史总是给新生事物以机会的,否则世界怎么会发展?只要找准了方向,找准了定位,就总能够崭露头角,立于不败。

  1. 找准方向。数据运算首先不是中文的强项了,就不必再来逞强了,老老实实地使用阿拉伯字母(也是外国字母哟)就得了。其它也类似。中文编程的用武之地在于:

    1. 有迫切需要的(无论来自国内还是国外);
    2. 外国现有的技术还没有达到的;
    3. 中文编程恰能大显身手的。本点是最重要一点。

    英文也不是放之四海而皆准的。举例来说,它就无法完美地处理中文。呵呵。个人比较喜爱的正则表达式在处理英文字母和数字时,展示了令人难以致信的强大。但是,它在处理看似毫无逻辑可言的中文时,却似狮子咬刺猬,无从下嘴。如果能有一种中文语言能够完美地实现中文正则表达式,其功绩将是里程杯似的。(警惕:如果流氓会武术,如果G*F*W会中文正则表达式!)

    这里只是提供一个方向。路子还得自己选,自己走。这个任务交给易语言们了。只要有需要,就会出现满足这种需要的产品。亦即,只要能满足人们的某种需求,就一定能够在市场竞争中生存。

  2. 站对位置。一开始就以改变世界为目标,总是有些唐吉诃德。同理,中文编程大可不必一开始就把以前所有编程语言都走过的路子再走一遍,跟老人抢饭吃。就跟mysql天生就是做数据库的、php从来都是做网络的一样,只有找准了中文编程的位置,才能变得不可或缺。
  3. 提供新特性。虽然程序员喜欢自己最拿手的语言,但这并不意味着固步自封而不学习新事物。如果中文编程在某个领域能够胜出传统语言一筹,则总是会有程序员主动(或被项目经理逼着)学习该种语言的。

我对中文编程很有好感,而且十分期待。不过,鉴于中文的编程远远没有达到英语编程高度和普及度,现在就大力推广和普及易语言,总觉得为时过早。对于用户来说,并不关心所使用的程序是使用易语言还是C语言,只要易用、满足功能上的需要即可;对于程序员来说,易语言尚不能代表先进的生产力的方向,无论是执行效率还是进化阶段,远远没有走在技术前沿。它还有很长的路要走。这条路,应该主要靠自修,而非政府的催熟。政府的作用可以是提供资金上的支持,而非政令上的规范。

考虑到jyf1987所言的二级考试,主要是考思路和算法,使用具体什么语言实现倒在其次,因此,如果仅仅是为了推广中文编程而推广易语言,我觉得有些欠妥。理想的情况是,吸引胜过号召,诱惑胜过强迫。如果采用中文编程的语言(包括易语言)从执行效率、编程便捷度上都胜其它语言一筹的话,桃李虽不言,树下自成蹊。

正则表达数与合数判定

Filed under: 编程 — 深柳堂主 @ 2008-04-01 10:00:40 Comments

quhao那里,了解到这样一篇文章:牛B的正则表达式:素数判定与线性方程求解

今天又学到一个牛B东西。你相信吗?正则表达式竟然可以用来判定素数,甚至可以用来解方程!下面这段正则表达式可以用来判断,一个字符串的长度是否为合数(假设这个字符串里全是字符’1′):
^1?$|^(11+?)\1+$

初看上去,这条正则式怪怪的。不过,略为分析一下,它就原形毕露。

中间的备选符竖线把正则式分数两部分,^1?$和^(11+?)\1+$。

先看第1部分。
^1?$匹配的是,行首,1个或者0个’1‘,行尾。
换言之,它匹配的是一个空行或者只含一个’1‘的行。

再看第二部分。
先说一下正则式的基本规则。

  • +:量词,表示前面一个单位的一次或多次重复。
  • ?:量词,表示前面一个单位的出现0次或1次。
  • +?:连用,表示前面一个单位的一次或多次重复,不过倾向于越少越好。正所谓:懒惰模式。
  • ():捕获。这里面的内容重复出现时,可以使用\1,\2之类的代词来表示。

我们切入正题。
^(11+?)\1+$
,它匹配的是,
行首,紧接着是由’1‘和m个1组成的捕获组(m是大于等于1的自然数),紧接着是N个这样的捕获组(n是大于等于1的自然数,n与m不必相等)。

11+?和\1+是理解这条正则表达式的关键。
我们再细分一下。

  • 1,匹配1个’1‘,仅此而已;
  • 1+?不能再分,它匹配的是1次或更多次的’1‘(为了表示方便,该次数我们用m来表示),?表示懒惰式匹配。因此,11+?可以表示为(1+m)个1
  • \1 表示前面所捕获的括号内的内容。后边又一个+,它匹配的是1次或更多次的’\1‘(为了表示方便,该次数我们用n来表示)。

这样,我们澄清了这条正则式试图表达的意思:
^(11+?)\1+$,它匹配的是由(1+m)(1+n)个1组成的字串。其中m和n都是大于等于1的自然数。n和m可以相等,也可以不相等。

全局来看,^1?$|^(11+?)\1+$匹配的是一个空行,或者一个’1‘,或者(1+m)(1+n)个’1‘。

(1+m)(1+n)的集合是什么样的数呢?连编程都不用,我直接在excel里列了一张表格:

考虑到n和m相等的情况会出现对称。我们只考虑其中一半即可:

即,得到的数列为:

4,6,8,9,10,12,14,15,16,18,20,…

从其产生的规则来说,上面的数全是合数(均由乘积构成);但是,上面这些数列是否就等同于合数集,这就不是我能证明的了,给数学系的同学去证明吧。

值得补充的一点是,上面两个图表只是使用的后半部分的正则式,即只有^(11+?)\1+$不包括^1?$。如果按照原正则式补全,此数列就会变成:

0,1,4,6,8,9,10,12,14,15,16,18,20,…

根据合数的定义,0和1是不包括在内的。不知原作者为什么把0和1也要囊括进来。

虽如此,我十分佩服写出这条正则式的大牛。理解其含义之后,我也会心微笑。同理,我们还可以构造许多类似的正则式,只要满足两个条件,一是你知道有某条简洁的公式;二是你知道如何使用正确的正则语法来表达出来。

PS:

原贴中有一条例子是三元一次方程11x + 2y + 5z = 115

^(.*)\1{10}(.*)\2{1}(.*)\3{4}$

解密:此处的.*共出现3次,互不约束,当然是三元一次