Mengdong的技术博客

学习,记录,分享

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  53 随笔 :: 0 文章 :: 64 评论 :: 0 引用

公告

2012年5月15日 #

vim+\LaTeX+TtH+Python+MetaWeblog API写博攻略

vim+LATEX+TtH+Python+MetaWeblog API写博攻略

mdyang

 

Chapter 1
准备工作

首先需要安装LATEX环境,本文使用Ubuntu + tex live,编辑器则使用vim。如果熟悉其他编辑器如emacs也可。

 

有了LATEX环境后,即可使用latexpdflatex等命令编译LATEX源代码,生成对应的DVI或PDF文件。由于我们要写博文,需要HTML格式的文档,因此需要将LATEX转换为HTML的工具。在此推荐TtH,一个将LATEX编译为HTML的工具。

 

1.1  TtH: TEXto HTML的转换工具

 

TtH最简单的用法为:

 
tth input.tex

 

执行该命令将会将input.tex编译为input.html,注意TtH忽略CJK宏包,因此中文LATEX文档里的\usepackage{CJK(utf8)}\begin{CJK}\end{CJK}等可以省略。虽然忽略了CJK宏包,但TtH仍然可以正确处理中文,由于TtH生成的HTML文件是UTF-8编码的,所以只需保证输入的LATEX源代码也是UTF-8编码的即可。当使用浏览器打开生成的.html文件时可能会发现中文都是乱码,这是由于TtH生成的HTML文件中缺少<head>段中的一个<meta>标签:

 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 

 

这一行告诉浏览器页面编码是UTF-8,缺少这一行浏览器可能会选择错误的编码集显示页面,例如在中文版Windows系统下可能使用GBK编码显示该页面,造成中文乱码。如果在浏览器的查看设置里将页面编码手动设置为UTF-8,就会发现里面的中文都能够正确显示。所以这只是一个小问题,只需在HTML文件中插入上述<meta>标签即可。

 

1.2  pyblog: MetaWeblog API的Python实现

 

MetaWeblog是RFC的一套规范,MetaWeblog API是一套基于XML-RPC实现的远程调用API,可以使用这些API进行博客操作,包括发布日志、修改日志、分类管理等。主流的编程语言都有XML-RPC的程序库。在Python中这个库是xmlrpclib。不过在自己实现基于Python的MetaWeblog API之前本着避免重复发明车轮的原则去Google Code上搜索了一下,果然发现了一个MetaWeblog API的Python库:pyblog。这个库封装了MetaWeblog API的一些常用函数,并且还支持Wordpress API(MetaWeblog API的超集)。美中不足的是这个库似乎有一些错误,在我的Windows Server 2008 R2 + Python 2.7.2 AMD64上报错。经过研究发现第91行的代码有错误:

 
r = getattr(self.server, methodname)(args)

 

应该是:

 
r = getattr(self.server, methodname)(*args)

 

另外一个对我个人来说美中不足的地方是pyblog库没有提供对HTTP代理服务器的支持,所以我参照这篇日志中介绍的为xmlrpc添加HTTP代理服务器支持的方法,对pyblog的代码进行了一点改进。需要注意的是这篇日志中实现的UrllibTransport类的构造函数里缺了这么一句:

 
self._use_datetime = True

 

我加了这么一句是因为原日志中UrllibTransport类的代码在应用到pyblog中时报了一个错,说UrllibTransport类没有_use_datetime这个属性。我根据命名猜测这个属性应该是个布尔型,所以添加了上面那一句。添加以后代码工作正确。

 

至此两个最重要的问题已经解决了:

 
  • LATEX代码转换为HTML(使用TtH)
     
  • 通过MetaWeblog API将HTML代码的日志发布到博客(使用pyblog)
     
 

接下来要做的是将这两个步骤连接起来。考虑pyblog是用Python写的,因此这里使用Python作为胶水语言连接这两步。

 

Chapter 2
pyposter: 连接LATEX与MetaWeblog API的Python脚本

 

2.1  设计目标

 

相比于WYSIWYG编辑器,使用LATEX写博最大的不便在于无法做到所见即所得。对于写好的博文,如果想要检查完稿,需要进行编译,并使用浏览器查看才行。所以使用LaTeX进行博文撰写主要分为以下几个阶段:

 
  1. 编写LATEX源码
     
  2. 编译LATEX源码为HTML并在浏览器中预览,如无问题进入下一步,否则返回1.修改
     
  3. 将写好的博文发送至博客
     
 

基于以上考虑,我为pyposter设计了两个功能:buildpost。其中buildLATEX源码编译为HTML,并启动一个HTTP服务器方便预览,post使用MetaWeblog API将HTML源码发布至博客。下面分两个小节分别讲述功能细节。

 

2.2  build: LATEX源码编译、博文预览

 

pyposter是一个Python脚本,其文件名就叫pyposter。该脚本具备buildpost两项功能。本节介绍build功能。

 

对于LATEX源码编译,只需调用TtH即可。Python中可以通过os.system()执行命令。

 

编译完毕后需要预览,首先需要在TtH生成的HTML中加入那个缺失的<meta>标签,声明文件的编码,这样无需手动修改浏览器的显示编码页面就可以正常显示。这可以通过简单的文本处理实现,可参见pyposter中的build()实现。

 

至于预览,Python内置了一个简单的HTTP服务器SimpleHTTPServer,可以通过如下命令启动:

 
python -m SimpleHTTPServer

 

启动后的HTTP服务器在8000端口侦听(也可以设置为其他端口),HTTP地址的根目录对应执行该命令的当前目录,如果当前目录下有index.html则默认主页为该文件,否则会显示文件列表。

 

编译、预览都搞定了以后,就需要对pyposter进行一些处理,使其在系统的任意位置都可以使用。通过以下三个设置,可以在任意位置执行pyposter Python脚本:

 
  • pyposter的首行添加#!/usr/bin/python(告诉系统该文件由Python执行)
     
  • 为文件pyposter添加执行权限(chmod +x pyposter
     
  • 将pyposter所在的路径加入环境变量$PATH
     
 

设置完毕后,可使用以下命令编译、预览使用LATEX编写的博文:

 
pyposter build

 

以上命令使用TtH编译当前目录下的main.tex,生成main.html,逐行扫描main.html,为其添加如下编码信息:

 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 

 

经过修改的HTML代码被输出至index.html,然后一个HTTP服务器在当前目录下启动,在浏览器中访问http://HOST:8000即可预览(注意:将HOST替换为具体的主机名或IP)。预览完毕后按CTRL+C即可结束pyposter build进程。如果需要修改则返回vim进行修改,修改完毕后再编译、预览,如果文章已完成则可以进入下一步。

 

2.3  post: 发布博文

 

发布博文需要解决的一个小问题是调用MetaWeblog API的new_post方法时需要单独指定博文标题。因此需要HTML文件中提取文章标题。只需将<title>标签中的文字提取出来即可,简单的文本处理,在此不再详述,可参见pyposterpost()函数。

 

发布操作的实现则简单得多,直接调用pyblog中封装好的MetaWeblog API即可。我对pyblog的代码进行了一些小修改,使其能够使用HTTP代理服务器。

 

执行以下命令可以将当前目录下的index.html发布为博文:

 
pyposter post

 

Chapter 3
小结

 

我已经把pyposter放到Google Code上:pyposter at Google Code。通过修改配置文件conf.py可使pyposter应用于其他博客。

 

pyposter现在已经可以做到:

 
  • 一条命令编译LATEX源码并预览HTML(通过pyposter build
     
  • 一条命令发布HTML博文至博客(通过pyposter post
     
 

pyposter已经具有了基本的功能。但仍然有很多功能需要完善:

 
  • 虽然已经可以正确获取所有类别(通过pyblog的MetaWeblog.get_categories()),但仍然无法为博文添加类别标签
     
  • 无法管理类别标签(添加、删除类别标签)
     
  • 暂时不支持设置博文的entryName
     
  • 未考虑博文包含图片时的情况
     
  • 暂时不支持编辑博文(更改已发布博文的内容)
     
 

这些都是留待以后完善的功能。并且限于目前的应用情景,pyposter还只能用于博客园的MetaWeblog API,其他的博客系统暂时还没有进行验证。除MetaWeblog API外,pyblog中还实现了Wordpress API,其功能也有待验证。

 

欢迎有兴趣试用的各位朋友指正。

 




File translated from TEX by TTH, version 4.01.
On 15 May 2012, 09:32.

posted @ 2012-05-15 11:25 mdyang 阅读(19) 评论(0) 编辑

2012年5月7日 #

这个读书笔记目录系列尝试以PDF文件的形式提供,也是我的LaTeX初学成果。

《Linux Kernel Development》读书笔记1

第1章:Linux内核概览
第2章:内核概览

posted @ 2012-05-07 18:03 mdyang 阅读(624) 评论(0) 编辑

2012年5月5日 #

最近写博客的过程中已经越来越感觉到WYSIWYG编辑器已经难以满足我的书写欲望,随着将我的毕业论文迁移至LaTeX接近完成,我决定接下来的读书笔记也用LaTeX写,长期目标分为以下三个阶段:

  1. .tex代码->pdfLaTeX->PDF文档->上传网盘->日志+下载链接的方式发布
  2. .tex代码->TTH(TeX to HTML)->手工拷贝至WYSIWYG编辑器->日志
  3. .tex代码->TTH(TeX to HTML)->MetaWeblog API->日志

等到达第3阶段的时候,我幸福的博客生活就算是真正开始了,因为我可以直接从.tex代码发布博客了。

我现在使用Ubuntu 10.10 + texlive 2009 + vim进行写作,首先使用apt-get安装如下包:

texlive-full latex-cjk-all

然后就可以按照lnotes[1]中所述的方法创建中文文档了,我使用pdfLaTeX,即执行

pdflatex LaTeX文件名

执行后.tex源代码被编译为同名.pdf文档。

但是有一个问题:latex-cjk自带的宋体实在不好看,在某些缩放比例下看起来有的字粗有的字细,所以我希望把Windows里的宋体移过来。

找了好多资料都不好使,最后找到[2]中的方法,总算是搞定了。

[2]中的方法操作完毕后,再执行fc-cache -fv刷新一下字体缓存文件,就可以正确编译使用了新字体的.tex文件了。

2012年5月19更新:也可以使用XeTeX,可以比较好的解决中文字体问题,不需要额外生成LaTeX字体库,直接使用计算机系统里的字体。

参考资料:

  1. huangxg, lnotes. 水木清华. http://www.dralpha.com/zh/tech/lnotes.pdf
  2. Vani有约会, latex-CJK安装中文字体的脚本. 百度贴吧
posted @ 2012-05-05 22:17 mdyang 阅读(109) 评论(0) 编辑

第11章:引用

  • 引用一律声明为标量类型(即$开头的命名变量),使用\运算符取引用
    • 对引用变量的修改等同于对引用指向实际数据的修改
    • 取变量引用:my $scalar_r = \$scalar;
    • 取列表的引用:my $array_r = \@array;
    • 取哈希的引用:my $hash_r = \%hash; 
  • 通过引用解决列表无法嵌套的问题:

 

my @array1 = (10, 20, 30, 40, 50);
my @array2 = ( 1, 2, \@array1, 3, 4);

 

  • 因为\@array1本质上只是一个标量,所以列表不会被扁平化,依旧保留了嵌套层次
  • 对匿名列表的引用:将列表的()替换为[]:my $array_r = [1, 2, 3, 4, 5];
  • 对匿名哈希的引用:将哈希的()替换为{}:my $hash_r = { apple => "pomme", pear => "poire" };
  • 对引用变量解引用通过{$var_r}实现
    • 列表

 

my @array = (1, 2, 3, 4, 5);
my $array_r = \@array;
my @array2 = @{$array_r};  #拷贝了数组

 

    • 哈希与列表类似
  • 对于数组引用,可以将${$ref}简记为$ref->,例如可以将${$ref}[2]简记为$ref->[2],而将${${ref}[2]}[1]简记为$ref->[2]->[1],并进一步简记为$ref->[2][1]
  • 使用undef销毁一个引用:undef $ref; perl对于引用指向的数据维护一个引用计数,当计数减到0时引用指向的数据被销毁,内存空间被释放
  • 使用引用使得表示复杂的数据结构成为可能。这些数据结构包括矩阵(多维数组)、链表、树、图等。
  • 一些思考:C/C++的引用主要为了传地址。与C/C++中的指针、引用不同的是,perl引用除了传递地址外,还是perl中将标量(scalar)、列表(list)、哈希(hash)进行一般化(或者说统一)表示的机制,使用引用后,可以将标量、列表、哈希均表示为标量(因为地址本质上是一个无符号整型数,这一点与C中的void*有些类似)。通过引用,就可以解决perl中无法存储带有嵌套层次的列表、无法表示复杂数据结构的问题。

第12章:模块 

  • 模块是一个perl源代码文件,与普通的.pl源代码文件相比,模块有如下两个不同点:
    • 扩展名不是pl,而是pm(这一条并不是强制条件)
    • 最后有一句1;(或是return true;或是任何返回true值的语句)强制要求
  • do用于在perl代码中的任意位置嵌入一个.pl脚本或是.pm模块,语法是do “filename”;perl将会在@INC中的路径下寻找filename
    • 如果在main.pl中执行do ‘inc.pl’;需要注意的是inc.pl中的代码不能访问main.pl中定义的lexical变量
  • require用于在perl代码中的任意位置嵌入一个模块,语法是require “filename”;或require modulename;当使用require modulename;时,modulename形如module::submodule::subsubmodule,代表文件./module/submodule/subsubmodule.pm
    • 与do不同,require只支持嵌入模块,因此require的文件必须以返回true语句结束
    • 对于一个文件只嵌入一次,即使写了多条对同一文件的require语句
  • use用于在perl代码中的任一位置嵌入一个模块,语法是use modulename;modulename同require中的modulename
    • 与require不同,use在编译前执行,也就是说,即使use中的模块写在代码中的最后一句,也会第一个执行

 

- do require use
支持 源码 模块 模块 模块
语法 do ‘filename’; require ‘filename’;
require modulename;
use modulename;
处理次数 嵌入几次,处理几次 仅一次 仅一次
文件不存在 跳过,不报错 报错 报错
执行时间 运行时 运行时 编译时(最先处理)

 

  • @INC变量也是一个普通perl列表,可以更改,因此可以自行向其中添加路径(使用unshift或者push)
  • 模块文件的开头应该声明package packagename;packagename形如package::subpackage::subsubpackage,对于package::subpackage::subsubpackage中的函数sub1,调用方法是package::subpackage::subsubpackage::sub1
    • 注意package声明的是模块名,而require和use使用的模块名实际上是路径名,和模块名并不一样,比如说有一个模块为./m1/test1.pm,其中的package声明却是package m1::test2;该包内包含一个函数sub1,则在main.pl中应该use/require m1::test1;而在调用时则应该写m1::test2::sub1()
    • 当然,为了清晰、易管理,模块名和模块文件名、路径应该保持一致
  • 可以使用Exporter类简化包内的函数调用写法。没有使用Exporter时,必须写形如package::subpackage::subsubpackage::sub1的调用,过于啰嗦,而在写包时继承Exporter即可:

 

package Acme::Webserver::LoggerExporter;
# Acme/Webserver/LoggerExporter.pm
use strict;
use warnings;
# become an exporter and export the functions
use Exporter;
use base 'Exporter';
our @EXPORT = qw(open_log close_log write_log log_level);
则调用open_log时就可以将全写调用:
Acme::Webserver::LoggerExporter::open_log()
改为简写调用:
open_log()

 

  • 也可以在use模块时声明要导入的模块:
use Data::Dumper qw(Dumper);
# 可以直接调用Dumper()

 几个常用的包

  • Data::Dumper是将变量序列化为perl语法的字符串的包,序列化列表和哈希时非常方便
  • File::Find是一个遍历文件夹,对其中每一个文件进行处理的函数,用法是File::Find::find(\&wanted, “/home/simon/”);
    • 首个参数wanted是一个回调函数,对每个文件应用。第二个参数是执行文件夹
    • 每次执行回调时当前目录被切换为当前文件所在的目录
    • 当前目录的相对路径为$File::Find::dir
    • $_为当前文件的文件名
    • $File::Find::name为当前文件的全名(包括目录)
  • Getopt::Std和Getopt::Long是两个处理命令行参数的包,可以将形如-al的简写命令行参数解析为a和l两个参数,也可以将-a arg1 -l arg2这样的命令行参数解析为哈希映射
  • File::Spec是一个处理路径字符串的包,包括路径字符串简化、路径叠加、路径解析等
  • Benchmark是一个性能测试包,可将某一代码块重复执行若干次,测得性能参数
  • Win32是一个封装了一些Win32 API的包,包括Win32::Sound、Win32::TieRegistry等

第13章:面向对象的Perl

  • perl中并没有真正的“类”,所谓的类,其实是一个包
  • 要定义一个类,声明一个package即可:package Person;
  • 类的构造函数固定取名为new,即sub new {...}
  • 初始化类对象通过$obj = new Person();或者$obj = Person->new();
  • 构造函数sub new要点:
    • 参数表的第一个参数(@_[0])是类名,第二个开始为调用构造函数时传入的参数
    • 通过传入哈希实现类似成员变量的功能
    • 生成对象引用后,必须使用bless()函数对引用的类型进行转换
    • 最后一句必须返回生成的对象引用

 

#类定义
package Person;

sub new { #此时_@为(‘Person’, ‘name’, ‘Carl’, ‘gender’, ‘male’)
 $classname = shift; #获得类名,此时$classname为’Person’, _@为(‘name’, ‘Carl’, ‘gender’, ‘male’)
 my $self = {@_}; #将传入参数转化为哈希,$self为(‘name’=>’Carl’, ‘gender’=>’male’)
 bless $self, $classname #将引用$self转化为$classname类型
 return $self; #返回的Person对象本身是一个哈希,含有所有成员变量
}

#类使用
$person = Person->new(‘name’=>’Carl’, ‘gender’=>’male’);

 

  • Package内定义的变量为类变量,即静态成员变量(static member variable),不能直接访问,必须定义访问器(accessor, 即get/set函数)
  • 成员函数要点:
    • 名字以下划线_开头的成员函数为私有的
    • 函数的第一个参数(即@_[0])为对象引用,第二个参数开始为函数参数

 

#类定义
package Person;

sub new {...} #省略
sub _init {...} #私有函数
sub name {
 my $self = shift; #取调用对象引用
 my $name = shift; #取第二个参数
 $self->{name} = $name if defined $name; #如果传入名字,则设置名字为传入值
 return $self->{name}; #返回名字值
}

#类使用
$person = Person->new(‘name’=>’Carl’, ‘gender’=>’male’);
$person->name(‘Caesar’); #将名字设置为’Caesar’
print $person->name(), “\n”;  #打印名字,将打印’Caesar’

 

  • 对象的销毁参照11章中引用指向数据的销毁方法

后记

Perl给我留下深刻印象的地方:

  • 简捷易用的文本I/O、正则表达式使Perl成为文本处理的利器
  • 提供众多UNIX API,加上脚本语言的灵活性,Perl适合进行UNIX系统管理

个人感觉Perl中的两个难点,也是Perl的败笔:

  • 引用(Reference)
    • 列表自动一维化的机制莫名其妙。Perl中标量、列表和哈希拥有各自不同的词法标识($、@、%,列表、哈希内容均使用(),列表取值使用[],哈希使用{}),将其引用化后解引用又有一套各自不同的词法,很容易弄晕
  • 面向对象(OO)
    • Perl中的OO机制有点半残,单单是构造函数中必写的几行:
my $classname = shift;
my $self = {@_};
bless $self, $classname;
return $self;
    • 以及函数中第一句必写的my $self = shift;就让人十分讨厌,重复性劳动。如果这真的是一门OO语言,这些工作应该由编译器完成。
    • 根据Wikipedia上Perl页面的介绍,OO是Perl 5中加入的新特性,这说明Perl最早并没有被设计为一门OO程序设计语言,所以Perl 5中的OO特性可以看成是在过程式语言中进行的一种升级。比如每个函数第一句就必有的my $self = shift;就与C++中的this指针神似,只不过C++作为一种新语言革命得比较彻底,this指针是由编译器自动提供的,不必手工获取。与C++相比,Perl里的OO更像是用C语言实现的OO,说到这里,有空可以去看看《Object-oriented Programming with ANSI-C》,这本书讲了用C语言实现OO特性的各个技术细节,“通过这本书你可以明白C++, Java, Python 等面向对象语言中的类、继承、实例、连接、方法、对象、多态... 都是如何实现的. 能让你通过C来写出优美并可以重用的代码.”(以上文字来自豆瓣网友Border
posted @ 2012-05-05 16:57 mdyang 阅读(29) 评论(0) 编辑

2012年5月4日 #

第6章:子过程/函数

  • 声明:subfunction_name;
  • 定义:subfunction_name {...}
  • 函数调用同C:
    • example_subroutine();或example_subroutine;
    • example_subroutine('Perl is', 'my favorite', $language);或example_subroutine 'Perl is', 'my favorite', $language;
    • 调用时需保证之前已有声明/定义
  • 返回值:函数的最后一行代码可以写表达式作为返回值,例如写$total;也可以使用return语句在函数体中的任意位置返回返回值
  • 函数内部通过@_变量访问传入参数:
  • Perl中按引用传参,改变输入参数将影响函数外的变量
  • 实现默认参数值的小技巧:
sub log_warning {
 my $message = shift || "Something's wrong";
 my $time = shift || localtime; # Default to now.
 print "[$time] $message\n";
}
  •  实现参数命名的小技巧:
    • 调用:logon(username => $name, password => $pass, host => $hostname);
    • 定义: 
sub logon {
 die "Parameters to logon should be even" if @_ % 2;
 my %args = @_;
 print "Logging on to host $args{hostname}\n";
 ...
}

第7章:正则表达式

  • 正则表达式以双斜线对//包裹,//中可以使用变量,变量将被代换为对应的值
  • 正则式匹配:str =~ /re/若str匹配/re/成功为true,反之false;!~则与=~相反
  • /re/等价于$_ =~ /re/
  • 进行匹配后,可以使用$1,$2,$3...获得字符串中匹配成功的子串
    • 因为不知道有多少个匹配成功的子串,所以需要用defined算符一一检验$1, $2, $3是否已定义,stupid
  • //正则式中以下元字符(metacharacter)需要使用\转义:. * ? + [ ( ) { ^ $ | \ /
  • \Q可用于关闭元字符,\E用于结束\Q。\Q...\E之间的部分可自由使用上一要点中提到的元字符
  • 锚点^表示从字符串起始处匹配,而$则表示匹配至字符串末尾结束
  • []可定义字符集,例如[abc]匹配a,b或c,[0-9]匹配0,1,2,3,4,5,6,7,8,9任一。[]中使用^表达反义,即[^eo]可匹配除e,o外任意字符
  • 几个等价:\d等价于[0-9],\w等价于[0-9A-Za-z_],\s等价于[ \t\n\r\f],\D等价于[^0-9],\W等价于[^0-9A-Za-z_],\S等价于[^ \t\n\r\f],.等价于任意字符(换行符除外)
  • |可用于表示或,例如yes|maybe可匹配yes或maybe,ye(s|t)匹配yes或yet
  • ?意味?前面的记号出现0或1次,例如(word )?is可匹配word is和is
  • +则为1次及1次以上,*为任意次(包含0次)
    • /bea?t/匹配beat和bet
    • /bea+t/匹配beat, beaat, beaaat...
    • /bea*t/匹配bet, beat, beaat, beaaat...
  • {}则可以定义具体的出现次数,例如\s{2,3}可匹配2个空格,也可匹配3个空格。{x}代表x次,{x,}则代表x次及x次以上
  • 正则式匹配器的工作原则:
    • 一旦匹配无法继续(下一个字符无法满足正则式定义),立即停止匹配
    • 一旦匹配成功,马上结束匹配
    • 遇+*?三个字符时取最长匹配,即匹配至无法匹配时再匹配之后的正则式与字符串
    • 最近分支原则:若存在分支匹配(例如[a-z]或ye(s|t)这种情况)则从前向后依次尝试,若尝试失败则取下一个,直到成功匹配或所有情况匹配失败
  • 使用正则式进行替换:str =~ s/find/replace/;可用于将str中满足find模式的首个子串替换为replace,若不指定str,执行s/find/replace/;为对$_操作,在末尾加g修饰符可替换所有子串
$_ = "Awake! Awake! Fear, Fire, Foes! Awake! Fire, Foes! Awake!";
s/Foes/Flee/;
print $_,"\n";
输出:
Awake! Awake! Fear, Fire, Flee! Awake! Fire, Foes! Awake!

 

$_ = "there are two major products that come out of Berkeley: LSD and UNIX";
s/(\w+)\s+(\w+)/$2 $1/g;
print $_, "?\n";
输出:
are there major two that products out come Berkeley of: and LSD UNIX?
  • 类似q//和qq//,//和s///也可以使用别的分隔符,当在匹配(//)中使用其他分隔符时,需要使用m作为前缀,例如m/^\s*[A-Z]/;m#^\s*[A-Z]#;m{^\s*[A-Z]};等,而s/old text/new text/g;则可以写为s{old text}{new text}g;也可以出于清晰写为:

s{old text}
{new text}g;

再如s/\/usr\/local\/share\//\/usr\/share\//g;可写为s#/usr/local/share/#/usr/share/#g;

  • 修饰符
    • /m将字符串作为多行字符串处理,在这种情况下^$不再分别匹配单词首尾,而是匹配行首行尾
    • /s将字符串作为单行字符串处理,此时.匹配包括换行符在内的所有字符
    • /g:匹配时若有多个可匹配子串则全部匹配;替换时则替换所有可匹配子串,使用此修饰符时可使用\G锚点匹配最后一个可匹配子串的最后一个字符位置
    • /x允许以多行方式书写正则式,且可以添加注释
  • split(re, str)将str按照re分为多个子串,返回包含这些子串的列表。不指定str则默认对$_操作。例如split /:/, “kake:x:10018:10020::/home/kake:/bin/bash”可得(“kake”, “x”, “10018”, “10020”, “”, “/home/kake”, “/bin/bash”)
  • join(str, list)可用str将list中各个元素连接为一个字符串,并返回这个字符串,例如join “#”, (“kake”, “x”, “10018”, “10020”, “”, “/home/kake”, “/bin/bash”)可得“kake:x:10018:10020::/home/kake:/bin/bash”

第8章:文件与数据

  • 打开文件:open(filehandle, mode, filename)例如open(FH, '<', 'input.txt')
    • 打开成功时返回true,反之false
    • 也可以写作open(FH, '< input.txt')
  • 访问模式:>写  <读  >>追加
  • close(filehandle)用于关闭文件句柄,例如close(FH);
  • 标量读入:my $line = <FH>,读入一行
  • 列表读入:my @list = <FH>,读入所有行,每行为一个列表元素
  • 特殊文件句柄:<>(称为“钻石运算符”)
    • 当未在命令行参数中指定输入文件时,为<STDIN>
    • 否则为指定的文件句柄。可指定多个文件,按指定顺序逐个打开、逐行读取
  • @ARGV为存储命令行参数的字符串数组,例如以perl argv1.pl king crimson rocks运行时@ARGV为(‘king’, ‘crimson’, ‘rocks’)
  • <>本质上就是用@ARGV实现的。$ARGV为<>当前文件句柄指向文件的文件名
  • print FH list可以向FH指向的文件中输出list
  • $|变量设置是否使用OS的输出缓冲区,默认为0(使用),设为1后不使用
  • 管道:将上一个程序的STDOUT输出接入:open(FH, '-|', command);例如open(FH, '-|', 'perl sort2.pl gettysburg.txt');
  • 管道:将当前程序的STDOUT输出接入下个程序的STDIN:open(SORT, '|-', command);例如open(SORT, '|-', 'perl sort2.pl');
  • 管道:可使用IPC::Open2建立双向管道(未详述)
  • lc(str)将字符串str中字母转换为小写后输出,uc(str)则转换为大写
  • 类似shell的文件测试:(-operator $file),operator包括:
    • e $file存在时为true
    • f $file为文件(不是目录)时为true
    • d $file为目录时为true
    • z $file大小为0时为true
    • s $file大小不为0时为true
    • r $file可读时为true
    • w $file可写时为true
    • x $file可执行时为true
    • o $file为当前用户拥有时为true

第9章:字符串处理

  • length(str)返回str的长度
  • index(str, substr)返回str中substr第一次出现时的下标,substr不存在时返回-1
    • index(str, substr, mindex)指定从mindex开始查找
  • rindex(str, substr)返回str中substr最后一次出现时的下标,不存在时返回-1
    • rindex(str, substr, mindex)指定从mindex开始查找
  • substr(string, starting_index, length)返回string中从starting_index开始取length长度的子串
  • tr///用于字符替换,例如tr/old/new/将会建立如下字符替换规则:o->n, l->e, d->w,例如$string = ‘2011064’,而执行$string =~ tr/0123456789/abcdefghij/;或$string =~ tr/0-9/a-j/;后,$string变为‘cabbage’
    • d修饰符用于删除字符,例如my $vowels = $string =~ tr/aeiou//;并不能删除$string中的元音字母,而my $vowels = $string =~ tr/aeiou//d;就可以。再例如$string =~ tr/ //d;可删除$string中的所有空格

第10章:OS交互

 

  • %ENV保存了所有环境变量(改变%ENV并不能真正改变系统环境变量设置),例如$ENV{HOME},$ENV{PATH},$ENV{USER}等
  • 文件通配符:glob(pattern)函数用以返回下一个满足pattern的文件名,例如glob(‘*.pl’),等价于<*.pl>,表示所有扩展名为pl的文件。
while (glob('*.dat')) {
 print "found a data file: $_\n";
}
  • 可以使用opendir打开一个目录,通过readdir函数读取其中包含的文件,closedir关闭:
opendir DH, "." or die "Couldn't open the current directory: $!";
while ($_ = readdir(DH)) { … }
closedir DH;
  • 以下函数与UNIX API相同或类似,可参照APUE(《UNIX环境高级编程》)
      • chdir(directory)
      • unlink(list_of_files) 可unlink多个文件
      • rename(old_file_name, new_file_name)
      • link(file_to_link_to, link_name)
      • symlink(file_to_link_to, sym_link_name)
      • readlink(sym_link_name)
      • mkdir(directory_name, mode)
      • rmdir(directory_name)
      • chmod(file_or_directory_name, mode)
      • system(command)
  • system()函数将执行命令的输出打印至控制台(STDOUT),返回进程的执行结果(个人推断:main函数的返回值)。而使用`command`则可将输出捕获,例如:
    • $output = `$command`;将$command执行的输出保存至字符串$output,包括换行符
    • @output = `$command`;将$command执行的输出保存至列表@output,每行一个元素,包括换行符
posted @ 2012-05-04 16:46 mdyang 阅读(24) 评论(0) 编辑

仅列出标题  下一页