网络寻租

Programmer, Gamer, Hacker

Utf8介绍

| Comments

今天学习了一下utf8的相关概念, 发现自己的理解还是不很透彻, 这里整理一下:

什么是UCS?

我们首先需要知道如何标识一个具体的字符, 国际上对于字符标识有一个东西, 叫UCS, 全称: Universal Character Set,

它是关于所有字符编码的标准. 简单地说, 为了能够规范我们所有字符的表示形式, 把所有字符都映射成一张表, 每个字符都指代单独的一个数字做标识.

什么是UTF-8?

上面的UCS只是表示字符的标识, 并没有说明具体的表示方式是什么. 所以就有了UTF-8, 用来把UCS转换成计算机能够处理的字符串. 它为了节省空间, 方便解析和除错做了优化. 具体表示方式如下:

  • 小于u80的字符, 直接打印为一个字符, 这个是为了和ASCII标准兼容.
  • 大于等于u80小于u800的字符, 分割成2个字符, 第一个字符开始为110, 第二个字符开始为10, 拆分的方法是先填满后面的字符(等会看后面的例子).
  • 以此类推…

说的不是太清楚, 这里有一个UCS映射到UTF-8的表, 一看就明白了:

U-00000000 – U-0000007F:    0xxxxxxx
U-00000080 – U-000007FF:    110xxxxx 10xxxxxx
U-00000800 – U-0000FFFF:    1110xxxx 10xxxxxx 10xxxxxx
U-00010000 – U-001FFFFF:    11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 – U-03FFFFFF:    111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 – U-7FFFFFFF:    1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

同时, 长的表示方式不能涵盖短的表示方式, 所以下面的范围是错误的(可以快速排除错误):

1100000x (10xxxxxx)
11100000 100xxxxx (10xxxxxx)
11110000 1000xxxx (10xxxxxx 10xxxxxx)
11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)

我们来看具体的例子(python代码):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 比如©这个符号, UCS的标识为: \u00a9:
>>> print u"\u00A9"
©

# 我们把a9转换成真正的表示方式:
>>> u"\u00A9".encode('utf8')
'\xc2\xa9'

# 我们也可以把真正的表示方式转换成标准里面的标识.
>>> '\xc2\xa9'.decode('utf8')
u'\xa9'

# 我们来看一个分割的例子:
>>> print u'\u2260'


# 转换成utf8就被拆散了:
# u+2260 = 0010 0010 0110 0000
# 11100010 10001001 10100000 = 0xE2 0x89 0xA0
>>> u'\u2260'.encode('utf8')
'\xe2\x89\xa0'

结论

现在还没有什么心得, 总之, 了解了上面的概念, 才能处理好平时遇到的字符编码问题.

参考资料: – http://www.cl.cam.ac.uk/\~mgk25/unicode.html

如何学习python

| Comments

image

我们假设你是一个初级程序员, 只懂得一点点的基础知识, 希望能够用python来做开发. 这篇文档就是为了满足以上目标而写的.

大纲

按照这篇文档所指示的任务过一遍, 你就能够做到:

  • 熟悉python语言, 以及学会python的编码方式.
  • 熟悉python库, 遇到开发任务的时候知道如何去找对应的模块.
  • 知道如何查找和获取第三方的python库, 以应付开发任务.

学习步骤

安装开发环境

如果你在window下, 去下载pythonxy安装起来, 然后运行python, 进入python解释环境.

如果你在ubuntu下, 执行: sudo apt-get install python, 然后在命令行下运行python, 进入python解释环境.

学习方法

作为一名成熟的开发人员, 我学习新东西(假设是pyqt)的习惯方式是:

  • 直接用google搜索pyqt的官方网站.
  • 按照官方网站的说明, 下载pyqt. (如果是用ubuntu, 看看软件库里面是否有足够新的版本)
  • 下载过程中, 开始阅读官方网站上面的教程.
  • 一边看教程, 一遍按照教程使用pyqt.
  • 如果发现教程不够全面, 用google搜索是否有对应的教学书籍可以看.
  • 示例学习完毕, 开发一个玩具程序, 用来检验自己是否需要用到的功能.

开始学习python

我建议你学习的过程也按照上面来, 首先过一遍python官方文档:

http://docs.python.org/tutorial/index.html

如果你觉得英文太有难度的话, 去看 python简明教程

或者这里有一个google的python课程: http://code.google.com/edu/languages/google-python-class/

然后做 http://www.pythonchallenge.com/ 这个网站上面的题目练练手. 如果卡在某一关太久, 可以看答案(google python challenge answer), 做完后看看别人的编码方式和自己有什么区别.

小项目

做完一遍后, 你会发现已经熟悉了基本的python开发. 然后做点小项目吧. 这里是一些题目, 挑感兴趣的去做.

  • 写一个简单的计算器/记账软件/扫雷游戏(用pyqt库做界面)
  • 写一个聊天室网站(用webpy框架, jquery刷新新的回复)
  • 写一个爬虫, 获取douban上面所有用户的地点, 画地点分布的直方图(用lxml解析, 保存数据到sqlite里面去, 用matplotlib画图)

FAQ

Q: 遇到了问题, 到哪里求助?

A: 上 http://groups.google.com/group/python-cn (需要翻墙) 或者 http://stackoverflow.com 提问就可以了.

Q: 如何查找python的某个功能?

A: 看官方文档. http://docs.python.org/library/index.html

Q: 如何用python完成一个任务(比如写网站)?

A: google: python 写网站, 或者 google: python web development.

你不需要一天工作8小时

| Comments

image

我们每天定时起床, 吃饭, 上公车, 赶在9点之前到达公司, 然后在哈欠中开始一天的工作.

刚刚打开电脑, 看了一个小时的邮件, 打算真正开始工作的时候, 就被邮件通知需要参加一个有很多头头出席的会议, 会议里面讨论的东西和你八杆子打不着, 等到最后的时候才问你一个很简单的问题, 或者布置给你一个这周必须解决的任务.

终于从封闭的小会议室里面出来, 呼吸到了一点新鲜空气, 觉得自己要休息一会, 上上网聊聊天(如果老板不在的话). 忙碌一会后, 到了吃中午饭的时间.

中午只有半个小时的休息时间, 刚好吃个午饭, 回到座位上又开始工作, 但是晕乎乎地一下午过去了, 然后发现到了下班时间, 头脑瞬间清醒过来, 发出几封必须得在今天发出来的邮件, 然后把电脑关掉下班. 回到家里面发现自己太疲惫了以至于只好看看电视剧打发时间.

这是我们一天的工作, 这是我们一天的生活. 但是问问自己, 一天完成了什么? 每天工作8小时, 下班后疲惫不堪, 有谁能够敢说这一天真正做了什么有价值的事情?

如果….

每天早上来到公司, 你是不是很困? 那是因为你睡眠不足, 人不应该在这个时间工作, 而是去小跑一会, 和其他人聊聊天, 说说话.

你不一定要参与开会, 你只需要和其中的一个人或者几个人发发邮件, 实在不行了, 找2,3个人开开小会就可以了.

你不一定要在下午工作时间到了的时候开始干活, 半个小时的午睡就能让你精神焕发.

甚至你不需要每天都在办公室里面坐8小时, 办公室环境嘈杂, 甚至乌烟瘴气, 你到一个公园里面散一会步就能把困扰你一个星期的问题解决掉.

甚至你不需要去完成现在的工作, 你可以和老板说, 这部分的任务可以找一个外包公司, 甚至一个商业软件, 花费的钱比自己的人力费用少一半, 并且非常的稳定.

话说回来, 这份工作只是工作, 你应该拥有控制自己工作时间内干什么的权力. 老板给你钱是为了让你解决问题, 而不是让你当他的傀儡. 完成布置给你的事情就好了, 剩下的时间是你赢得的, 你可以做任何你想做的事情.

只要不要把工作搞砸.

Shpaml源码分析

| Comments

在上次已经 介绍过shpaml, 它的代码总共只有365行, 既然这么一点代码, 没有理由不分析分析它的具体实现.

首先, 代码可以在这里看到: http://shpaml.webfactional.com/source_code

首先是入口出的代码:

1
2
3
4
5
6
7
8
if __name__ == "__main__":
    # if file name is given convert file, else convert stdin
    import sys
    if len(sys.argv) == 2:
        shpaml_text = open(sys.argv[1]).read()
    else:
        shpaml_text = sys.stdin.read()
    sys.stdout.write(convert_text(shpaml_text))

这里面是实现以下3种语法的功能, 太简单就不说了:

python -c “import shpaml; shpaml.convert_text()” echo ‘b | foo’ | python shpaml.py touch test.shpaml; python shpaml.py test.shpaml

然后, 从convert_text函数, 一直深入调用到了indent_lines函数(外面的几层都是包装), 这个才是重心.

我们知道, html是树状的, 输入的shpaml格式的文档本质上也是树状的. 我们需要把shpaml按照树状的方式解析出来, 同时对分析出来的数据做处理(加<>以及结尾加</tag>).

简单地介绍下代码里面的处理方式. 程序内嵌一个recurse函数, 这个函数的输入是字符串列表(就是需要转换的文本啦), 处理文本的时候如果发现有新的子树, 就会嵌套调用recurse, 用函数调用栈的方式来遍历tag树. 每次处理文本, 都会把生成的文本放到output这个字符串列表里面去. 下面是具体的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
def indent_lines(lines,
            output,
            branch_method,
            leaf_method,
            pass_syntax,
            flush_left_syntax,
            flush_left_empty_line,
            indentation_method,
            get_block,
            ):
    """Returns None.
    一堆注释不管它
    """
    append = output.append
    # 递归调用函数
    def recurse(prefix_lines):
        # 循环解析传进来的字符串列表
        while prefix_lines:
            # 列表已经处理过了, 分割成空格的前缀和后面的字符
            prefix, line = prefix_lines[0]
            if line == '':
                prefix_lines.pop(0)
                append('')
                continue
            # 我们看看这一行是否有缩进
            block_size = get_block(prefix_lines)
            if block_size == 1:
                # 如果没有缩进, 就根据状况来处理
                prefix_lines.pop(0)
                if line == pass_syntax:
                    pass
                elif line.startswith(flush_left_syntax):
                    append(line[len(flush_left_syntax):])
                elif line.startswith(flush_left_empty_line):
                    append('')
                else:
                    append(prefix + leaf_method(line))
            else:
                # 如果是一个新的缩进, 我们需要找到缩进的结尾, 然后把这一块数据取出来, 
                # 让branch_method处理下来
                block = prefix_lines[:block_size]
                prefix_lines = prefix_lines[block_size:]
                branch_method(output, block, recurse)
            # 循环消耗prefix_lines, 直到消耗完毕, 任务就完成了.
        return
    prefix_lines = list(map(indentation_method, lines))
    recurse(prefix_lines)

recurse 最后会进入到2个函数里面去, 一个是leaft_method, 它处理单行的一些语法, 比如: tag > tag2 > tag3 | text, 也是采用上面那种循环消耗字符串的方法. 这里略过不表.

另一个就是branch_method, 这里面的值是函数html_block_tag. 它里面是处理缩进后的一些语法. 处理完头部之后, 会把缩进里面的内容传给recurse函数, 就这样一步步解析玩子树. 里面的append函数就把解析玩的内容传给output, 最后打印成html代码.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def html_block_tag(output, block, recurse):
    append = output.append
    prefix, tag = block[0]
    if RAW_HTML.regex.match(tag):
        # 如果是html代码(<开头)就不解析头部
        append(prefix + tag)
        # 解析子树
        recurse(block[1:])
    elif COMMENT_SYNTAX.match(tag):
        # 注释..
        pass
    elif VERBATIM_SYNTAX.match(tag):
        # 子树不解析, 直接打印出来
        m = VERBATIM_SYNTAX.match(tag)
        tag = m.group(1).rstrip()
        start_tag, end_tag = apply_jquery_sugar(tag)
        append(prefix + start_tag)
        stream(append, block[1:])
        append(prefix + end_tag)
    else:
        # 普通的状况, 解析出tag
        start_tag, end_tag = apply_jquery_sugar(tag)
        # 输出tag头
        append(prefix + start_tag)
        # 解析子树
        recurse(block[1:])
        # 输出tag尾
        append(prefix + end_tag)

结论

shpaml采用函数嵌套调用的方法来解析和处理树状结构, 这个也是通常用的解析树状结构的方法(如果树状结构嵌套不多的话), 对于编程语法的解析, 也可以采用类似这样的方式, 对于每一个语法规则都有一个函数, 然后嵌套调用解析, 直到解析完毕.

Shpaml介绍

| Comments

image

不知道大家是否都写过html或者xml, 里面尖括号真是既然写又难看, 这里推荐给大家一个非常好用的工具: shpaml.

shpaml 是借鉴 haml (就是上面那个图片啦) 的一个工具, 可以极大地简化html/xml的编写工作. 并且不像haml那么重量级.

shpaml的生成工具只是一个简单的python文件, 你只需要在 这里 下载即可. 整个文件只有365行!

简单尝试一下

我们来看一个实际的例子. 比如我们需要写下面的html代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<html>
  <body>
    <div id="top-nav">
      <div id="top-nav-items">
      </div>
    </div>
    <hr />
    <div id="wrapper">
      <div id="header">
      </div>
      <div id="content">
      </div>
      <div id="sidebar">
      </div>
      <div id="footer">
        @2010 linjunhalida, all right reserved
      </div>
    </div>
  </body>
</html>

即使能够利用工具来自动生成很多文本, 上面的代码也非常难以阅读. 但是用shpaml的方式就不一样了

html
  body
    #top-nav
      #top-nav-items
    > hr

    #wrapper
      #header
      #content
      #sidebar
      #footer
        @2010 linjunhalida, all right reserved

是不是感觉一下清爽很多? 写起来也不那么废手指了?

具体语法, 直接查阅 shpaml官方教程 , 很简单的, 半小时搞定.

生成html代码

那么接下来我们如何把上面的文本生成html代码呢? 先保存成一个文件: xxx.shp, 然后运行

python shpaml.py xxx.shp > xxx.html

shpaml.py在 `这里`_ 下载.

打开xxx.html, 是不是和上面的html一模一样? 其他生成方法, 可以见 shpaml源码页面.

结论

  • shpaml采用缩进的方式来表示层级的递进, 这个方法和python的方法一致, 对于python程序员来说应该会很亲切.
  • shpaml用python写成, 整个代码只在一个文件里面, 感兴趣的同学可以学习学习. 它也非常容易嵌入到其他web框架中去.
  • 同样的, 如果你发现一个数据源存在很多的冗余信息(就像上面的html/xml), 可以仿照shpaml的方法, 来实现一个上层的模板语言.

希望你和我一样, 喜欢上shpaml.

如何把rss当作邮件来阅读

| Comments

image

根据 大妈gurudigger里面的idea, 我研究了一下如何把rss订阅都发送到邮箱中, 统一采用邮箱来处理每日的rss阅读.

尝试了一下以下工具/网站:

最后, 我在shlugchat里面发问, 某人推荐我使用 rss2email, 然后一试, 果然挺好用的.

rss2email会把所有的文章都以分开的邮件发送, 在gmail里面很好做阅读.

安装方法(已经在ubuntu源里面了)

sudo apt-get install rss2email

其他系统请见 rss2email 官方网站.

使用方法

rss2email的工作目录在 \~/.rss2email里面, 需要先拷贝配置文件

mkdir ~/.rss2email
cp /usr/share/doc/rss2email/examples/config.py ~/.rss2email/

然后, 需要修改config.py, 用来设置发送邮件的一些参数, 重点需要修改的是

# 默认是0, 需要改成1, 如果你像我一样采用gmail来发送的.
SMTP_SEND = 1 
# gmail的smtp服务器
SMTP_SERVER = "smtp.gmail.com"
# gmail需要认证, 所以改成1
AUTHREQUIRED = 1 
# 发送的邮箱用户名, 我为了区分专门注册了一个邮箱.
SMTP_USER = 'linjunhalida.rss.mail'  
# 密码
SMTP_PASS = 'xxx'  

好了, 我们输入需要接收rss邮件的邮箱

r2e new you@yourdomain.com

然后一个一个增加rss源(必须是rss的位置, 而不是网站的名称, 不然抓取不到)

r2e add http://feeds.feedburner.com/allthingsrss/hJBr

最后, 我们需要让r2e不发邮件跑一遍, 放弃当前时间点之前的数据

r2e run --no-send

现在配置完成了, 每次只要你想看新的内容, 就可以执行以下命令

r2e run

我设置了160个源, 运行比较慢. 我把它用crontab来作为后台程序跑了. 修改/etc/crontab, 添加上

1 * * * * halida /usr/bin/r2e run

我设置的是每个小时的第一分钟去抓取, 以我自己的用户名(halida)来跑.

结论

更多的内容和介绍, 在: http://www.allthingsrss.com/rss2email/getting-started-with-rss2email/

鉴于现在做这个服务的网站不多, 什么时候我搭建一个服务器来玩玩..

Ruby_on_rails初探

| Comments

image

好吧, 昨天看了一下ruby, 今天就要来看看ruby on rails了.

哲学

  • DRY: 不写重复的东西
  • 约定取代设置: rails假定了你要做的事情, 而不是你自己设置一切.
  • REST方式.

教程

这里是一篇 rails教程, 按照上面的指示做一遍, 就对rails的思路和哲学有了一定了解了, 这里就不再重复.

整体架构

image 如上图, rails采用MVC架构. 进来的http请求, 交由Dispatcher分发给(设置文件是app/routes.rb)对应的controller(app/controller下面), 然后controller把数据交给view(app/views)渲染返回.

特性

自动代码生成

rails3里面可以用命令直接生成大量代码

rails generate controller home index
rails generate scaffold Post name:string title:string content:text

运行之后生成了一堆文件. 节省了工作, 但是对于有洁癖的人来说, 会很不舒服.

快捷方式

rails提供了很多快捷方式以减少代码量, 比如对数据做验证:

1
2
3
4
5
class Post < ActiveRecord::Base
  validates :name,  :presence => true
  validates :title, :presence => true,
                    :length => { :minimum => 5 }
end

比如访问权限控制:

1
2
3
4
5
6
7
8
class PostsController < ApplicationController

  before_filter :authenticate, :except => [:index, :show]

  # GET /posts
  def index
    @posts = Post.all
  ...

这些看起来是ruby的哲学, 减少了代码量的同时, 把复杂度隐藏到framework里面了, 不好说是好事还是坏事.

结论

按照上面的教程走了一遍, 个人感觉:

  • 它注重快速开发, 用最少的代码来生成最多的功能.
  • ruby on rails采用命令来生成大量代码, 我个人非常不喜欢, 因为不够简洁. 但是对于快速开发, 这个方式节省了大量的编码工作.
  • 它假设了一条最好的方式来做开发, 并鼓励开发者走这条道路.
  • 个人觉得, 适合一次又一次地开发同类型的网站.

上面只是对rails的初探, 很不完全, 也不深入. 如果有机会开发过一个项目, 可能有更深刻的体会. 但是还有其他的很多事情在等着我… 这个就先放下吧.

Ruby初探

| Comments

image

python和ruby的区别

python经常被拿来和ruby做比较, 他们都是动态脚本语言, 在应用场景上面也非常相似. 我们听到的, 它们之间广为认知的区别是:

python ~ “There should be one – and preferably only one – obvious way to do

it."

ruby ~ “There Is More Than One Way To Do It.”

但是远远不止这些, 它们之间有无数的细节不同. 根据ruby官方网站上面给出的 针对python程序员的介绍 :

  • Strings are mutable. 字符串是可写的.
  • You can make constants (variables whose value you don’t intend to change). 可以设置常量.
  • There are some enforced case-conventions (ex. class names start with a capital letter, variables start with a lowercase letter). 强制名称大小写.
  • There’s only one kind of list container (an Array), and it’s mutable. 只有一个list容器
  • Double-quoted strings allow escape sequences (like t) and a special “expression substitution” syntax (which allows you to insert the results of Ruby expressions directly into other strings without having to “add ” + “strings ” + “together”). Single-quoted strings are like Python’s r”raw strings”. “”字符串可以内嵌语句
  • There are no “new style” and “old style” classes. Just one kind. 只有一种类.(相对python有新旧之分)
  • You never directly access attributes. With Ruby, it’s all method calls. 无法访问类的属性, 只能通过方法访问.
  • Parentheses for method calls are usually optional. 执行方法可以不用括号.
  • There’s public, private, and protected to enforce access, instead of Python’s _voluntary_ underscore __convention__. 可以限制类方法的访问范围了.
  • “mixin’s” are used instead of multiple inheritance. mixin取代了多重继承.
  • You can add or modify the methods of built-in classes. Both languages let you open up and modify classes at any point, but Python prevents modification of built-ins — Ruby does not. 可以修改系统内建类的方法.
  • You’ve got true and false instead of True and False (and nil instead of None). true/false/nil取代True/False/None
  • When tested for truth, only false and nil evaluate to a false value. Everything else is true (including 0, 0.0, “”, and []). 只有false/nil为假, 其他都为真.
  • It’s elsif instead of elif. elsif取代elif
  • It’s require instead of import. Otherwise though, usage is the same. require取代import.
  • The usual-style comments on the line(s) above things (instead of docstrings below them) are used for generating docs. 代码上面的注释是文档.
  • There are a number of shortcuts that, although give you more to remember, you quickly learn. They tend to make Ruby fun and very productive. 很多快捷方式增加产能.
  • There’s no way to unset a variable once set (like Python’s del statement). You can reset a variable to nil, allowing the old contents to be garbage collected, but the variable will remain in the symbol table as long as it is in scope. 变量是持久的, 不能被删除(除非自动垃圾收集掉)

上面只是一个总览, 没有给出实际的写ruby的感觉. 我们还是通过示例来看看ruby的特质.

ruby特质

下面的内容取自 the ruby programming language.

首先, ruby是面向对象的. 所有的值都是对象, 比如:

1
2
1.class   # => Fixnum
0.0.class # => Float

注意上面, 函数和方法(上面的class)可以不用带括号, 直接执行, 并且没有歧义. ruby是不能直接访问属性的, 所以不会混淆.

blocks 和 iterators 对python程序员看起来有点怪异, 但是看多了还是很好理解:

1
2
3.times {print "ruby"}  # 打印3遍 ruby
1.upto(9) {|x| print x} # 打印 123456789

times和upto是整型的方法, 他们返回一个迭代器, 然后这个迭代器就执行下面{}内的代码.

ruby也有list和dict对应的数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
a  = [1, 2, 3, 4] # 和python一样也有list
a.map do     # do end和{}等价
    |x| x*x
end

# :one是符号, 如果你知道lisp, 应该明白这个是什么, 
# 如果你不知道.. 我也不知道怎么说, 就是符号啦.
# ruby的hash table写法好像没有python简洁.   
d = {:one => 1, :two => 2, "3" => 3}
d[:one] # => 1
d.each do |key, value|
    print "#{value} : #{key}; " # ruby 里面的字符串可以嵌入语句
end

ruby的语法是面向表达式的, if之类的控制符也是表达式, 比如:

1
minimum = if x < y then x else y end

ruby的操作符是作为方法来实现的, 比如 + – * / [] 等, 都可以按照需要来定义.

取值和赋值是用不同的方法, 只是读取, 用 [], 如果要赋值, 就要用 []= 了.

这些个概念的区别, 需要好好体会.

方法定义:

1
2
3
def square(x) # 没有":"
    x*x       # 方法的返回值是最后一个表达式的值.
end

赋值:

1
2
3
x  = 12
x += 1
a, b = 1, 2 # 可以同时赋值多个变量

还有些值得一提的对象: 正则表达式对象(Regexp)和范围对象(Range):

1
2
1..10 === 5         # 5在1..10中间
/\d{5}/ === "12345" # 匹配5个数字

上面的1..10是Range, /d{5}/是Regexp.

然后是类了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Seq
    include Enumerate # 导入Enumerate module
    def initialize(from, to, by) # 初始化函数, 和__init__一样.
        @from, @to, @by = from, to, by # @表示的是类的属性.
    end

def each
    x = @from
    while x <= @to # while做循环
        yield x # 和python的yield一样.
        x += @by
    end
end

s = Seq.new(1, 10, 2)
s.each {|x| print x} #显示 "13579"

还有一些令人意外的东西:

ruby的字符串是可变的, 比如:

1
2
3
s = "hello"
s[1..2]= "mo"
s # => "hmolo"

ruby里面, 只有false和nil是假, 0和”“都是为真, 需要注意.

如何学习ruby

直接去 `ruby看官方文档` 吧. 当然, 作者写的书: the ruby programming language 是深入了解ruby的基础, 和K&R对C的重要性一样.

结论

花了一下午的时间熟悉ruby, 学习前, 感觉ruby会很繁杂, 以及会有”有了python干嘛学习ruby”的想法. 真正开始学了之后, 还是体会到一点ruby的精妙之处的. 个人感觉ruby离lisp比较近(当然, 只有lisp才有那么强大的宏). 等我再深入一点ruby, 再看看有什么意思吧. 恩, 还有ruby的神器: ruby on rails.

Http_介绍

| Comments

image

HTTP是什么就不说了, 大家都知道. 这篇文章对HTTP实现方式的相关内容做一个整理, 满足大家的窥私欲望.

用户如何利用HTTP

先不管HTTP下面是如何实现的, 我们看看上层: 对于用户而言, HTTP的使用很简单: 打开一个浏览器, 输入网址, 比如: http://www.example.com, 然后按回车, 浏览器就打开了一个界面. 整体工作逻辑就是

发出网址(URL) --> 服务器传回网站内容 --> 浏览器显示界面

我们理清接口(不用去管浏览器渲染的部分):

输入 ~ 用户给本地的一个程序URL信息

输出 ~ 服务器返回状态, 以及HTML内容

HTTP通讯过程

HTTP是如何实现上面的目标的呢? HTTP直接利用TCP连接, 并且通讯模式很简单, 客户端发出一个请求, 服务器给出一个响应. 并且这个通讯过程是纯文本的.

我们看一个实际的例子, 通过telnet来直接看看HTTP是如何通讯的:

首先连接目标服务器, 80端口是HTTP协议的默认端口.

halida@halida-desktop:~$ telnet tonycode.com 80
Trying 67.205.49.228...
Connected to tonycode.com.
Escape character is '^]'.

telnet连接上之后, 我们发出请求.

GET / HTTP/1.1
Host: tonycode.com

“GET”是HTTP请求的方法, ”/“是获取资源的目录, “HTTP/1.1”标示采用的是什么HTTP协议版本. “Host”行代表的是HTTP header, 请求附带的一些其他信息. cookie, 页面缓存等. 具体可见: `HTTP headers`

最后输入2行回车, 表示请求内容发送完毕.

下面是接收到的内容

HTTP/1.1 200 OK

200是状态码, 表示…就是上面的OK, 请求处理完成.

Date: Wed, 09 Feb 2011 01:06:45 GMT
Server: Apache
Last-Modified: Wed, 21 Apr 2010 15:49:54 GMT
ETag: "71de2eb-bce-484c1252b6c80"
Accept-Ranges: bytes
Content-Length: 3022
Vary: Accept-Encoding
Content-Type: text/html

然后就是返回的一串 `HTTP header`, 里面含有返回内容的信息等.

最后是正文了, 就是我们喜闻乐见的HTML文档了(太长就不显示出来了)

<!DOCTYPE html> ...

整体过程就是那么简单. 更多的细节在 `HTTP` wiki文档.

状态码

不是每次请求都是200 OK的, 这里面列出一些常见的状态码:

200 OK ~ 没什么好说的.

400 Bad Request ~ 请求有问题.

404 Not Found ~ 最常见的错误, 无法在服务器上找到对应的资源.

403 Forbidden ~ 服务器禁止访问此资源.

其他的见: status code wiki页面

连接状态

HTTP/0.9, HTTP/1.0都是请求/响应后立刻断开, HTTP/1.1里面可以同一个TCP连接使用多次, 以减小多次重复连接带来的资源消耗和延迟.

cookies

HTTP协议本身是无状态的, 一个请求一个响应, 就是那么简单. 但是很多时候我们需要记录状态, 比如用户登录等功能. 一般比较常用的是采用 cookie 的方式实现.

简单点说, 当客户端发出一个请求后, 服务器返回的HTTP header里面会带有一个

Set-Cookie: name=value; name2=value2

的段, 然后客户端会把这个字符段缓存下来, 下次请求的时候, 就会在自己的header里面带上

Cookie: name=value; name2=value2

就是这么简单. 其他一些技术细节, 比如cookie的作用时间和范围, 见 cookie wiki介绍.

HTTPS

HTTP本身是明文的, 非常不安全. 为了解决这方面的问题, 就有了HTTPS.

简单地说, HTTPS和HTTP的区别在于, 不是使用TCP作为连接方式, 而是采用SSL的方式来做连接, 上层应用层是没有多少变化的, 传输的时候数据做了加密, 以及连接到服务器的时候, 会有一套验证机制保证服务器是真正的服务器.

具体还是见 `HTTPS` 的wiki界面.

结论

HTTP协议很简单优雅, 或许是这样的简单优雅才承载起来一个庞大的web世界. 对它的掌握是web程序员必备的基础, 之后才能更好地理解在此之上的很多精妙应用.

黑客与画家

| Comments

image

很久以前就耳闻 hackers and painters 这本书, 终于在今年过年期间, 抽空看完了. 这本书有点像是杂文集, 里面的内容遥相呼应, 但又独立成章.

里面的核心思想: 黑客更像是艺术家, 而不是工程师或者科学家. 编程工具对于黑客而言, 像是画笔对于画家, 掌握了工具, 不代表能够创作出好的作品出来. 这篇文章可以见 作者博客 (中文翻译) 既然作者已经介绍得很清楚了, 我也不多说了. 我现在的问题是, 作为程序员, 技术能够花时间学到, 但是创造能力很难, 是否有提升的方法?

这本书没有给我带来太多的新知, 可能跟我已经看过很多类似的文章有关吧. 有人已经 完成翻译工作了, 但是好像现在还没有上市, 如果你真的像我一样时间很多, 或者英语阅读水平很好, 可以google一下, 有破解的英文版.