├── .gitignore ├── Beginning Perl for Bioinformatics (A4).pdf ├── Beginning Perl for Bioinformatics (A4).tex ├── Chapters ├── chapter1.tex ├── chapter10.tex ├── chapter11.tex ├── chapter12.tex ├── chapter13.tex ├── chapter2.tex ├── chapter3.tex ├── chapter4.tex ├── chapter5.tex ├── chapter6.tex ├── chapter7.tex ├── chapter8.tex ├── chapter9.tex ├── chapter_aa.tex ├── chapter_ab.tex ├── chapter_colophon.tex ├── chapter_perface.tex ├── cover.tex ├── cover_en.tex ├── cover_zh.tex └── header_zh.tex ├── Fonts ├── SourceCodePro-It.otf ├── SourceCodePro-Light.otf ├── sarasa-gothic-sc-bold.ttf ├── sarasa-gothic-sc-bolditalic.ttf ├── sarasa-gothic-sc-italic.ttf ├── sarasa-gothic-sc-regular.ttf └── sarasa-mono-sc-regular.ttf ├── Frontmatter.jpg ├── README.md ├── figures ├── figure1_1.png ├── figure4_1.png ├── figure4_2.png ├── figure8_1.png ├── figureab1.png ├── figureab2.png ├── note.png └── warning.png └── scripts ├── example10-1.pl ├── example10-2.pl ├── example10-3.pl ├── example10-4.pl ├── example10-5.pl ├── example10-6.pl ├── example10-7.pl ├── example10-8.pl ├── example11-1.pl ├── example11-2.pl ├── example11-3.pl ├── example11-4.pl ├── example11-5.pl ├── example11-6.pl ├── example11-7.pl ├── example12-1.pl ├── example12-2.pl ├── example12-3.pl ├── example12-4.pl ├── example4-1.pl ├── example4-2.pl ├── example4-3.pl ├── example4-4.pl ├── example4-5.pl ├── example4-6.pl ├── example4-7.pl ├── example4-8.pl ├── example5-1.pl ├── example5-2.pl ├── example5-3.pl ├── example5-4.pl ├── example5-5.pl ├── example5-6.pl ├── example5-7.pl ├── example6-1.pl ├── example6-2.pl ├── example6-3.pl ├── example6-4.pl ├── example7-1.pl ├── example7-2.pl ├── example7-3.pl ├── example7-4.pl ├── example8-1.pl ├── example8-2.pl ├── example8-3.pl ├── example8-4.pl ├── example9-1.pl ├── example9-2.pl └── example9-3.pl /.gitignore: -------------------------------------------------------------------------------- 1 | ## Core latex/pdflatex auxiliary files: 2 | *.aux 3 | *.lof 4 | *.log 5 | *.lot 6 | *.fls 7 | *.out 8 | *.toc 9 | *.fmt 10 | *.fot 11 | *.cb 12 | *.cb2 13 | 14 | ## Intermediate documents: 15 | *.dvi 16 | *-converted-to.* 17 | # these rules might exclude image files for figures etc. 18 | # *.ps 19 | # *.eps 20 | # *.pdf 21 | 22 | ## Bibliography auxiliary files (bibtex/biblatex/biber): 23 | *.bbl 24 | *.bcf 25 | *.blg 26 | *-blx.aux 27 | *-blx.bib 28 | *.brf 29 | *.run.xml 30 | 31 | ## Build tool auxiliary files: 32 | *.fdb_latexmk 33 | *.synctex 34 | *.synctex.gz 35 | *.synctex.gz(busy) 36 | *.pdfsync 37 | 38 | ## Auxiliary and intermediate files from other packages: 39 | # algorithms 40 | *.alg 41 | *.loa 42 | 43 | # achemso 44 | acs-*.bib 45 | 46 | # amsthm 47 | *.thm 48 | 49 | # beamer 50 | *.nav 51 | *.snm 52 | *.vrb 53 | 54 | # cprotect 55 | *.cpt 56 | 57 | # fixme 58 | *.lox 59 | 60 | #(r)(e)ledmac/(r)(e)ledpar 61 | *.end 62 | *.?end 63 | *.[1-9] 64 | *.[1-9][0-9] 65 | *.[1-9][0-9][0-9] 66 | *.[1-9]R 67 | *.[1-9][0-9]R 68 | *.[1-9][0-9][0-9]R 69 | *.eledsec[1-9] 70 | *.eledsec[1-9]R 71 | *.eledsec[1-9][0-9] 72 | *.eledsec[1-9][0-9]R 73 | *.eledsec[1-9][0-9][0-9] 74 | *.eledsec[1-9][0-9][0-9]R 75 | 76 | # glossaries 77 | *.acn 78 | *.acr 79 | *.glg 80 | *.glo 81 | *.gls 82 | *.glsdefs 83 | 84 | # gnuplottex 85 | *-gnuplottex-* 86 | 87 | # hyperref 88 | *.brf 89 | 90 | # knitr 91 | *-concordance.tex 92 | # TODO Comment the next line if you want to keep your tikz graphics files 93 | *.tikz 94 | *-tikzDictionary 95 | 96 | # listings 97 | *.lol 98 | 99 | # makeidx 100 | *.idx 101 | *.ilg 102 | *.ind 103 | *.ist 104 | 105 | # minitoc 106 | *.maf 107 | *.mlf 108 | *.mlt 109 | *.mtc 110 | *.mtc[0-9] 111 | *.mtc[1-9][0-9] 112 | 113 | # minted 114 | _minted* 115 | *.pyg 116 | 117 | # morewrites 118 | *.mw 119 | 120 | # mylatexformat 121 | *.fmt 122 | 123 | # nomencl 124 | *.nlo 125 | 126 | # sagetex 127 | *.sagetex.sage 128 | *.sagetex.py 129 | *.sagetex.scmd 130 | 131 | # sympy 132 | *.sout 133 | *.sympy 134 | sympy-plots-for-*.tex/ 135 | 136 | # pdfcomment 137 | *.upa 138 | *.upb 139 | 140 | # pythontex 141 | *.pytxcode 142 | pythontex-files-*/ 143 | 144 | # thmtools 145 | *.loe 146 | 147 | # TikZ & PGF 148 | *.dpth 149 | *.md5 150 | *.auxlock 151 | 152 | # todonotes 153 | *.tdo 154 | 155 | # xindy 156 | *.xdy 157 | 158 | # xypic precompiled matrices 159 | *.xyc 160 | 161 | # endfloat 162 | *.ttt 163 | *.fff 164 | 165 | # Latexian 166 | TSWLatexianTemp* 167 | 168 | ## Editors: 169 | # WinEdt 170 | *.bak 171 | *.sav 172 | 173 | # Texpad 174 | .texpadtmp 175 | 176 | # Kile 177 | *.backup 178 | 179 | # KBibTeX 180 | *~[0-9]* 181 | -------------------------------------------------------------------------------- /Beginning Perl for Bioinformatics (A4).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/Beginning Perl for Bioinformatics (A4).pdf -------------------------------------------------------------------------------- /Beginning Perl for Bioinformatics (A4).tex: -------------------------------------------------------------------------------- 1 | % !TeX root 2 | % !TEX encoding = UTF-8 Unicode 3 | % !TeX program = xelatex -synctex=1 -interaction=nonstopmode --output-driver="xdvipdfmx -q -E -V 7" %.tex 4 | 5 | \input{./Chapters/header_zh.tex} 6 | 7 | \usepackage{geometry} 8 | \geometry{left=3cm,right=3cm,top=3cm,bottom=2cm,foot=3cm} 9 | 10 | 11 | \VerbatimFootnotes 12 | 13 | \begin{document} 14 | 15 | %\draftwatermarkoff 16 | 17 | \input{./Chapters/cover.tex} 18 | 19 | \dominitoc % Initialization 20 | 21 | %\draftwatermarkon 22 | 23 | \frontmatter 24 | \input{./Chapters/chapter_perface.tex} 25 | 26 | \clearpage 27 | \setcounter{page}{0} 28 | \tableofcontents 29 | \clearpage 30 | 31 | \listoffigures 32 | \listoftables 33 | \lstlistoflistings 34 | 35 | \mainmatter 36 | \input{./Chapters/chapter1.tex} 37 | \input{./Chapters/chapter2.tex} 38 | \input{./Chapters/chapter3.tex} 39 | \input{./Chapters/chapter4.tex} 40 | \input{./Chapters/chapter5.tex} 41 | \input{./Chapters/chapter6.tex} 42 | \input{./Chapters/chapter7.tex} 43 | \input{./Chapters/chapter8.tex} 44 | \input{./Chapters/chapter9.tex} 45 | \input{./Chapters/chapter10.tex} 46 | \input{./Chapters/chapter11.tex} 47 | \input{./Chapters/chapter12.tex} 48 | \input{./Chapters/chapter13.tex} 49 | 50 | %\appendix 51 | \renewcommand{\thechapter}{\Alph{chapter}} 52 | \titleformat{\chapter}{\centering\LARGE\bfseries}{附录 \thechapter}{2em}{} 53 | \titlecontents{chapter}[0pt]{\vspace{0.3\baselineskip}\bfseries}{附录 \thecontentslabel\quad}{}{\hfill\contentspage} 54 | \begin{appendices} 55 | \input{./Chapters/chapter_aa.tex} 56 | \input{./Chapters/chapter_ab.tex} 57 | \end{appendices} 58 | 59 | \backmatter 60 | \input{./Chapters/chapter_colophon.tex} 61 | 62 | \end{document} 63 | -------------------------------------------------------------------------------- /Chapters/chapter1.tex: -------------------------------------------------------------------------------- 1 | \chapter{生物学和计算机科学} 2 | \label{chap:chapter1} 3 | \minitoc 4 | 5 | 涉足计算机程序设计和生物学领域,总会发现有许多激动人心的事情,随处可见的新技术和新成果便是其中之一。 6 | 7 | 当然,生物学是一门古老的学科,但其中许多有趣的研究方向都源于新技术和新想法。现代科学中的遗传学起源于广受赞誉的孟德尔的工作\footnote{译者注:孟德尔的研究论文发表于1865年。},迄今为止仅有100多年的历史,但已成为现代生物学中举足轻重的一门学科。脱氧核糖核酸(DNA)和第一个蛋白质的结构是大约50年前解析出来的\footnote{译者注:DNA的双螺旋结构和第一个蛋白质的结构分别于1953年和1958年被解析出来。},而克隆DNA的聚合酶链式反应(PCR)技术才出现了20多年\footnote{译者注:PCR技术出现于1983年。}。人类基因组计划(Human Genome Project,HGP)旨在破译人类基因的遗传信息,刚刚过去的十年\footnote{译者注:指1990年到2000年。}见证了该计划的启动和完成\footnote{译者注:1990年HGP正式启动,2000年工作草图完成。}现在,我们正处于生物学研究的黄金年代,这是人类医学史、科学史和哲学史上至关重要的一个时代。 8 | 9 | 计算机科学是一个相对崭新的学科。算法早在古代就已经出现(欧几里得),而对计算机器的痴迷也有一定的历史了(比如,帕斯卡的机械计算器,以及19世纪巴贝奇的蒸汽动力计算器)。但程序设计仅仅在50年前才出现,和第一台大型、可编程的电子数字积分计算机ENIAC的建造处于同一个时代\footnote{译者注:ENIAC诞生于1946年。}。之后,程序设计便急速发展,现在仍是如此。互联网\footnote{译者注:1973年ARPA网扩展成互联网,1983年ARPA网将其网络核心协议由NCP改变为TCP/IP协议。}和个人电脑\footnote{译者注:世界公认第一部个人电脑是1971年Kenbak Corporation推出的Kenbak-1。}才出现了20多年,而万维网更是只有短短10年的历史\footnote{译者注:1991年因特网上的万维网公共服务首次亮相。}。今天,我们的通讯、运输、农业、金融、政府、商业、艺术都和计算机以及程序设计密不可分,科学研究亦是如此。 10 | 11 | 计算机程序设计领域的急速发展着实令人兴奋,但这也要求相关的专业从业人员要与时俱进。在某中程度上,程序设计代表了过程性知识——即如何做事的知识。计算机在我们社会和历史中的重要性,从使用计算机引起的过程性知识的海量增长中就可见一斑。同时我们也看到计算和算法的概念已被广泛使用,比如在艺术、法律和科学中就随处可见。计算机已经成为启发人们解开事物本质的制胜法宝。有感于此,把发生分子生物学过程的细胞看成一种特殊的计算机器,这绝对是一个诱人的想法。 12 | 13 | 反之亦然,生物学中的重大发现在计算机科学中也有所体现,如进化程序、神经网络和模拟退火等。不切当的启发存在一定的危险性,这是确确实实存在的,但不可否认,生物学和计算机科学两个领域观点的交换和启发已经成为各自领域取得重大发现的推动力。 14 | 15 | \section{DNA的组成} 16 | 为非生物学家着想,有必要回顾一下DNA和蛋白质的基本概念和相关术语。如果你是生物学家,可以直接跳过下面的两小节。 17 | 18 | DNA是由四种分子组成的聚合物。这四种分子常被叫做碱基或者核苷酸,它们是腺嘌呤、胞嘧啶、鸟嘌呤和胸腺嘧啶,单字母缩写分别为A、C、G和T。\footnote{它们因最早被发现的地方而得名:腺体、细胞、鸟粪和胸腺}(关于DNA是如何表述成计算机数据的,请参看\autoref{chap:chapter4}。)这些碱基首尾相连形成DNA的一条单链。 19 | 20 | 在细胞中,DNA通常以双链形式存在,两条链以著名的双螺旋形式互相缠绕在一起。双螺旋的两条链拥有互相配对的碱基,称为碱基对。一条链上的A总是和另一条链上的T相配对,而G则和C配对。 21 | 22 | DNA链是有方向性的。核苷酸的一端叫做5'端,另一端叫做3'端。当核苷酸连接形成DNA链的时候,一个核苷酸的5'端总是和另一个核苷酸的3'端相连接。此外,当细胞使用DNA时,如转录成RNA的过程,也是从5'端到3'端一个碱基一个碱基地进行。所以,当在纸上书写DNA时,方向是从左到右的,这和DNA碱基的5'端到3'端的方向是对应的。一个编码基因可能出现在两条链的任何一条上,所以当查找或分析DNA时一定要对两条链进行分析。 23 | 24 | 当两条链形成双螺旋时(见\autoref{fig:figure1.1}),它们的方向是相反的,也就是说,一条链的方向是5'端到3'端,而另一条链的方向则是3'端到5'端。所以,观察双螺旋的任何一个末端,都是一条链的3'端和另一条链的5'端。 25 | 26 | \begin{figure} 27 | \centering 28 | \includegraphics[width=0.5\textwidth]{figure1_1.png} 29 | \caption{DNA的两条链} 30 | \label{fig:figure1.1} 31 | \end{figure} 32 | 33 | 因为碱基对都是A-T配对和C-G配对,同时两条链的方向又是相反的,因此常用反向互补这个术语来描述两条链上碱基之间的关系。说“反向”是因为两条链的方向相反,说“互补”是因为某个碱基总是和它的互补碱基相配对——A和T配对、C和G配对。 34 | 35 | 基于以上事实,对于任何一条DNA单链,很容易就可以得到双螺旋中对应的另一条链。只需要简单得把碱基换成它们的互补碱基:A换成T、T换成A、C换成G、G换成C。因为DNA的书写方向是从5'端到3'端,所以在对DNA互补之后,还需要把它反向写出来才行。 36 | 37 | GenBank(the Genetic Sequence Data Bank)数据库(\href{http://www.ncbi.nlm.nih.gov}{http://www.ncbi.nlm.nih.gov})存储着绝大多数已知的序列数据。我们将会在\autoref{chap:chapter10}对GenBank进行详细介绍。 38 | 39 | \section{蛋白质的组成} 40 | 蛋白质和DNA类似,它们也是聚合物,由数量不等的简单分子组成一个长串。DNA是由四种核苷酸组成的,而蛋白质则是由20中氨基酸构成的。这些氨基酸出现的顺序并不固定,它们的名字和单字母、三字母缩写都罗列在了\autoref{tab:table4.2}中。 41 | 42 | 氨基酸由氨基基团和羧基基团构成。相邻氨基酸的氨基基团和羧基基团会形成化学键,叫做肽键。氨基酸都有从骨干上突出出来的侧链,20种氨基酸的侧链各不相同。侧链的化学属性在决定蛋白质属性方面起着关键作用。 43 | 44 | 蛋白质通常有比DNA更加复杂的3D结构。肽键有相当大的旋转自由度,从而允许蛋白质形成多种3D结构。和DNA的双螺旋结构不同,蛋白质可以由一条或多条由氨基酸组装成的肽链构成,并且可以折叠成各种不同的形状。\footnote{为了集中精力学习Perl语言,我尽量避开绝大部分令人迷惑的生物学知识。但我禁不住还是要提醒一句,其实DNA也有更加复杂的3D结构。DNA可以以单链、双链和三链形式存在,并且在细胞周期的大部分时间内它都卷曲压缩在一个很小的空间内。}蛋白质的氨基酸序列叫做蛋白质的一级结构,一级结构卷曲形成的$\alpha$-螺旋、$\beta$-折叠和转角等局部结构叫做二级结构,最终的折叠和组装叫做蛋白质的三级结构和四级结构(参看\autoref{chap:chapter11})。 45 | 46 | 可利用的蛋白质一级序列数据要比二级结构或高级结构的数据多。事实上,有大量的蛋白质一级序列数据可供使用(因为大量的DNA已被测序,从DNA中识别出蛋白质的一节序列并不是非常困难)。 47 | 48 | PDB(Protein Data 49 | Bank)数据库储存着成千上万个蛋白质的结构信息,这些信息都是最近几十年的工作成果积累起来的。我们将在\autoref{chap:chapter10}详细介绍PDB,当然你也可以先去PDB的网站(\href{http://www.rcsb.org/pdb/}{http://www.rcsb.org/pdb/})逛逛,熟悉一下这个最为基本的生物信息学资源。 50 | 51 | \section{\textit{In Silico}} 52 | 最近,\textit{in silico}这个新词已经成为指代在计算机中进行生物学研究的专用术语,和\textit{in vivo}、\textit{in vitro}这两个传统术语一起来描述进行实验研究的位置。 53 | 54 | 对于非生物学家来说,\textit{in vitro}表示“在玻璃中”,换言之,在实验试管中;\textit{in vivo}则表示“在生命中”,换言之,在生物活体内。\textit{in silico}这个术语的由来,源于大多数计算机芯片主要是由硅构成的这个事实。就我个人而言,我更喜欢\textit{in algorithmo}这样的术语,毕竟有许多不需要基于硅的计算方法,像DNA计算、量子计算、光学计算等奇妙的计算过程。 55 | 56 | 可以在线获取的大量生物学数据,使得生物学研究处于和物理学、天文学相类似的境地。在这些学科中,基于现代仪器的实验会产出海量的数据,为了分析处理这些数据,计算机不仅是无价的,而且是必需的。事实上,在计算机中对实验进行完全模拟是非常有可能的。比如,物理学中用计算机进行模拟的一个早期应用,就是对音乐厅的声学进行建模,通过改变音乐厅的设计来研究最终的声学效果,这显然比通过建造数十个音乐厅来检验声学效果要廉价的多。 57 | 58 | 自从计算机问世以来,在生物学中也发生着类似的转变,随着HGP和对多种生物DNA测序的进行,这种趋势在近几年急剧加大。需要收集、检索和分析的实验数据对单个生物学家来说实在是太过巨大了,这就迫使生物学家使用计算机来处理这些信息。 59 | 60 | 除了生物学数据的存储和提取,现在通过计算机模拟来研究生命系统也已经成为可能。获取人类和其他一些生物的基因,这已经成为计算机标准且常规的处理。当确定DNA的序列后,可以把它们存储在计算机中,然后写程序来识别限制酶切位点、进行限制酶切消化、制作限制酶图谱(参看\autoref{chap:chapter9})。与之类似,基因识别程序可以从测序的DNA中识别出潜在的外显子和内含子。(到本书撰写之际,并不是很精确,不同生物的识别结果差异很大。)也可以对细胞过程进行建模,利用该模型来研究如基因调控变化的影响等生物学过程。 61 | 62 | 现在,利用芯片技术(玻璃片上点上数千个样本,利用仪器进行检测)仅仅通过一次实验就可以获得成千上万个基因的表达水平。借助计算机来解析基因之间复杂的相互作用。比如,我们期望能够找到所有相关的基因,在细胞中它们通过蛋白质产物参与相同的生化途径。芯片会产出海量的数据,和其他实验数据不同,这些数据需要在计算机中进行存储和分析。 63 | 64 | 在我进入贝尔实验室成为程序员的第一天,我导师就告诉我,他的模拟计算速度太快了——仅需过夜就可完成,但这却让他头疼,因为他没有足够的时间来分析上一次的模拟了!尽管计算机有着各种令人头疼的问题和陷阱,但使用计算机来模拟实验确实给生物学带来了极大的益处。 65 | 66 | \section{计算的局限} 67 | 计算机科学中一些非常有趣的结果证明了人类知识的局限性。在生物学中有一些开放性的问题,有人认为利用更多的计算资源就可以解决这些问题,但这并不总是对的,因为有些问题本身就是无解的,换句话说,它们不可能被任何程序解决。此外,有些问题也许是可以解决的,但是随着问题量的增长,在实际中是没法解决这些问题的。这样的问题是不治的,称为NP完全。即使使用百万台计算机,每台的计算能力都是现在最强大计算机的一百万倍,也有可能需要十亿年才能计算出一个NP完全问题的答案。 68 | 69 | 你有可能会遇到NP完全问题,但这是非常罕见的,你的选择就是别去招惹这种无法解决的问题。我提及它们更多的是因为有趣,而不是因为菜鸟程序员在实际中会遇到这样的问题。但随着你在程序员的路上越走越远,尝试更多复杂程序的时候,这些局限,尤其是某些生物学问题的不治本性,会对你的编程产生实质性的影响。 70 | -------------------------------------------------------------------------------- /Chapters/chapter13.tex: -------------------------------------------------------------------------------- 1 | \chapter{进阶主题} 2 | \label{chap:chapter13} 3 | \minitoc 4 | 5 | 本书的初衷是帮助你学习基本的Perl语言编程。在本章中,我会介绍一些深入学习Perl涉及到的主题。 6 | 7 | \section{程序涉及的艺术} 8 | 我强调\textit{程序设计}的艺术,这也暗示了程序要以何种方式展示出来。通常的过程就是先讨论问题和想法,写出伪代码,然后编写一组小的、互相协作的子程序,最后搭建出完整的程序。在某些点上,你已经看到了,完成同一个任务有不止一种方法。这是程序员心态的一个重要部分:或者利用已掌握的知识,或者进行不断的尝试。 9 | 10 | 另一个已经提过的主题也解释了使用\textit{问题解决策略}的程序员所依赖的东西。它们包括知道如何充分利用可检索的新闻组档案、书籍和语言文档等资源的信息,对于调试工具有足够的实践经验,理解基本的算法和数据结构设计和分析。 11 | 12 | 随着技能的提升,你的程序会更加复杂,你会发现这些策略起的作用越来越重要。要设计、编程解决复杂的问题,或者处理大量的复杂数据,都需要更加高深的问题解决策略。所以,花一些精力学习像计算机科学和生物学家那样进行思考,是非常值得的。 13 | 14 | \section{网页编程} 15 | 因特网是生物信息学数据最主要的来源。从FTP站点到使用网页的程序,学习Perl的生物信息学家需要有能力去访问这些网络资源。如今大概每一个实验室都必须要有一个自己的网页,并且许多经费也需要它。你需要学习关于HTML和XML标记语言\footnote{译者注:还有HTML5、XHTML、Markdown等。}的基础知识,这些标记语言被用来显示网页,要了解网络服务器和网页浏览器之间的区别,以及生活中类似的事情。 16 | 17 | 流行的\textit{CGI.pm}模块使得创建交互式的网页变得相当简单,以及其他的一些可用的模块使得因特网编程任务也不是那么痛苦了。比如,你可以为你自己的网页编写代码,让访问者尝试你最新的序列分析器或者检索你特定目的的数据库。你也可以向你自己的程序中添加代码,让它们可以和其他的网站进行交互,自动访问和获取数据。在地理上分散各地的合作者们可以在一个项目中利用这样的网页编程进行亲密无间的协作。 18 | 19 | \section{算法和序列比对} 20 | 你会想花一些时间去探索一下算法中的表中结果,在\autoref{chap:chapteraa}中有相关的推荐资料。一个入门的好的切入点是最基本的序列比对方法,比如Smith-Waterman算法。在算法的术语中,并行、随机和近似的主题都值得你至少去混个眼熟。 21 | 22 | 序列比对是算法家族中的一个子集,这就是字符串匹配算法,用来寻找相同或相似的程度,或者寻找序列间同源的证据。Smith-Waterman算法、空位的处理、预处理和并行技术的使用以及多序列比对等等都是这个主题中的一部分。 23 | 24 | \section{面向对象编程} 25 | 面向对象编程(object-oriented programming)是程序设计的一种风格,它为数据和子程序提供了一个明确定义的界面(在面向对象编程中叫做方法)。面向对象编程学起来并不难,它让某些本来很难的事情变得简单了(反之亦然,但你并没有必要用它来处理所有的事情!)。自从几年前这个特性被添加到Perl语言中以来,大量的Perl代码都开始用面向对象的风格进行编写。 26 | 27 | \section{Perl模块} 28 | 我多次提到模块,而CPAN这个Per代码的大仓库中有大量的可以使用的模块。大部分都是免费的,但是最好检查一下版权限制,看看Perl FAQs中关于版权议题的讨论。最近的大多数模块,包括CPAN中的大量代码,都开始使用面向对象编程的风格进行编写。要想理解这种风格,你需要扩充你的Perl知识,但是你不需要对面向对象编程进行很深入的学习就可以在你的程序中使用大多数的模块。 29 | 30 | \subsection{BioPerl} 31 | 生物信息学中一个重要的并且在稳步发展的Perl模块套件就是BioPerl项目,你可以在网站 \href{http://www.bioperl.org}{http://www.bioperl.org} 上找到它。这些模块赋予你很多的能力,都是可以直接使用的。 32 | 33 | \section{复杂的数据结构} 34 | Perl可以处理复杂的数据结构,在许多编程的情况下这是非常有用的。当然这也需要你去学习,这样才能读懂你可能会遇到的大量已有的Perl代码。 35 | 36 | 比如,在本书中,你已经解析了很多数据。为了完成这个任务,你编写了一组子程序,每一个都非常简短,每一个都用来解析数据不同层面的结构。通过使用复杂的数据结构,你可以用反映数据的结构的形式来存储你的解析过程。这和使用面向对象的方法访问已经解析的数据结合起来,是实现数据解析的一个非常有用的方法。 37 | 38 | 复杂的数据结构依赖于指针,我在通过指针进行访问以及\textit{File::Find}的讨论中简单提过它。 39 | 40 | \section{关系数据库} 41 | 关系数据库是Perl程序员和生物信息学家需要了解的另外一个领域。总有一天,你会发现使用使用平面文件或者DBM没法管理中型或大型项目的数据,这时就要考虑关系数据库了。尽管需要花点力气才能配置好并进行编程,但是它提供了一个标准且可靠的方法来存储数据,并且针对它可以询问各种问题。在本书中,我们简单讨论了以下关系数据库,但实际上使用了一个简单的DBM数据库。然而,在你工作的历程中,你很可能会遇到Oracle、MySQL、PostgreSQL、Sybase和其他的一些数据库。Perl模块DBI,它本身就表示Database Independence,使得在不(太)考虑实际使用的哪个数据库的前提下编写操作关系数据库的代码成为可能。 42 | 43 | 事实上,编写处理数据库的代码并不是很难。最困难的部分其实是要把正确的库存储到数据库中,确保有正确的Perl模块可以使用,以及你知道如何从你的程序中连接数据库。一旦你把这些都搞定了,使用数据库通常来说就非常容易了。 44 | 45 | 都知道,关系数据库有它们自己的知识,需要大量的知识来设计和操作好的数据库。许多程序员就专门研究这些议题,其实不少生物信息学家也专门做这个,因为对于设计更好的生物学数据库来说有很多有趣的研究问题。 46 | 47 | \section{芯片和XML} 48 | 芯片(用于研究基因表达的小型化的基于芯片的“实验室”)和XML(Extensible Markup Language,可扩展标记语言)是两个结合在一起的现代发展领域。现在整个基因组都可以使用,芯片技术让你可以一次检测成千上万个基因转录本的相对水平,通过它们的帮助,我们希望理解细胞中成千上万个基因和基因产物之间的通路和相互作用。简单来说,XML是一个新的、改良版的HTML,它是作为存储和互换数据的标准而出现的。(本书就是通过广泛使用XML进行编写的。\footnote{译者注:本书是基于\LaTeX 进行排版的。})XMl正在成为许多新的实验数据类型的重要的接口。 49 | 50 | \section{图形编程} 51 | 用好的图形展示数据,对于让你的同事能够充分理解你的结果是至关重要的。图形编程语言展示数据和结果,并且通过绚丽且易于导航的界面和软件应用进行交互。许多生物信息学的程序都处理大量的数据,一个图形用户界面(GUI,graphical user interface)可以很容易把有助于你工作的应用和浪费你时间的应用区分开来。像常见于网页上的GUIs,不仅对于展示输出结果至关重要,对于用户数据的收集也是非常重要的。 52 | 53 | 通过点击的方法与软件应用进行交互是最基本的标准。一个好的GUI可以让一个应用或者程序更加易用。然而,一个复杂的GUIs以及图形数据展示,与更加简单的图形相比,其可移植性要差一些。你可能要去摸索一下Tk、GD以及其他一些Perl模块的图形能力。 54 | 55 | \section{网络建模} 56 | 生物学系统,比如基因和基因产物,相互作用的网络,可以进行建模,用图算法进行研究。尽管和“图形”这个名词非常相似,但图算法是完全不同的一个东西,它基于图论的离散数学领域。举个例子,利用图和其他许多变体(比如佩特里网(Petri net))的算法,可以存储并研究生化通路和细胞内以及细胞间信号通路的属性。 57 | 58 | \section{DNA计算机} 59 | 对于有超前思维的科学家来说,了解研究计算方面的新动向既有趣也有启发性,比如DNA计算机、光计算和量子计算。DNA计算机尤其有趣。它们使用标准的分子生物学实验室中的技术作为通用计算机的模型。它们可以执行算法、存储数据,从常见的行为来看就行一台“真”的计算机一样。在本书编写时,它们还是不切实际的,但光想想就足够激动人心的了,也许某一天真的会实现,谁知道呢?\footnote{译者注:该领域已经取得了不错的进展,请参看 \href{https://zh.wikipedia.org/wiki/DNA\%E9\%81\%8B\%E7\%AE\%97}{DNA运算(维基百科)}。} 60 | -------------------------------------------------------------------------------- /Chapters/chapter2.tex: -------------------------------------------------------------------------------- 1 | \chapter{Perl语言入门} 2 | \label{chap:chapter2} 3 | \minitoc 4 | 5 | Perl语言是一种流行的编程语言,在生物信息学和网络编程中广泛应用。Perl之所以能被生物学家广泛使用,是因为它特别适合用来解决生物信息学问题。 6 | 7 | Perl也是一个应用程序,就像你在计算机中安装的其他应用程序一样。对于大多数生物学实验室使用的各种操作系统来说,Perl(完全免费)都存在其中并时刻运行着。\footnote{操作系统管理者程序的运行和其他一些计算机提供的基本服务,如文件存储等。}计算机中的Perl应用程序\footnote{译者注:此处指的是实际编译并运行程序的解释器,一般使用perl(小写p)来表示。}读取Perl语言程序(比如你将在本书学习过程中写的任何一个程序)\footnote{译者注:此处指Perl脚本。指代程序语言时一般用Perl(大写P)来表示。},把它翻译成计算机可以理解的指令,并运行(或“执行”)它。 8 | 9 | 所以,Perl这个词语既指你用来编写脚本的程序语言,也表示计算机中运行这些脚本的应用程序/解释器。\footnote{译者注:一般情况下,前者使用Perl表示,后者使用perl表示。}你可以通过上下文的语境来区分Perl的具体含义。 10 | 11 | 所有的计算机语言,包括Perl,都需要一个翻译器应用程序(包括解释器和编译器两种)来把程序翻译成计算机可以实际运行的指令。Perl的翻译器应用程序通常指的就是Perl解释器,当然它也包括Perl编译器。你会发现一般把Perl程序叫做Perl脚本或者Perl源码。程序、应用程序、脚本和可执行文件这四个术语在某种程度上是通用的,在本书中我都把它们叫做“程序”。 12 | 13 | \section{低而长的学习曲线} 14 | 对于Perl来说,令人高兴的一点就是你很快就可以学会Perl程序的编写。大体上来看,Perl的学习曲线是比较低的。这也就是说你可以轻松入门,不需要学习掌握太多的知识就可以写出非常实用的程序。 15 | 16 | Perl提供了不同的编程范式,这已经超出了本书的范畴,所以我并不打算对此进行深入探讨,但我还是要说一句,最流行的编程范式叫做命令式编程,这也是你将在本书中学习到的编程范式。另一种比较流行的编程范式叫做面向对象编程,Perl对这种编程范式也有很好的支持。其他编程范式还包括函数式编程和逻辑编程。 17 | 18 | 尽管你可以轻松入门,但如果想学习Perl中的所有知识,那将花费你大量的精力。大多数人都只学习像本书中的知识点一样的基本知识,当需要时再学习其他的相关主题。 19 | 20 | 在继续进行之前,我们先讨论几个基本概念: 21 | 22 | \textcolor{black}{什么是计算机程序?} 23 | 24 | \begin{adjustwidth}{4em}{} 25 | \hspace*{2em}计算机程序就是用特定编程语言写成的一系列指令,这些指令可以被计算机读取。一个程序可以非常简单,简单到就像下面这个把DNA序列打印到计算机屏幕上的Perl语言程序一样: 26 | 27 | %\noindent 28 | \begin{lstlisting} 29 | print 'ACCTGGTAACCCGGAGATTCCAGCT'; 30 | \end{lstlisting} 31 | 32 | 就像在计算机中存储各种数据(不限于程序)一样,要在文件中编写和保存Perl语言程序。文件以成组分层的形式进行存储,这些不同的组在Macintosh和Windows系统中叫做文件夹,在Unix和Linux系统中叫做目录,其实两者是完全可以互换使用的。 33 | \end{adjustwidth} 34 | 35 | \textcolor{black}{什么是编程语言?} 36 | 37 | \begin{adjustwidth}{4em}{} 38 | \hspace*{2em}有一系列详细定义的语法规则来指导计算机程序的编写。通过学习编程语言的这些语法规则,你可以编写出在计算机上运行的程序。编程语言和英语等我们日常使用的口语是非常相似的,只是针对计算机系统进行了严格而特定的定义。经过一定的训练,就可以轻松阅读并编写计算机程序。有许多不同的编程语言,在本书中你将学习Perl语言。 39 | 40 | 程序员编写的程序也叫做源代码,有时也简称为源或代码。源代码需要翻译成机器语言,计算机才能够运行它。机器语言都是二进制数字,非常难于阅读和编写,通常把它叫做二进制可执行程序。就像在本章中你将看到的那样,使用Perl解释器(或编译器),你可以把Perl程序变成可以运行的程序。 41 | \end{adjustwidth} 42 | 43 | \textcolor{black}{什么是计算机?} 44 | 45 | \begin{adjustwidth}{4em}{} 46 | \hspace*{2em}哦,…… 47 | 48 | 好吧,这是个愚蠢的问题。计算机就是你在计算机商城里买到的机器。但实际上,你应该有一个清晰的认识,明白计算机到底是怎样的一台机器。本质上来说,计算机就是一台可以运行不同程序的机器。正是这种最基本的灵活性和适用性,使得计算机成为如此有用且通用的工具。它是可编程的,你将学习如何使用Perl编程语言来对它进行编程。 49 | \end{adjustwidth} 50 | 51 | \section{Perl的优势} 52 | 接下来的几个小节将对Perl的几个优点进行说明。 53 | 54 | \subsection{易于编程} 55 | 编程语言的易用性体现在不同的方面。我说“容易”指的是对于程序员来说易于编程。Perl的一些特性,使得解决常见的生物信息学问题非常容易。它可以处理ASCII文本文件或平面文件中的信息,而许多重要的生物学数据就是存储在这样的文件中,GenBank和PDB等数据库就是如此。(关于ASCII的讨论请参看\autoref{chap:chapter4};GenBank和PDB分别是\autoref{chap:chapter10}和\autoref{chap:chapter11}的讨论主题。)使用Perl,可以容易得处理DNA和蛋白质的长序列,方便得控制一个或多个其他程序。最后再举一个例子,Perl曾用来把生物学研究实验室概况和研究成果放在实验室的动态网站上。Perl可以胜任所有的这些任务,当然绝不止这些。 56 | 57 | 尽管Perl是一种非常适用于生物信息学的编程语言,但它绝不是唯一的选择,也不一定总是最好的选择。其他编程语言,如C和Java,也在生物信息学中使用。如何选择一种编程语言,这取决于需要解决的问题、程序员的能力、可利用的系统等因素。 58 | 59 | \subsection{快速原型} 60 | 在生物学研究中使用Perl的另一个非常重要的优势就是,程序员可以非常迅速得写出一个典型的Perl程序(这被称为快速原型)。与C和Java相比,许多问题用很少的几行Perl代码就可以解决,这也直接导致了它在生物学研究中的流行。在一个研究中,经常需要写一些处理新问题的程序,这些程序仅会偶尔使用或使用一次,或者需要被频繁修改。使用Perl,你只需折腾几分钟或者几个小时就可以写出这样的程序,继续后续的研究工作。当在工作中选择使用Perl时,这种快速原型的能力常常是需要重点考虑的因素。常常可以遇到同时精通Perl和C的程序员,他们声称在编程时Perl要比C快五到十倍。这种差距在人手不足的研究实验室中尤其显著。 61 | 62 | \subsection{可移植性,速度和程序维护} 63 | 可移植性表示编程语言可以在各种不同的计算机操作系统上运行。Perl的可移植性就不错,在生物学实验室中使用的所有现代计算机中,它都可以使用。如果你在自己的Mac中用Perl编写一个分析DNA的程序,然后把它放到Windows计算机中,你会发现它通常可以正常运行,或者仅需很小的修改就可运行。 64 | 65 | 速度表示程序运行的速度。在这方面,Perl虽然不是最好的,但表现也不错。考虑到运行的速度,最常见的选择就是C。用C编写的程序,其运行速度通常比对应的Perl程序快两倍甚至更多。(有许多利用编译器等来提高Perl运行速度的方法,但依然……。) 66 | 67 | 在许多组织中,都是先用Perl来编写程序,然后再把那些确实需要提高运行速度的部分用C重写。事实上,运行速度只是偶尔才会成为需要考虑的关键因素。 68 | 69 | 编程相对是比较昂贵的,因为它需要时间和熟练的人员,它是劳动密集型的。另一方面,计算机和计算机时间(在有了中央处理单元之后通常叫做CPU时间)却是相对便宜的。无论如何,在一天内的大部分时间里,大多数桌面计算机都出于空现状态。所以最好的策略就是节省程序员的时间,让计算机工作。一般来说使用Perl就可以了,除非你的程序必须运行四秒而非十秒。 70 | 71 | 程序维护是保证程序正常运行的常规工作,比如给程序添加特性、扩展程序以便能够处理更多类型的输入、移植程序以便在其他计算机系统上运行、修复bug等工作。编写程序需要花费一定的时间、精力和财力,而好的程序在维护阶段的花费远比第一次编写时的花费要高。编写程序时使用一种语言和特定的风格是非常重要的,因为这将使得维护工作相对容易一些,Perl就是这样的编程语言。(就像其他编程语言一样,你可以用Perl写出晦涩难懂、难于维护的代码,但我会给你一些指导,使你的程序可以被其他程序员轻松读懂。) 72 | 73 | \subsection{Perl的版本} 74 | 向其他所有流行软件一样,Perl也在不断成长,在近15年的历史中不断发展变化\footnote{译者注:Perl诞生于1987年。}。Perl的作者拉里$\textbullet$沃尔和庞大的开发社区会定期发布新的版本。这些新的版本都进行了认真的设计,以便向下兼容旧版本写成的大部分程序,但是偶尔也会添加一些新的特性,这些特性在旧版本的Perl中无法正常工作。 75 | 76 | 本书假设你安装了Perl 5或者更高的版本。如果你的计算机中安装了Perl,那很有可能是Perl 5,但最好去确认一下。在Unix或者Linux系统中,以及MS-DOS或者MacOS X的命令行窗口中,命令 \verb|perl -v|会显示Perl的版本号。在我的计算机中,使用的是Perl 5.6.1\footnote{译者注:现在最新的版本是5.22.0(2015-06-01)。}。数字5.6.1比5“大”,也就是说它满足要求。如何计算机中Perl的版本号小(很有可能是4.036),你最好安装一个最新版本的Perl,这样本书中的大部分程序才能正常运行。 77 | 78 | 未来的版本会如何呢?Perl总实在进化,Perl 6已经近在眼前了\footnote{译者注:Perl 6正在开发中,它将会与现在的Perl版本有很大的不同,但相信还要开发一段很长的时间。}。本书中的代码在Perl 6中能否依然正常工作?答案是肯定的。尽管Perl 6要添加一些新的东西进去,运行本书中的Perl 5代码不会存在太大的问题。 79 | 80 | \section{在你的计算机中安装Perl} 81 | 接下来的几个小节将指导你在最常见的计算机系统中安装Perl。 82 | 83 | \subsection{也许Perl已经安装上了!} 84 | 许多计算机,尤其是Unix和Linux计算机,已经预装了Perl。(注意Unix和Linux本质上是一样的操作系统;Linux是Unix操作系统的克隆,或者说是功能性的拷贝。)所以,首先确认一下Perl是不是已经被安装上了。在Unix和Linux系统中,在命令提示符后面输入一下命令: 85 | 86 | \begin{lstlisting}[language=bash] 87 | $ perl -v 88 | \end{lstlisting} 89 | 90 | 如果Perl已经安装上了,你会看到和我自己Linux计算机上类似的信息: 91 | 92 | %\begin{verbatim} 93 | \begin{lstlisting}[language=] 94 | This is perl, v5.6.1 built for i686-linux 95 | 96 | Copyright 1987-2001, Larry Wall 97 | 98 | Perl may be copied only under the terms of either the Artistic License or the GNU General Public License, which may be found in the Perl 5 source kit. 99 | 100 | Complete documentation for Perl, including FAQ lists, should be found on this system using 'man perl' or 'perldoc perl'. If you have access to the Internet, point your browser at http://www.perl.com/, the Perl Home Page. 101 | \end{lstlisting} 102 | %\end{verbatim} 103 | 104 | 如果没有安装Perl,你会看到如下类似的信息: 105 | 106 | %\begin{verbatim} 107 | \begin{lstlisting}[language=sh] 108 | perl: command not found 109 | \end{lstlisting} 110 | %\end{verbatim} 111 | 112 | 如果你看到这样的信息,并且你使用的是大学或公司的公用Unix系统,一定要向系统管理员进行确认,也许Perl已经安装上了,但是你的环境设置导致你无法找到它。(或者,系统管理员可能会说:“你要用Perl?没问题,我来给你安装。”) 113 | 114 | 在Windows或者Macintosh中,可以在程序目录中或者使用查找程序查找\textit{perl}。在MS-DOS的命令窗口或者MacOS X的shell窗口中,你同样可以尝试输入 \verb|perl -v|。(注意MacOS X其实是Unix系统!) 115 | 116 | \subsection{没有网络可用?} 117 | 如果你没有网络可用,你可以把计算机给你可以联网的朋友,让他帮忙安装Perl。你也可以利用朋友的计算机,通过Zip磁盘片或者刻录一张光盘把Perl软件复制到你的计算机中。通过各种途径(咨询当地的软件商店),你也可以获得商业的含有Perl的包装光盘,此外,像O'Reilly出版的《Perl Resource Kits》等书籍中也会包含Perl的光盘。 118 | 119 | 除了安装Perl,本书中的所有内容都不要联网。在上下班坐地铁的时候,或者其他类似的情况,如果你想做做练习,也未尝不可。除了安装Perl,本书中需要联网的内容主要包括:从书籍网站上下载示例代码了,这样你就不用一行一行输入计算机了;下载并练习测试题;从各种生物学数据库中查找生物学数据;在计算机中没有安装Perl文档的情况下联网查阅Perl文档。 120 | 121 | 要知道,如果你想做生物信息,因特网是必不可少的。你可以在没有联网的情况下通过本书学习编程的基本原理,但是你需要联网才能下载生物信息学软件和数据。 122 | 123 | \subsection{下载} 124 | Perl是一个应用程序,所以在你的计算机中下载和安装Perl的过程和安装其他应用程序是完全一样的。 125 | 126 | 有一个网站是学习Perl相关知识的起点,它就是 \href{http://www.perl.com/}{http://www.perl.com/}。网站主页上有一个下载点击按钮,通过它你可以找到在计算机上安装Perl所需要的所有东西。在下载页面,有获取帮助的链接和其他相关链接。所以即使本书中的内容过时了,你仍然可以访问Perl站点,找到安装Perl所需要的相关内容。 127 | 128 | 下载和安装Perl通常都比较容易,事实上,大部分时间都还是比较惬意的。然而,有时为了让它能够正常工作,你还是需要付出一些努力的。如果你是编程方面的新手,并且碰到了一些棘手的问题,你最好向实验室中使用Perl的专业程序员、管理员、教师等人寻求帮助。 129 | 130 | 简言之,在计算机中安装Perl的基本步骤如下所示: 131 | 132 | \begin{enumerate} 133 | \item 确认一下Perl是否已经安装上了;如果已经安装了,确认一下Perl的版本不低于Perl 5。 134 | \item 连接网络,打开Perl官网的主页 \href{http://www.perl.com/}{http://www.perl.com/}。 135 | \item 进入下载页面,确定你要下载的Perl发行版。 136 | \item 下载正确的Perl发行版。 137 | \item 在你的计算机中安装此发行版。 138 | \end{enumerate} 139 | 140 | \subsection{二进制 vs. 源代码} 141 | 当从站点 \href{http://www.perl.com}{http://www.perl.com} 中下载Perl的时候,你需要在二进制发行版和源代码发行版中进行选择。在计算机中安装Perl的最好选择就是使用已经编译好的二进制版本,因为它最容易安装。然而,如果没有二进制版本可用,或者你想配置安装Perl时的各种选项,就可以下载Perl的源代码。源代码本身是用C语言编写的,你可以使用C编译器对它进行编译。对于新手来说,从源代码进行编译实在是太过复杂了,所以还是尽量寻找适合计算机操作系统的二进制版本吧。 142 | 143 | \subsection{安装} 144 | 接下来的几个小节是在特定平台上安装Perl的操作指南。 145 | 146 | \subsubsection{Unix和Linux} 147 | 如果你的Unix或者Linux计算机中没有安装Perl,首先去寻找二进制包进行安装。在 \href{http://www.perl.com}{http://www.perl.com} 站点的下载页面上,你会看到二进制发行版的副标题。选择Unix或Linux,看看是否有适用于你的操作系统的二进制版本。有许多版本可以下载安装,一旦你下载了二进制版本,根据网站上的指南就可以把Perl安装上了。许多Linux发行版都在它们的网站上维护着最新的Perl二进制版本。比如,如果你使用的是红帽Linux系统,你需要首先确认系统的版本(使用 \verb|uname -a|),然后找到对应的rpm文件,下载之后进行安装。红帽Linux系统有Perl的rpm文件,用户可以使用以下命令进行安装: 148 | 149 | %\noindent 150 | \begin{lstlisting}[language=bash] 151 | rpm -Uvh perl.rpm 152 | \end{lstlisting} 153 | \noindent (perl.rpm文件的实际名称可能有所变化)。 154 | 155 | 如果没有适用于你使用的Unix或Linux的Perl二进制版本,你就必须要从源代码进行编译了。这种情况下,还是从Perl网站开始,点击下载按钮,选择源代码发行版。源代码中有一个\textit{INSTALL}文件,它是指导你进行操作的指南,从下载源代码、在系统中进行安装、从源代码编译成二进制可执行文件,到最后安装二进制可执行文件,每一个步骤都有详细的说明。 156 | 157 | 前面已经提到,相比安装已经编译好的二进制版本,从源代码进行编译是一个漫长的过程,并且需要仔细阅读操作指南,但通常这还是值得的。为了从源代码安装Perl,你需要一个C编译器。如今,某些Unix系统中并没有一个完整的C编译器,而在Linux中通常都安装有一个叫做\textit{gcc}的免费的C编译器。当然,你也可以在任何缺少C编译器的Unix(或Windows,或Mac)系统中安装\textit{gcc}。 158 | 159 | \subsubsection{Macintosh} 160 | MacPerl网站 \href{http://www.macperl.com/}{http://www.macperl.com/} 上(你可以从Perl网站上点击下载按钮进入该网站)清晰得解释了MacPerl的安装步骤,此处是一个简要的概述。 161 | 162 | 在MacPerl网站上,点击获取MacPerl,按照指引即可下载该应用程序。它会下载到你的桌面上,双击即可进行安装。如果你没有Aladdin Stuffit Expander(大多数Mac都有),双击它就不会有什么效果,所以你需要去网站 \href{http://www.aladdinsys.com}{http://www.aladdinsys.com} 下载并安装Stuffit。 163 | 164 | 在MacOS Finder中MacPerl作为一个独立的应用程序进行安装,而在Macintosh程序员工作台中则作为一个工具进行安装。你想要的很可能是一个独立的应用程序。Perl 5可以适用于MacOS 7.0及其后续版本。至于哪个Perl版本适用于你自己的硬件和MacOS版本,在MacPerl网站上可以找到详细的说明。 165 | 166 | \subsubsection{Windows} 167 | 对于不同的Windows版本,有好多二进制发行版可供选用。因为Windows是和因特尔32位芯片密切相关的,所以这些二进制发行版通常叫做Wintl或者Win32二进制包。现在标准的Perl发行版是来自ActiveState的ActivePerl,网站是 \href{http://www.activestate.com/ActivePerl/}{http://www.activestate.com/ActivePerl/} 在上面你可以找到完整的安装说明。你也可以在Perl网站上通过下载按钮找到ActivePerl,在二进制发行版副标题下,找到Perl for Win32,点击ActivePerl站点链接即可。 168 | 169 | 在ActiveState网站的ActivePerl页面中,点击下载按钮,你将下载Windows-Intel二进制包。注意安装它需要一个叫做Windows Installer的程序,如果你的计算机中没有安装,可以在ActivePerl中找到它。 170 | 171 | \section{如何运行Perl程序} 172 | 如何运行Perl的详细步骤,取决于你的操作系统。你安装Perl时参考的操作指南中包含了你需要知道的所有相关内容,此处我仅进行简短的总结,这对于起步来说足够了。 173 | 174 | \subsection{Unix或Linux} 175 | 在Unix或Linux中,你通常会在命令行中运行Perl程序。如果你位于程序所在的目录中,假设这个Perl程序文件叫做\textit{this\_program},你通过输入 \verb|perl this_program|就可以运行它。如果你在另外的目录中,就必须要给出程序的路径名,比如: 176 | 177 | \begin{lstlisting}[language=] 178 | perl /usr/local/bin/this_program 179 | \end{lstlisting} 180 | 181 | 因为不同的计算机可能会把Perl安装在不同的目录中,所以通常情况下,你会在\textit{this\_program}文件的第一行指定系统中Perl的正确路径。在我的计算机中,我的Perl程序中的第一行是: 182 | 183 | \begin{lstlisting}[language=bash] 184 | #!/usr/bin/perl 185 | \end{lstlisting} 186 | 187 | 你可以通过键入 \verb|which perl|来找到你系统中Perl的安装路径。 188 | 189 | 使用\textit{chmod}命令,你可以赋予程序可执行权限。比如,你可以键入: 190 | 191 | \begin{lstlisting}[language=bash] 192 | chmod 755 this_program 193 | \end{lstlisting} 194 | 195 | 如果你的第一行设置正确,并且也使用了\textit{chmod}命令,你可以直接键入Perl程序的文件名来运行它。所以,如果你在程序所在的目录中,你可以键入 \verb|./this_program|;如果程序所在的目录包含在 \verb|$PATH|或者 \verb|$path|环境变量中,你可以键入 \verb|this_program|。\footnote{ \verb|$PATH|是sh、bash和ksh等shell的环境变量;而 \verb|$path|则适用于csh和tcsh。} 196 | 197 | 如果你的Perl程序没有正常运行,命令窗口中的shell会给出错误信息,这些错误信息也许会让你晕头转向。比如,我的Linux系统中的bash给出了如下所示的错误信息: 198 | 199 | \begin{lstlisting}[language=bash] 200 | bash: ./my_program: No such file or directory 201 | \end{lstlisting} 202 | 203 | 出现该错误信息有两种可能:在当前目录中确实没有叫做\textit{my\_program}的程序,或者\textit{my\_program}的第一行没有给出Perl的正确路径。你需要好好检查一下,尤其是当运行来源于CPAN(参看\autoref{chap:chapteraa})的程序时,这些程序第一行中Perl的路径往往都不相同。另外,如果你键入 \verb|my_program|,可能会得到这样的错误信息: 204 | 205 | \begin{lstlisting}[language=] 206 | bash: my_program: command not found 207 | \end{lstlisting} 208 | 209 | 这表示操作系统找不到该程序。但它就在当前目录中呀!问题可能出在你的 \verb|$PATH|或 \verb|$path|环境变量并不包含当前目录,所以系统根本就没在当前路径中寻找该程序。这种情况下,根据使用的shell不同,你需要修改 \verb|$PATH|或 \verb|$path|环境变量,或者键入 \verb|./my_program|而非 \verb|my_program|。 210 | 211 | \subsection{Macs} 212 | 在Mac系统中,保存Perl程序时,推荐使用的方式是作为“droplets”;MacPerl文档中给出了简要的说明。基本上你只需要用MacPerl应用程序打开Perl程序,另存为时选择Droplet类型选项即可。 213 | 214 | 你可以通过拖放文件到droplet上来把它作为输入文件(通过 \verb|@ARGV|数组,参看\autoref{chap:chapter6}的讨论)。 215 | 216 | 最新的MacOS X其实是一个Unix系统,因此你也可以通过命令行来运行Perl程序,就像前述在Unix和Linux系统中的操作那样。 217 | 218 | \subsection{Windows} 219 | 在Windows系统中,Perl程序通常和\textit{.pl}文件名后缀相关联。在Perl安装过程中,通过修改注册表的设置实现了这种关联。有了这种关联,在MS-DOS命令窗口中,你就可以键入 \verb|this_program|或者 \verb|perl this_program.pl|来运行\textit{this\_program.pl}程序。Windows中有一个PATH变量,存储着系统从中寻找程序的文件夹,在Perl安装过程中,该变量被修改以便收录包含Perl应用程序的文件夹的路径,该路径通常为\textit{c:$\backslash$perl}。如果你想运行一个Perl程序,该程序所在的文件夹并为被PATH变量所收录,你可以键入该程序的完整路径,如\textit{perl c:$\backslash$windows$\backslash$desktop$\backslash$my\_program.pl}. 220 | 221 | \section{文本编辑器} 222 | 既然已经设置好了计算机,也安装上了Perl,接下来就需要选择一个文本编辑器并学习其基本知识了。文本编辑器用来键入程序等文档,并把文档内容保存到文件中。所以要编写一个Perl程序,你需要使用一个文本编辑器。尽管某些文本编辑器学习起来比较容易,但如果以前你从未使用过文本编辑器,学习起来工作量也是不小的。下面是一些最为流行的编辑器,此处依然按照操作系统的类型进行介绍: 223 | 224 | \noindent 225 | \textcolor{black}{Unix或Linux} 226 | \begin{adjustwidth}{4em}{} 227 | vi和Emacs都是比较复杂(但是很棒)的编辑器。pico、xedit和其他一些编辑器(nedit、gedit、kedit)非常容易使用,学习起来也不难,但功能并不是很强大。在StarOffice\footnote{译者注:现在比较流行的是OpenOffice和LibreOffice。}中包含了一个和Microsoft Word相兼容的编辑器,而且是免费的(但一定要确保把文件保存为ASCII或者纯文本)。 228 | \end{adjustwidth} 229 | 230 | \noindent 231 | \textcolor{black}{Macintosh} 232 | \begin{adjustwidth}{4em}{} 233 | MacPerl内置的编辑器就很不错。有一个很好的收费编辑器叫做BBEdit,它对Perl进行了优化,相对应的免费版本叫做BBEdit Lite。你也可以使用共享编辑器Alpha或Microsoft Word(确保把文件保存为ASCII纯文本)。 234 | \end{adjustwidth} 235 | 236 | \noindent 237 | \textcolor{black}{Windows} 238 | \begin{adjustwidth}{4em}{} 239 | Notepad已经比较流行了,用起来也令人满意;Microsoft Word也是可以使用的,但一定要保存为ASCII或纯文本。在基于Windows的计算机中进行Perl编程,强烈推荐使用Emacs的Windows版本,虽然学习起来有些复杂。当然,还有好多其他的编辑器,我就使用Unix编辑器vi的一个免费版本——移植到Windows中的Vim。 240 | \end{adjustwidth} 241 | 242 | 还有许多其他的文本编辑器可以使用。许多计算机上都有多种编辑器可供选择。(有些程序员在他们的职业生涯中会试图编写一个编辑器,或者对已有的编辑器进行某些功能上的扩展,所以可供选择的编辑器真的是非常众多的。) 243 | 244 | 有些编辑器非常容易学习和使用;而有些编辑器则有众多的特性、相应的指南书籍、讨论组和网站等,学习它们还是要花费一定精力的。如果你是一个程序员菜鸟,不要自找麻烦,选择一个易用的编辑器吧。日后,如果你喜欢冒险,可以进一步学习使用一个“神”级的编辑器,它的某些特性会让你事半功倍。不知道在你的计算机中有哪些可用的编辑器?可以向程序员或其他用户咨询一下,或者去查阅计算机系统中附带的文档。 245 | 246 | \section{寻求帮助} 247 | 确保你有必需的文档。如果你向前述那样安装了Perl,作为Perl默认安装的一部分,文档已经安装到了计算机中,而Perl发行版中附带的指南解释了如何去获取这些文档。还有一个很棒的在线文档,可以在Perl网站主页上找到它。 248 | 249 | 各种编程资源是寻找编程问题答案的好地方,而Perl的资源对使用Perl编程来说是必需的。去\autoref{chap:chapteraa}看一下吧,从中你可以找到书籍、在线文档、可用的程序、新闻组、存档、期刊和会议等各种资源。 250 | 251 | 既然你已经开始编程,你将接触到最重要的书籍、网站、网络新闻组及其可搜索的存档、当地的大师(附近该方面的专家)以及程序文档。这些文档包括程序手册(打印版或在线版)和常见问答集(FAQs)。 252 | 253 | 多数编程语言都有一个标准的文档集,包括语言定义和使用的完整说明。Perl的该文档集作为在线手册包含在了程序中。尽管编程手册通常写的不咋地,但最好是做好不得不面并“生啃”它们的准备。视若无睹、充耳不闻的能力有时候也是一种宝贵的财富。Perl的手册并不是很糟糕,它最大的问题就是,像其他语言的手册一样,把所有的细节都放在了里面,所以刚一开始可能会有种卷帙浩繁的感觉。不过,教程文档可以帮助初学者对Perl文档进行梳理,这绝对是初学者的福音。 254 | 255 | 最后,我极力主张程序员菜鸟去找一些经验丰富的Perl程序员,他们可以帮你解决一些偶尔遇到的问题。他可以是课程的教师或助教、同事,或者是沦落到当地计算机商店的某个人、在在线新闻组(有专门针对Perl初学者的新闻组)中回答你提问的那个人。在你的初学阶段,偶然和一个经验丰富的用户进行的交谈,会使你避免数个小时钻牛角尖的苦思冥想,这是非常有可能的。大部分程序员都非常乐意向初学者伸出援手,或者提供一定的建议。在编程界,友好、学术的气氛十分盛行。 256 | 257 | 但是还有一个警告:如果有人重复提问可以在FAQs或其他标准文档中可以找到答案的问题,这往往会激怒那些专家们。对于这种类型的问题,你有时会看到RTFM——Read The F(ine) Manual\footnote{译者注:RTFM: Read The F***ing Manual。与之类似的还有STFW: Search The F***ing Web等。}——的答复。所以在重复提问之前,一定要去FAQs中查看一下是否已有解答,以避免浪费别人宝贵的时间。 258 | 259 | (我忍不住要提起一件偶然发生的轶事。)在我学习编程时接受的第一个任务中,有一个问题令我寸步难行,而这个问题看上去并没有很明显的解决方案。于是我向被公认为实验室里最好的程序员求助。我对遇到的困境详细得进行了描述,而他则耐心得聆听着。当我解释完后,他笑着向我说道:“男儿有泪不轻谈,自力更生当为先!”听到此话,我不免有些垂头丧气,丈二和尚摸不着头脑。但完全想不到的是,他给出的建议完全是在假装深沉,而他最终也向我进行了解释,并指点我找到了解决办法。 260 | -------------------------------------------------------------------------------- /Chapters/chapter3.tex: -------------------------------------------------------------------------------- 1 | \chapter{编程的艺术} 2 | \label{chap:chapter3} 3 | \minitoc 4 | 5 | 本章将概述程序员是如何完成他们的任务的。如果你已经安装了Perl,而且想立即编写生物信息学中的实用程序,可以跳过本章直接阅读\autoref{chap:chapter4}。 6 | 7 | 初进生物学实验室的人对各种试管仪器会有一种莫名的崇拜,与之类似,刚刚接触编程的初学者也会对程序员的世界充满了好奇,认为它们如同一个充满了怪异术语和高深技能的神秘黑盒子。为了让读者尽快融入这个大家庭,我会对重要的知识和技能进行简短的介绍,每个程序员都要学习并使用到这些内容。其中有两个是最为重要的,一个是优秀程序员在实践过程中所使用的编程策略,另一个则是如何找到在编程过程中遇到的各种问题的答案。通过一些简单的描述性实例的学习,我们将总结出程序员寻找问题解决方案的方法。\autoref{chap:chapteraa}中罗列了一些非常好的Perl和生物信息学的资源,在解决实践过程中遇到的问题时,它们会对你有所帮助的。 8 | 9 | \section{学习编程的不同方法} 10 | 学习编程的最佳方法是什么?答案取决于你要完成的任务。有许多引领你入门的方法,比如: 11 | 12 | \begin{itemize} 13 | \item 参加各种类型的学习班 14 | \item 阅读像本书这样的教程性的书籍 15 | \item 死啃编程手册 16 | \item 拜其他的程序员为师 17 | \item 研究你所需要的一个程序 18 | \item 尝试上述几种或所有方法,直到对编程能够驾轻就熟为止 19 | \end{itemize} 20 | 21 | 答案还取决于你打算如何学习编程。有人喜欢参加培训班,因为培训班会把知识点整理得有条有理,同时授课老师也会解答学生的各种问题。另外一些人则可能会更加喜欢自学。 22 | 23 | 不管是那种学习编程的方法,有些东西却是共通的。如果以前你从未写过程序,下面几个小节的内容是你首先必须要了解的。 24 | 25 | \section{编辑-运行-修正(还有保存)} 26 | 就像跳舞、弹琴、烹饪或者其他家庭中的活动一样,学习编程需要你实际动手去做,这是最重要的一点。你可以阅读源码,但如果不动手去编写、调试程序,你永远也无法真正编写出程序。 27 | 28 | 当学习Perl语言编程时,你要弄明白Perl是如何工作的,就像在接下来的几章中你将看到的那样。此外,你还要学习大量的程序实例。在接下来几章的最后有一些练习题供你练手,此时你要尝试编写自己的程序。只有这样的实战练习才能使你成长为一个真正的程序员。 29 | 30 | 为了帮助你写出第一个程序,同时弄明白它的工作原理,我会对一些内容进行简要的概述,这些在编写程序过程中都是至关重要的。 31 | 32 | 你用计算机做什么?程序员使用计算机时,大部分工作都无外乎在编辑器中编写或修正程序,然后运行程序并检查它的运行状态,再根据运行状态回去检查和修正程序,如此循环往复。对于一个程序员来说,通常一半以上的时间都用在了编辑程序上。 33 | 34 | \subsection{保存和备份} 35 | 即使你只写了几行代码,也一定要保存它,请牢记这一点。实际上,在编辑代码的过程中,应该有定期保存程序每一个版本的观念。这样在进行了大量编辑后,即使计算机崩溃了,你也不会丢失数个小时的劳动成果。此外,要确保在另一个磁盘上对你的工作进行了备份。如果你的硬盘损坏了,上面的所有数据都会丢失。所以,对你的工作进行定期(每日)备份至关重要,可以备份到磁带、软盘、ZIP磁盘片、另一个硬盘、光盘等其他媒介上。不管怎样,当你的磁盘损坏时,因为备份的存在,你的工作内容将不会全部丢失。 36 | 37 | 除了备份硬盘,还应记住,要对你的程序进行定期保存,保留它的每一个版本\footnote{译者注:推荐使用Git等版本控制工具。}。这样,当你需要回退到程序的历史版本时,你可以轻松做到。 38 | 39 | 还有一点,一定要确保你的备份确实可以使用。举个例子,如果你把数据备份到了磁带上,每次备份一段时间后,都要尝试从磁带上恢复文件,来确保软件以及磁带本身都可以正常使用。以防系统崩溃,你可能要定期把程序打印出来(“白纸黑字”),这样会多一份保险。最后一点,比较好的一个策略是不要把鸡蛋放在一个篮子里,把你的备份放在一个远离计算机的地方,这样即使遇到火灾或者其他灾难,你仍有备份可用。 40 | 41 | \subsection{错误信息} 42 | 修复错误是编写程序过程中的基本步骤。在编辑完一个程序后,接下来你要做的就是运行它,看看程序能否正常工作。多数情况下,你会发现有一些像忘记添加分号这样的拼写错误。结果可想而知,因为程序中存在语法错误,运行时你会看到系统给出的各种错误信息。这时,你将不得不仔细查看错误信息,去重新编辑程序以消除这些讨厌的错误。 43 | 44 | 有时,这些错误信息是比较隐秘的。这种错误导致的结果就是,Perl解释器很难精确定位错误所在,它仅知道某个地方出错了,也仅此而已。所以,它会猜测问题的根源所在,在这个过程中,它可能会给出一些与错误本身无关的信息。 45 | 46 | 牢记一点,在处理错误信息时,要对后面的视而不见,只关注第一个或前两个错误信息即可。修复这一两个最先出现的问题,然后尝试重新运行一次程序。错误信息通常都比较冗长,甚至可能有数页之多。除了第一个错误,把其他的都忽略掉吧!还有一点需要注意,第一个错误信息中给出的代码行号通常都是正确的,有时它会有一行之差,但不会偏差太大。稍后,我们会练习制作错误并解读错误信息。 47 | 48 | \subsection{调试} 49 | 也许你编写了一个程序,Perl解释器可以正常运行它而没有任何报错。然而你却发现,程序并没有像你期望的那样工作。现在,你需要回过头来,去查阅程序代码,尝试找出问题所在。 50 | 51 | 也许你仅仅是犯了一个低级错误,比如,本应该使用减法的地方你却用了加法。也有可能你误解了文档中的内容,以错误的方式编写了程序(重新阅读文档吧)。还有可能你对要完成的任务考虑不周、计划不足(想清楚具体策略后重新编写相应部分的代码吧)。有时你并不能找到问题所在,那就四处求助吧(可以尝试在新闻组存档和FAQs中搜索一下,或者向同事求助)。 52 | 53 | 对于那些难于发现的错误,有一个叫做调试器的程序专门对付它们。调试器允许你一步一步运行程序,看看在运行过程中到底发生了什么。(\autoref{chap:chapter6}中对Perl的调试器进行了深入讲解。) 54 | 55 | 当然,还有其他工具或者技术可供选用。比如,在程序中加入 \verb|print|语句,把那些中间值或中间结果输出出来,这也可以帮助你检查程序。此外,也有专门的程序,在程序运行过程中它会对其进行观察,然后输出相应的报告,比如,告诉你程序的哪一部分消耗的时间最多。所有这些工具,以及其他类似的工具,对于编程来说都是必需的,一定要学会如何去使用它们。 56 | 57 | \section{编程文化} 58 | 编程是解决问题的实践,它是一个重复、循序渐进的过程。单打独斗未尝不可,但它通常是一个群体性的活动(让很多初学者惊讶吧)。它需要你培养特定的解决问题的技能,还要求你学习一些新的工具。编程有时难以捉摸,会让人厌恶至极。另一方面,对于那些有能力的程序员来说,当成功编写出程序后,也会有极大的成就感。 59 | 60 | 计算机程序无所不是,从一无是处,到给人美学及理智上的刺激,再到催生全新的知识。它们是如此美丽!(它们也有可能是破坏性的、愚蠢的、糊涂的甚至狠毒的,毕竟是人类创造了它们。)编写程序是一个重复、循序渐进的构建过程,从开始时的只砖片瓦,到最后的高楼大厦,看到这样的过程,谁能不由衷自豪呢?对于初学者来说,编程中的这种循序渐进的过程,简直就是一步一步学习语言的过程的缩影。 61 | 62 | 自从20世纪中期人们开始编写并积累程序,编程文化就在不断形成。慢慢地,我们积累出了坚固的编程文化底蕴。程序会反映出其他程序对它的影响,这就是文化氛围的力量,而程序员菜鸟也会从中受益良多。 63 | 64 | \subsection{开源程序} 65 | 编程越来越重要,随之就产生了经济价值,导致的后果便是,好多程序的源代码被隐藏了起来,以此来保存它的商业价值、提升竞争力。 66 | 67 | 然而,对于那些最好、最有用的程序的源代码来说,每个人都可以免费获取进行查阅。可以免费获取的源代码通常被称作开源。(对于开源程序代码来说,有各种各样的版权附加其上,但这些版权都允许任何人去查阅源代码。)开源运动对待程序源代码的态度,和科学家发表研究结果的态度非常类似:公布于众以供他人检查和讨论。 68 | 69 | 对于程序员菜鸟来说,这些程序的源代码非常有用,因为从中可以学习到专业程序员是如何编写代码的。开源的程序包括Perl解释器和大量的Perl代码、Linux操作系统、Apache网络服务器、Netscape网页浏览器、sendmail邮件传输代理等等。 70 | 71 | \section{编程策略} 72 | 为了让初学者对编程过程有一个直观的认识,通过几个教学性的实例研究,让我们看看程序员高手是如何思考来解决问题的。 73 | 74 | 假设你从测序实验室中拿到了一大批DNA序列,现在想对其中的调控元件\footnote{所谓调控元件是指细胞用来控制编码区域的DNA区段,它将帮助决定这段编码区域是否以及何时翻译成蛋白质。}进行计数。如果你是一个专业的生物信息学程序员,你会怎么做?有两种可能的解决策略:找一个现成的程序,或者自己动手写一个。 75 | 76 | 非常有可能已经有这样一个程序,正好是你需要的,可以正常运行而且是免费的。大多数时候,在网络上都可以找到你所需要的程序,从而避免了重复发明轮子的代价。这就是性价比最高的编程——最小的工作量换来了最大的成果。图书馆里呆一天,胜过实验室里忙半年,(他山之石可以攻玉)这是实验工作者的经典谚语。 77 | 78 | 时刻注意收集整理可用的程序,这是编程艺术中很重要的一部分。之后,你就可以使用合适的程序来完成自己的工作,或者对已有的程序进行修改来满足自己的需要。当然,还是要注意版权声明的,但是大部分都是免费的,尤其是针对学术和非营利机构。大部分的Perl模块都有版权,虽然有一定的限制,但都允许你使用并修改它。版权的细节可以在Perl网站上可以,也会和特定的模块附在一起。 79 | 80 | 如何找到这些已经存在且免费的很棒的程序呢?Perl社区已经把这样的程序代码收集整理起来,放在了Perl综合典藏网(CPAN)上,网址是 \href{http://www.CPAN.org}{http://www.CPAN.org}。去随便看看吧,你会发现它是按照主题进行整理的,所以可以快速查找网络、统计或图形等主题的程序。在我们这个例子中,你需要查找BioPerl模块,它包含了非常多的实用的生物信息学功能模块。所谓模块就是Perl代码的集合,你可以在Perl程序中轻松地加载并使用它们。 81 | 82 | 最有用的代码就是那些模块,它把许多相关的功能整合在了一起。在编写新程序的过程中,这些模块给予我们了极大的灵活性。尽管你仍然不得不去编程,但工作量已经大大减少,只需利用它们拼凑出一个完成的程序即可。还是以寻找调控元件为例,通过搜索你可能会发现一个方便使用的模块,它包含了所有的调控元件,还附带有相应的代码——给定调控元件后可以在DNA序列库中进行查找!而你需要做的仅仅是把这些现成的代码整合起来,给它提供一个DNA库,然后只需要很少的编程你就可以完成任务了。 83 | 84 | 还有好多其他地方可以找到现成的代码。你可以使用自己最喜欢的搜索引擎在网上进行搜索,可以通过浏览生物信息学链接合集来寻找程序,也可以在我们提到的新闻组、相关专家等资源那里进行寻找。 85 | 86 | 如果你没有找到问题的突破点,并且你也明白,自己写程序需要花费大量的时间,你就会想去图书馆的文献中自己查找一下,或者在图书管理员的帮助下进行查找。你可以在MEDLINE数据库中查找调控元件相关的文章,这些文章中通常会刊登有作者使用的代码(一个用Perl语言编写的程序)。你也可以在会议记录、书籍和期刊中进行查找。会议和商品展销会都是不错的地方,可以去逛逛,在那里你可以和其他人进行交流、向他们进行提问。 87 | 88 | 多数情况下,你都会如愿以偿,尽管你也有一定的付出,但是你为自己和实验室节省了数天、数周甚至数月的时间。 89 | 90 | 但是,针对修改现成的代码还有一句警告:有时修改现成的代码可能会比从头写一个完整的程序更加困难,这取决于有多少代码需要修改。为什么会这样呢?不同的程序有不同的作者,要弄明白程序各个部分的作用,有时候还是比较困难的。如果你都不理解程序第一部分使用的方法,修改又从何谈起?(稍后,我们会详谈如何编写可读的代码,以及在代码中添加注释的重要性。)这个因素本身在编程代价中就占了很大一部分。许多程序阅读、理解起来非常困难,因此也难以维护。而基于种种原因,测试这样的程序也会非常困难。要确保你的修改能够正常工作,有时会花费大量的时间与精力。 91 | 92 | 好吧,如果说你已经用三天的时间来寻找现成的程序,最终却一无所获,(也许有一个现成的程序,但是需要三万美元才能买到,这已经超出了你的预算;同时你身边的程序员专家忙得不可开交,也没有时间来给你写程序。)那你将不得不自己动手写一个程序了。 93 | 94 | 如何从头写一个在DNA序列中计算调控元件数目的程序呢?听我慢慢道来。 95 | 96 | \section{编程过程} 97 | 现在,你被指派去写一个在DNA序列中计算调控元件数目的程序。如果以前从未编写过程序,那你很可能会毫无头绪。为了写出这个程序,我们先讨论一下你需要知道的内容。 98 | 99 | 我们将逐步进行,这里是对这些步骤的简要概述: 100 | 101 | \begin{enumerate} 102 | \item 确定必需的输入,比如用户提供的数据或信息。 103 | \item 对程序进行整体构思,包括程序计算输出结果的基本方法——算法。 104 | \item 决定结果的输出形式;比如,输出到文件,或者进行图形化展示。 105 | \item 通过添加更多的细节改善整体构思。 106 | \item 编写Perl程序代码。 107 | \end{enumerate} 108 | 109 | 对于更短或者更长的程序来说,这些步骤可能有所不同,但对于你的大多数编程来说,这就是最基本的步骤。 110 | 111 | \subsection{构思阶段} 112 | 首先,对于程序如何工作,你需要酝酿一个计划。这是对于程序的总体构思,而且是一个关键的步骤,这样的构思通常在实际开始编写程序之前就要完成。编程常和厨房中的食谱相类比,毕竟它们都是完成某项任务的特定操作指南。比如,你要知道程序需要什么样的输入和输出。在我们这个例子中,输入的是新的DNA序列。接下来,你需要一个策略,就是程序如何对输入进行计算处理得到我们想要的输出。 113 | 114 | 在我们这个例子中,程序首先要从用户那里收集信息:也就是说,DNA序列在哪里?(这样的信息可以是存储DNA序列文件的文件名。)程序需要用户键入数据文件的文件名,可能是在计算机屏幕上进行输入,有可能是通过网页进行提交。然后,程序需要检查一下文件是否存在(有时文件并不存在,这时有发生,比如用户拼错了文件名,此时程序要给出警示),然后打开这个文件,在进行计算处理之前读入DNA序列。 115 | 116 | 该步骤虽然简单,但仍值得进行一定的注解。你可以直接把DNA序列放在程序代码中,这样就不用去写这部分代码了。但是把程序设计成读入DNA序列还是非常有用的,因为当你拿到新的DNA序列时就不用每次都重写程序了。这种想法非常简单,甚至是显而易见的,但却非常有效。 117 | 118 | 程序用来处理的数据叫做输入。输入可以有多种来源,如文件、其他程序、运行程序的用户、网站上填写的表单、电子邮件信息等。多数程序都读入某种形式的输入,但也有程序没有输入。 119 | 120 | 让我们把调控元件添加到实际的程序代码中吧。就像我们处理DNA序列一样,你可以从文件中读入调控元件;文件中存储的是调控元件的列表,这样程序就可以查找不同的调控元件了。但是,在这种情况下,我们要使用的调控元件列表并不会改变,那为什么还要麻烦用户输入这样一个文件的文件名呢? 121 | 122 | 既然有了DNA序列和调控元件列表,我们就要概括地决定程序如何在DNA序列中查找每一个调控元件。这一步显然是最为关键的一步,它将一步定乾坤。比如,如果程序的运行速度是一个重要的考虑因素,你就要让程序运行的足够快。 123 | 124 | 在这个工作中,此处的问题就是要选择正确的算法。算法就是处理问题的构思(马上我就会对此进行详述)。比如,你打算交替读入调控元件,在读入下一个调控元件之前,从头到尾在DNA中对当前元件进行查找。或者也有可能,你打算对DNA序列只进行一次从头到尾的读取,然后在DNA序列的每一个位置对每一个调控元件都进行一次查找,看看此处是否存在该调控元件。这两种方法有没有优劣之别?是否可以先对调控元件列表进行排序,这样查找就可以更快一些?此时,我们会说算法的选择至关重要。 125 | 126 | 构思的最后部分就是把结果以某种形式输出出来。也许你想把结果展示在网页上,或者在计算机屏幕上输出简单的列表,或者保存到一个可供打印的文件中,也可能是上述所有形式。在这个阶段,你可能需要让用户提供一个文件名来保存输出。 127 | 128 | 这就是如何展示结果的问题,这也确实是一个至关重要的问题。最理想的解决办法就是以某种方式把结果展示出来,这种方式使得用户仅需一瞥就可抓住计算过程中的重要特性。你可以使用图形、颜色、地图,甚至可以把异常结果用跳跃的小球标示出来,总之有很多方法。如果一个程序的输出结果很难解读,显然这并不是一个好的程序。事实上,让重要结果很难寻找或理解的输出,会彻底抹杀掉你在编写这个优雅程序过程中的所有付出。现在说的已经足够多了。 129 | 130 | 有非常多的策略,程序员可以使用这些策略来帮助他们进行好的整体构思。通常情况下,除了最小的程序外,所有的程序都会被分割成多个微小但却互相关联的部分。(在后续章节的学习中,我们会看到好多这样的例子。)每个部分是什么?它们之间如何进行关联?软件工程这个领域处理的就是这样的问题。此时此刻,我只想指出它们是非常重要的,提及一些程序员实现构思的途径。 131 | 132 | 有许多构思的方法,每种方法都有各自的拥护者。最好的办法就是了解一下有哪些可用的方法,并在处理任务时使用最合适的方法。比如,在本书中,我会教授一种叫做命令式编程的编程范式,它的理念是把一个问题分割成相互配合的程序或子程序(参看\autoref{chap:chapter6}),这就是所谓的结构化设计。另外一种流行的编程范式叫做面向对象编程,Perl也支持这种范式。 133 | 134 | 如果你在一个大的项目中和一堆程序员共事,构思阶段可能会非常正式,甚至可能会由其他人来完成,而不是由程序员自己来完成。另一方面,你可能会发现有些程序员一上来就编写程序,他们会边写程序边制定计划。没有一种适用于所有程序员的方法。(萝卜白菜,各有所爱。)但不管你怎样实现它,作为初学者,在开始编写代码之前,你最好还是要在头脑中有一定的构思。 135 | 136 | \subsection{算法} 137 | 算法就是构思、计划,计算机程序的计算过程。(如果不使用正式的数学语言,这确实是一个难以定义的术语,不过此处也算是一个合理的定义。)一个算法要通过使用特定的计算机语言编程来实现,但算法本身是计算的思路。使用伪代码可以对算法进行很好的表述,它不是一个真正的计算机程序,但却展示了程序的思路。 138 | 139 | 大部分程序都只做简单的事情。它们从用户那里获取文件名,打开文件并读入数据,然后进行简单的计算后把结果展示出来。此处你将学习算法的类型。 140 | 141 | 不管怎样,算法学都是一门深奥、成果卓越的学科,对生物信息学也产生了深远的影响。通过算法,可以找到新的分析生物学数据的方法,发现新的科学成果。在生物学中,确实有不少这样的问题,这些问题的解决必须要等待新算法的发明。 142 | 143 | 算法学中有许多巧妙的技术。作为一个程序员菜鸟,现在还没有必要为这些担心。在这个阶段,本章作为编程方面的入门教程中的导言章节,对算法方法进行深入讲解并不明智。你的首要任务就是学习如何用某种编程语言进行编程。当然,如果对算法念念不忘,你可以去学习相关的技术。买一本像样的教科书放在身边作为参考书,对一个严谨的程序员来说绝对是值得的。(参看\autoref{chap:chapteraa})。 144 | 145 | 在现在这个例子中,就是在DNA序列中对调控元件进行计数的这个例子,我给出了一种策略:交替读取调控元件,在处理下一个调控元件之前,在DNA序列中进行从头到尾的查找。其他算法也是可以的。事实上,这是字符串匹配这个普遍性问题的一个实例。字符串匹配在生物信息学中最重要的一部分,而对它的研究已经催生了许多巧妙的算法。 146 | 147 | 算法常常和这样的问题或技术一起被提起,并且也有许多资料也可查阅。对于实用主义的程序员来说,最无价的材料莫过于用特定语言写成的算法代码,你可以直接把他们用在自己的程序中。可以从\autoref{chap:chapteraa} 开始,使用其中列出的代码合集和书籍,能够相对轻松的把许多算法技术整合到你的Perl代码中。 148 | 149 | \subsection{伪代码和代码} 150 | 现在你有了整体构思,包括输入、算法和输出。你该如何把这些想法应用到程序的设计中呢? 151 | 152 | 一个常用的实践策略就是从编写伪代码开始。伪代码是一种非正式的程序,其中没有具体的细节,也不需要遵守正式的语法规则。\footnote{语法规则指的是就是语法的规则。根据英语语法,“Go to school”是对的,而“School go to”是错的。程序语言也有这样的语法规则。}伪代码不会向程序那样实际运行,它的目的仅仅是以一种快速、非正式的方法把程序的整体构思具体化而已。 153 | 154 | 举个例子,在实际的Perl程序中你可能会写一些叫做子程序的代码(参看\autoref{chap:chapter6})。在这个例子中,子程序会从用户的键入内容中获取答案;这个子程序可能会像这样: 155 | 156 | \begin{lstlisting} 157 | sub getanswer { 158 | print "Type in your answer here :"; 159 | my $answer = ; 160 | chomp $answer; 161 | return $answer; 162 | } 163 | \end{lstlisting} 164 | 165 | 但是在伪代码中,你可能仅仅需要这样写: 166 | 167 | \begin{lstlisting} 168 | getanswer 169 | \end{lstlisting} 170 | 171 | 至于细节日后再说。 172 | 173 | 对于上面讨论的内容,这里是程序伪代码的一个例子: 174 | 175 | \begin{lstlisting} 176 | get the name of DNAfile from the user 177 | 178 | read in the DNA from the DNAfile 179 | 180 | for each regulatory element 181 | if element is in DNA, then 182 | add one to the count 183 | 184 | print count 185 | \end{lstlisting} 186 | 187 | \subsection{注释} 188 | 注释是Perl源代码的一部分,旨在帮助理解程序的所作所为。从\#开始到行末的所有内容都被看作注释,会被Perl解释器忽略掉。(唯一的例外是大多数Perl程序的第一行,是像这样的一行: \verb|#!/usr/bin/perl|;参看\autoref{chap:chapter4}中的\autoref{sec:section4.2.3}。) 189 | 190 | 注释对于保持代码可用是非常重要的。注释通常包括对于程序主要目的和整体构思的讨论、如何使用程序的实例,以及散布程序各处的细节注解,来解释为什么那段代码在这里、它是做什么用的。一般来说,好的程序员会把好的注释作为程序完整的一部分来进行编写。在本书的所有编程实例中,你都会看到注释。 191 | 192 | 你的代码不只会被计算机读入,也会被人查阅,这一点非常重要! 193 | 194 | 在调试行为异常的程序时,注释往往非常有用。如果无法确认程序出错的地方,你可以尝试选择性地注释掉不同部分的代码。如果你发现当注释掉某一部分代码后问题消失了,就可以把出错范围缩小到你注释掉的那部分代码,当这部分代码足够短时,你就找到问题的所在了。这常常是一个非常有用的调试方法。 195 | 196 | 在你把伪代码转换成Perl源代码时,也可以使用注释。伪代码不是Perl代码,所以对于任何没有注释掉的伪代码,Perl解释器都会报错。在伪代码所在行的开头加上\#就可以把它注释掉了: 197 | 198 | \begin{lstlisting} 199 | #get the name of DNAfile from the user 200 | 201 | #read in the DNA from the DNAfile 202 | 203 | #for each regulatory element 204 | # if element is in DNA, then 205 | # add one to the count 206 | 207 | #print count 208 | \end{lstlisting} 209 | 210 | 在你把伪代码扩展成Perl代码时,移除\#就可以对Perl代码取消注释了。用这种方法时,Perl代码和伪代码会混杂在一起,但你可以正常运行或测试Perl代码部分,因为Perl解释器会把注释行简单地忽略掉。 211 | 212 | 你可以把伪代码整个保留在程序中,只需把它们注释掉即可。这种做法会保留下程序构思的提纲,当你或其他人试图阅读或修改代码时它们就会派上用场。 213 | 214 | 现在我们已经可以开始进行真正的Perl编程了。在\autoref{chap:chapter4}中,你会学习Perl的语法规则,并开始用Perl进行编程。当你开始编程时,牢记首先要对你的程序进行构思,之后才是你将花费大量时间重复去做的事情:编辑程序、运行程序,然后修正程序。 215 | -------------------------------------------------------------------------------- /Chapters/chapter7.tex: -------------------------------------------------------------------------------- 1 | \chapter{突变和随机化} 2 | \label{chap:chapter7} 3 | \minitoc 4 | 5 | 正如每一个生物学家所知道的那样,突变是生物学中的一个基本主题。在细胞中,DNA上的突变时时刻刻都在发生着。绝大多数突变都不影响蛋白质行使功能,是良性的。也有一部分突变确实会影响到蛋白质,导致肿瘤等疾病的发生。突变也会造成后代无法存活,它们在发育过程中就会死亡;有时,突变也能导致进化的改变。许多细胞都有很复杂的机制,来对突变进行修复。 6 | 7 | DNA的突变可能来源于辐射、化学制剂、复制错误等原因。我们将使用Perl的随机数生成器,把突变看成随机化事件来对其进行建模。 8 | 9 | 随机化是一种计算机技术,它经常会在日常使用的密码等程序中突然出现,比如你想生成一个不容易被猜到的密码。但随机化也是算法中的一个重要分支:许多最快的算法都用到了随机化。 10 | 11 | 使用随机化,可以来模拟和研究DNA突变的机制,以及突变对相关蛋白质生物活性的影响。模拟是研究系统和预测结果的一个强有力的工具,随机化让你可以更好地模拟生物系统中的“有序混沌”。使用计算机程序来模拟突变,这将有助于进化、疾病以及分裂和DNA修复机制等基本细胞过程的研究。细胞发育和功能的计算机模型,现在还在它们的早起阶段,在未来的几年中它将会更加精确且有用,而突变就是这些模型将要囊括在内的一个基本的生物学机制。 12 | 13 | 从编程技术以及对进化、突变和疾病建模的立场来看,随机化是一个强大的编程技巧,而幸运的是,它非常容易使用。 14 | 15 | 在本章中,我们将要完成以下内容: 16 | 17 | \begin{itemize} 18 | \item 在数组中随机选取一个索引,在字符串中随机选取一个位置:这些是在DNA(或其他数据)中选取随机位置的基本工具 19 | \item 使用随机数对突变进行建模,学习如何随机选取DNA中的一个核苷酸并把它突变成其他(随机)的核苷酸 20 | \item 使用随机数来生成DNA序列数据集,这可以用来研究实际基因组的随机化程度 21 | \item 重复突变DNA来研究在进化过程中突变随时间累积的影响 22 | \end{itemize} 23 | 24 | \section{随机数生成器} 25 | \textit{随机数生成器}是你可以调用的一个子程序。对于大多数实践操作来说,你不需要知道它里面是什么。你从计算机中得到的随机数数值,和真实世界中测量到的随机事件有一定的差别,比如,检测的核衰变事件。有些计算机确实连接着盖革计数器等设备,这样就可以有一个真实随机事件的来源了。但我敢打赌,你的计算机上并没有这样的设备。你有的只是一个代替盖革计数器的算法,它就是随机数生成器。 26 | 27 | 随机数生成器输出的数字并不是真正随机的,因此它们被叫做\textit{伪随机数}。一个随机数生成器,作为一种算法,是可以被预测的。随机数生成器需要一个种子作为输入,通过改变种子,你可以得到一系列不同的(伪)随机数。 28 | 29 | 随机数生成器生成的结果给出的是数值的均匀分布,这是随机化最重要的特性之一,并且很大程度上也决定了要根据期望的随机范围的大小来调整算法的使用。 30 | 31 | 对于随机数生成器来说,另一个要牢记在心的就是你初始化使用的种子本身也应该是随机选择的。如果你每次都使用同样的数字作为种子,那么每次你都将得到同样的“随机数字”序列。(这就并不随机了!)试着选一个具有随机性的种子,比如某些随时间任意改变的计算机事件计算出来的数字。\footnote{即使这样,对于紧要的用途来说,你还是没有跳出如来佛的五指山。除非你小心地选择种子,否则黑客还是可以猜出你是如何选择种子,从而破解你的随机数和密码。本章中使用的生成种子的方法, \verb=time|$$=,是可以被黑客中的“有志青年”所破解的。一个更好的选择是 \verb=time() ^ ($$+<<15))=。如果程序安全非常重要,你就应该好好查阅Perl的文档,以及CPAN中的\textit{Math::Random}和\textit{Math::TrulyRandom}模块。} 32 | 33 | 在接下来的例子中,我使用一个简单的方法来挑选种子,这对于大多数用途来说都是没有问题的。如果你使用随机数对存在紧要的隐私问题的数据(比如病人的记录)进行加密,你应该进一步参阅Perl中关于Perl提供给随机数生成器的几个高级选项的文档。在本书中,我使用的方法对于大多数情况的用途来说都已经足够了。 34 | 35 | \section{使用随机化的一个程序} 36 | \autoref{exam:example7.1}通过一个简单的程序介绍了随机化,它通过随机组合句子的片段来构造一个故事。这并不是一个生物信息学的程序,但是我发现这是学习随机化基础知识的一个有效的方法。你将学习如何从数组中随机选取一个元素,这会在后续突变DNA的程序实例中得到运用。 37 | 38 | 例子声明了几个包含句子片段的数组,然后把它们随机组合成完整的句子。这是一个微不足道的孩子的游戏,但它演示了一些编程要点。 39 | 40 | %\textbf{例7-1:使用随机数的儿童游戏} 41 | \lstinputlisting[label=exam:example7.1,caption={例7.1:使用随机数的儿童游戏}]{./scripts/example7-1.pl} 42 | 43 | 下面是\autoref{exam:example7.1}一些典型的输出: 44 | 45 | \begin{lstlisting}[breaklines=true] 46 | Joe and Moe jumped with Rebecca in New York City. Rebecca exploded Groucho in a dream. Mom ran to Harpo over the rainbow. TV giggled with Joe and Moe over the rainbow. Harpo exploded Joe and Moe at the beach. Robin Hood giggled with Harpo at the beach. 47 | 48 | Type "quit" to quit, or press Enter to continue: 49 | 50 | Harpo put hot sauce into the orange juice of TV before dinner. Dad ran to Groucho in a dream. Joe and Moe put hot sauce into the orange juice of TV in New York City. Joe and Moe giggled with Joe and Moe over the rainbow. TV put hot sauce into the orange juice of Mom just for the fun of it. Robin Hood ran to Robin Hood at the beach. 51 | 52 | Type "quit" to quit, or press Enter to continue: quit 53 | \end{lstlisting} 54 | 55 | 例子的结构非常简单。使用以下语句强制对变量进行声明并开启警告模式: 56 | 57 | \begin{lstlisting} 58 | use strict; 59 | use warnings; 60 | \end{lstlisting} 61 | 62 | 之后,对变量进行声明,并使用值对数组进行初始化。 63 | 64 | \subsection{为随机数生成器设置种子} 65 | 接下来,通过调用内置函数 \verb|srand|,为随机数生成器设置种子。它需要一个参数,就是前面讨论的随机数生成器的种子。如前所述,为了得到一系列不同的随机数,你必须使用不同的种子。尝试把它改成像这样的语句: 66 | 67 | \begin{lstlisting} 68 | srand(100); 69 | \end{lstlisting} 70 | 71 | 然后,多次运行该程序。每次,你都会得到完全相同的结果。\footnote{最新的随机数生成器会自动更改随机数序列,所以如果该实验不成功,很有可能你在使用一个非常新的随机数生成器。然而,有时你想重复一个随机数序列。注意,如果你像 \verb|srand;|这样调用 \verb|srand|,更新版本的Perl会自动给你一个好的种子。}你使用的种子: 72 | 73 | \begin{lstlisting} 74 | time|$$ 75 | \end{lstlisting} 76 | 77 | 每次都会计算返回不同的种子。 78 | 79 | \textit{time}返回代表时间的一个数,\textit{\$\$}返回代表运行的Perl程序的ID(每次你运行程序它都会改变)的一个数,而|表示位元的或运算,它把两个数的位组合起来(更多细节请参看Perl文档)。还有选取种子的其他方法,但就让我们使用最流行的这种方法吧。 80 | 81 | \subsection{控制流} 82 | 程序中的主循环是 \verb|do-until|循环。当你想在每次循环中采取任何行动(比如询问用户是否要继续)之前就做一些事情(比如打印出一个小故事)时,这种循环就非常方便了。 \verb|do-until|循环首先执行代码块中的语句,然后进行测试,决定它是否应该重复执行代码块中的语句。注意,这和你以前见过的其他类型的循环正好相反,它们是先进行测试后执行代码块。 83 | 84 | 既然总是向 \verb|$story|变量上附加内容,那就需要在每次循环的开始先把它清空。忘记需要在特定的地方把以某种形式递增的变量进行重置,这非常常见,所以在你编程时一定要留意这一点。线索就是不断增长的长字符串或大数字。 85 | 86 | \verb|for|循环包含着程序的主要工作。就像你前面看到的那样,这个循环初始化了一个计数器,执行测试,并在代码块的最后对计数器进行递增。 87 | 88 | \subsection{造句} 89 | 在\autoref{exam:example7.1}中,注意造句用的语句蔓延了数行代码。这有一点点复杂,而这正是整个程序的真正内容,所以附加了一些注释帮助理解它。注意语句进行了精心的格式化,这样它就整洁地排列在了八行中。变量名也是进行选择的,这样这个过程就清晰了许多——你使用一个名词、一个动词、一个名词和一个介词短语进行造句。 90 | 91 | 然而,即使是这样,在中括号中也有多层嵌套的表达式,它用来指定数组的位置,要理解这些代码你需要进行一点仔细的分析。你会看到,你用以空格分隔的句子片段构造了一个字符串,并用一个句点和空格将其结束。字符串是通过多次使用点字符串连接操作符构建出来的,这些点字符串连接操作符被放在了每一行的开头,这样就使得整个语句的结构清晰了许多。 92 | 93 | \subsection{随机选取数组的一个元素} 94 | 让我们仔细看看其中一个语句成分选择器吧: 95 | 96 | \begin{lstlisting} 97 | $verbs[int(rand(scalar @verbs))] 98 | \end{lstlisting} 99 | 100 | 对于这种多层嵌套的括号,要由内向外进行阅读和计算。所以包裹在括号最内层的表达式是: 101 | 102 | \begin{lstlisting} 103 | scalar @verbs 104 | \end{lstlisting} 105 | 106 | 从语句前面的注释中你可以看到,内置函数\textit{scalar}返回数组元素的个数。例子中的数组 \verb|@verbs|有七个元素,所以这个表达式返回7。 107 | 108 | 所以现在你得到的是: 109 | 110 | \begin{lstlisting} 111 | $verbs[int(rand(7))] 112 | \end{lstlisting} 113 | 114 | 而嵌套在最内层的表达式就成了: 115 | 116 | \begin{lstlisting} 117 | rand(7) 118 | \end{lstlisting} 119 | 120 | 代码中语句前帮助性的注释提醒你,这个语句返回一个大于0、小于7的(伪)随机数。这个数是一个\textit{浮点数}(有一个分数的十进制数)。回想一下,一个有七个元素的数组的元素索引是从0到6。 121 | 122 | 所以现在你得到的类似于: 123 | 124 | \begin{lstlisting} 125 | $verbs[int(3.47429)] 126 | \end{lstlisting} 127 | 128 | 而你想要对这个表达式进行计算: 129 | 130 | \begin{lstlisting} 131 | int(3.47429) 132 | \end{lstlisting} 133 | 134 | \textit{int}函数会丢掉浮点数的小数部分,仅返回它的整数部分,在这个例子中就是3。 135 | 136 | 所以你来到了最后的一步: 137 | 138 | \begin{lstlisting} 139 | $verbs[3] 140 | \end{lstlisting} 141 | 142 | 这会给你 \verb|@verbs|数组的第四个元素,注释中已经给你了足够的提示。 143 | 144 | \subsection{格式化} 145 | 为了随机选取一个动词,你调用了几个函数: 146 | 147 | \begin{description} 148 | \item[\textcolor{black}{\textit{scalar}}] 确定数组的大小 149 | \item[\textcolor{black}{\textit{rand}}] 从数组大小决定的范围内选取一个随机数字 150 | \item[\textcolor{black}{\textit{int}}] 把\textit{rand}返回的浮点数转变成用于索引数组元素的整数值 151 | \end{description} 152 | 153 | 使用嵌套的括号,这些函数调用被组合到了一行中。有时,这会生成难于阅读的代码,对于作者这种辛苦工作得来的成果,某些吹毛求疵的读者可能会直喊头疼,因为它们并不讨人喜欢。你可以使用一些额外的临时变量,试着重写这些行的代码。比如,你可以这样写: 154 | 155 | \begin{lstlisting} 156 | $verb_array_size = scalar @verbs; 157 | $random_floating_point = rand ( $verb_array_size ); 158 | $random_integer = int $random_floating_point; 159 | $verb = $verbs[$random_integer]; 160 | \end{lstlisting} 161 | 162 | 并且,对其他造句部分也进行类似的改写,最后通过这样的语句你就可以构造出句子了: 163 | 164 | \begin{lstlisting} 165 | $sentence = "$subject $verb $object $prepositional_phrase. "; 166 | \end{lstlisting} 167 | 168 | 这是风格的问题。当你编程时,你总是会进行类似的抉择。\autoref{exam:example7.1}中的排版风格是基于这样的得失权衡:既要把整个任务表达清晰(得),又要避免难于阅读的高度嵌套的函数调用(失)。使用这种排版的另一个原因就是,在后面的程序中,你经常需要从数组中随机选取一个元素,所以你将对这种特殊的函数调用的嵌套习以为常。事实上,如果你将要多次重复同样的事情,你可能会对这样的调用编写一个小的子程序。 169 | 170 | 就像在大多数代码中一样,易读性是这里最重要的因素。你必须要能够阅读和理解代码,不管是你自己的还是别人的代码,这通常都要比实现其他的动人的目标重要,比如最快的速度、使用最少的内存以及最简练的程序。它并不总是很重要,但通常来说最好先把它写的易读一些,之后如果需要的话再返回去尝试提高其速度(或者其他)。你甚至可以把更加易读的代码作为注释写在那儿,这样阅读代码的人就能够对程序以及你是如何提高程序速度(或者其他)的有一个清晰的理解。 171 | 172 | \subsection{计算随机位置的另一种方法} 173 | Perl通常有不同的方法来完成同一个任务。下面就是编写这个随机数选择的另一种方法;它使用的同样的函数调用,但是没有使用小括号: 174 | 175 | \begin{lstlisting} 176 | $verbs[int rand scalar @verbs] 177 | \end{lstlisting} 178 | 179 | 这种函数链在Perl中很常见,其中的每一个函数都需要一个参数。要计算表达式,Perl首先把 \verb|@verbs|作为\textit{scalar}的参数,这会返回数组的大小。然后它把得到的值作为 \verb|rand|的参数,这会返回一个大于 \verb|0|、小于数组大小的浮点数。然后,它把浮点数作为\textit{int}的参数,这会返回小于浮点数的最大整数。换句话说,它计算的数字和用于数组 \verb|@verbs|的下标是完全一样的。 180 | 181 | 为什么Perl允许这样呢?因为这样的计算非常频繁,并且,根据“让计算机干活”的精神,Perl的设计者拉里$\textbullet$沃尔决定让你(以及他自己)免于键入这些括号并使其配对的烦恼。 182 | 183 | 已经走了这么远了,拉里决定为了简单还要再进一步。你可以省略\textit{scalar}和\textit{int}函数的调用,直接使用: 184 | 185 | \begin{lstlisting} 186 | $verbs[rand @verbs] 187 | \end{lstlisting} 188 | 189 | 这里发生了什么?既然\textit{rand}已经期望一个标量值,它就会把 \verb|@verbs|放在一个标量上下文中,也就是简单的返回数组的大小。拉里聪明的设计了数组的下标(当然,它总是整数值),这样当需要下标时,会自动提取浮点数值的整数部分,所以就不需要\textit{int}了。 190 | 191 | \section{模拟DNA突变的程序} 192 | \autoref{exam:example7.1}给你了突变DNA时需要的工具。在接下来的例子中,你将照常使用由字母A、C、G和T构成的字符串来表示DNA。你将在字符串中随机选取位置,然后使用\textit{substr}函数来改变DNA。 193 | 194 | 这次,让我们换一种思路,在给出整个程序之前,首先来编写一些将要使用到的子程序。 195 | 196 | \subsection{伪代码设计} 197 | 从简单的伪代码开始,这是把DNA中一个随机位置上的核苷酸突变成一个随机核苷酸的子程序的设计: 198 | 199 | \begin{enumerate} 200 | \item 选取DNA字符串中一个随机的位置。 201 | \item 选择一个随机的核苷酸。 202 | \item 把DNA随机位置上的核苷酸替换成随机的核苷酸。 203 | \end{enumerate} 204 | 205 | 这看上去简洁且直指要害,所以你决定把前两句分别写成子程序。 206 | \subsubsection{在字符串中选取一个随机位置} 207 | 怎样才能在一个字符串中随机选取一个位置呢?回忆一下,内置函数\textit{length}返回的就是字符串的长度,此外,字符串中的位置是从 \verb|0|到 \verb|length-1|进行编号的,就像数组中的位置一样。所以你可以使用和\autoref{exam:example7.1}一样的通用策略,编写成子程序: 208 | 209 | \begin{lstlisting} 210 | # randomposition 211 | # 212 | # A subroutine to randomly select a position in a string. 213 | # 214 | # WARNING: make sure you call srand to seed the 215 | # random number generator before you call this function. 216 | 217 | sub randomposition { 218 | 219 | my($string) = @_; 220 | 221 | # This expression returns a random number between 0 and length-1, 222 | # which is how the positions in a string are numbered in Perl. 223 | 224 | return int(rand(length($string))); 225 | } 226 | \end{lstlisting} 227 | 228 | 如果不计算注释的话,\textit{randomposition}实际上是一个简短的函数。这和\autoref{exam:example7.1}中选取一个随机的数组元素的想法是一样的。 229 | 230 | 当然,如果你亲自编写这段代码,需要进行一点测试,来看看这个子程序能不能工作: 231 | 232 | \begin{lstlisting} 233 | #!/usr/bin/perl -w 234 | # Test the randomposition subroutine 235 | 236 | my $dna = 'AACCGTTAATGGGCATCGATGCTATGCGAGCT'; 237 | 238 | srand(time|$$); 239 | 240 | for (my $i=0 ; $i < 20 ; ++$i ) { 241 | print randomposition($dna), " "; 242 | } 243 | 244 | print "\n"; 245 | 246 | exit; 247 | 248 | sub randomposition { 249 | my($string) = @_; 250 | return int rand length $string; 251 | } 252 | \end{lstlisting} 253 | 254 | 下面是测试的一些典型输出(你的结果可能会有所不同): 255 | 256 | \begin{lstlisting} 257 | 28 26 20 1 29 7 1 27 2 24 8 1 23 7 13 14 2 12 13 27 258 | \end{lstlisting} 259 | 260 | 注意 \verb|for|循环的新的写法: 261 | 262 | \begin{lstlisting} 263 | for (my $i=0 ; $i < 20 ; ++$i ) { 264 | \end{lstlisting} 265 | 266 | 这里演示了你可以在 \verb|for|循环中使用 \verb|my|对计数器变量(在这个例子中就是 \verb|$i|)进行声明,从而使其进入循环。 267 | 268 | \subsubsection{选择一个随机的核苷酸} 269 | 接下来,让我们写一个子程序,从四个核苷酸中随机选取一个: 270 | 271 | \begin{lstlisting} 272 | # randomnucleotide 273 | # 274 | # A subroutine to randomly select a nucleotide 275 | # 276 | # WARNING: make sure you call srand to seed the 277 | # random number generator before you call this function. 278 | 279 | sub randomnucleotide { 280 | 281 | my(@nucs) = @_; 282 | 283 | # scalar returns the size of an array. 284 | # The elements of the array are numbered 0 to size-1 285 | return $nucs[rand @nucs]; 286 | } 287 | \end{lstlisting} 288 | 289 | 又一次,这个子程序简洁、悦目。(大多数有用的子程序都是这样的,尽管编写一个简短的子程序并不保证它是有用的。事实上,你将会看到还可以对这个子程序进行一点改进。) 290 | 291 | 让我们也对它进行以下测试: 292 | 293 | \begin{lstlisting} 294 | #!/usr/bin/perl -w 295 | # Test the randomnucleotide subroutine 296 | 297 | my @nucleotides = ('A', 'C', 'G', 'T'); 298 | 299 | srand(time|$$); 300 | 301 | for (my $i=0 ; $i < 20 ; ++$i ) { 302 | print randomnucleotide(@nucleotides), " "; 303 | } 304 | 305 | print "\n"; 306 | 307 | exit; 308 | 309 | sub randomnucleotide { 310 | my(@nucs) = @_; 311 | 312 | return $nucs[rand @nucs]; 313 | } 314 | \end{lstlisting} 315 | 316 | 下面是一些典型的输出(它是随机的,所以理所当然,有很大的可能性你的输出会与此不同): 317 | 318 | \begin{lstlisting} 319 | C A A A A T T T T T A C A C T A A G G G 320 | \end{lstlisting} 321 | 322 | \subsubsection{把随机的核苷酸放到随机的位置} 323 | 现在轮到第三个、也是最后一个子程序了,它要进行实际的突变。下面是代码: 324 | 325 | \begin{lstlisting} 326 | # mutate 327 | # 328 | # A subroutine to perform a mutation in a string of DNA 329 | # 330 | 331 | sub mutate { 332 | 333 | my($dna) = @_; 334 | my(@nucleotides) = ('A', 'C', 'G', 'T'); 335 | 336 | # Pick a random position in the DNA 337 | my($position) = randomposition($dna); 338 | 339 | # Pick a random nucleotide 340 | my($newbase) = randomnucleotide(@nucleotides); 341 | 342 | # Insert the random nucleotide into the random position in the DNA. 343 | # The substr arguments mean the following: 344 | # In the string $dna at position $position change 1 character to 345 | # the string in $newbase 346 | substr($dna,$position,1,$newbase); 347 | 348 | return $dna; 349 | } 350 | \end{lstlisting} 351 | 352 | 这里还是一个简短的程序。当你查看它时,会发现它阅读、理解起来都相对比较容易。通过选取一个随机的位置、随机的核苷酸,并把字符串中那个位置的核苷酸替换成那个随机的核苷酸,你实现了突变。(如果你忘记了\textit{substr}是如何使用的,可以参看\autoref{chap:chapterab}或者其他的Perl文档。如果你像我一样,你可能不得不多次查阅文档,尤其是要确保以正确的顺序使用参数。) 353 | 354 | 这里使用的声明变量的风格有点不同。以前是在程序的开头声明变量,而这里则是在第一次使用变量的时候才对它们分别进行声明。每种编程风格都各有利弊。把所有变量放在程序的顶部是一种很好的组织形式,而且对阅读代码也有所帮助;而随用随声明在编写程序时看起来则是一种更加自然的方式。选择权在你手中。 355 | 356 | 此外,注意这个子程序的大部分是如何基于其他的子程序构建起来的,仅仅需要添加一点代码。这使得代码的易读性大大提高。此时,你可能会觉得你已经把任务进行了很好的分解,并且每一个小部分都比较容易完成,而最后它们也能很好的在一起协作。但真是这样的吗? 357 | 358 | \subsection{改进设计} 359 | 你可能会对自己这么快就编写完程序而颇感自豪,但你注意到了一些事情。你总是要声明讨厌的 \verb|@nucleotides|数组变量,然后把它传递给\textit{randomnucleotide}子程序。但你使用这个数组的唯一地方只在\textit{randomnucleotide}子程序的内部。所以为什么不把设计改变一下呢?下面是一个新的尝试: 360 | 361 | \begin{lstlisting} 362 | # randomnucleotide 363 | # 364 | # A subroutine to randomly select a nucleotide 365 | # 366 | # WARNING: make sure you call srand to seed the 367 | # random number generator before you call this function. 368 | 369 | sub randomnucleotide { 370 | my(@nucs) = ('A', 'C', 'G', 'T'); 371 | 372 | # scalar returns the size of an array. 373 | # The elements of the array are numbered 0 to size-1 374 | return $nucs[rand @nucs]; 375 | } 376 | \end{lstlisting} 377 | 378 | 注意这个函数现在没有参数了,要像这样调用它: 379 | 380 | \begin{lstlisting} 381 | $randomnucleotide = randomnucleotide( ); 382 | \end{lstlisting} 383 | 384 | 它从一个特定的数据集中选取一个随机的元素。当然,你总是在思考,并且会说“要是有一个从任意数组中随机选取一个元素的子程序该会多方便呀。我可能现在并不需要它,但我敢打赌很快我就会需要这样的子程序!”所以,你定义了两个子程序,而不是一个: 385 | 386 | \begin{lstlisting} 387 | # randomnucleotide 388 | # 389 | # A subroutine to randomly select a nucleotide 390 | # 391 | # WARNING: make sure you call srand to seed the 392 | # random number generator before you call this function. 393 | 394 | sub randomnucleotide { 395 | my(@nucleotides) = ('A', 'C', 'G', 'T'); 396 | 397 | # scalar returns the size of an array. 398 | # The elements of the array are numbered 0 to size-1 399 | return randomelement(@nucleotides); 400 | } 401 | 402 | # randomelement 403 | # 404 | # A subroutine to randomly select an element from an array 405 | # 406 | # WARNING: make sure you call srand to seed the 407 | # random number generator before you call this function. 408 | 409 | sub randomelement { 410 | 411 | my(@array) = @_; 412 | 413 | return $array[rand @array]; 414 | } 415 | \end{lstlisting} 416 | 417 | 回头看一下,你会注意到并不需要更改\textit{mutate}子程序,改变的只是\textit{randomnucleotide}的内部构造,而不是它的行为。 418 | 419 | \subsection{组合子程序来模拟突变} 420 | 现在,所有的材料都到位了,所以你要编写如\autoref{exam:example7.2}一样的主程序,来看看新的子程序是否工作。 421 | 422 | %\textbf{例7-2:突变DNA} 423 | \lstinputlisting[label=exam:example7.2,caption={例7.2:突变DNA}]{./scripts/example7-2.pl} 424 | 425 | 下面是\autoref{exam:example7.2}的一些典型的输出: 426 | 427 | \begin{lstlisting} 428 | Mutate DNA 429 | 430 | Here is the original DNA: 431 | 432 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 433 | 434 | Here is the mutant DNA: 435 | 436 | AAAAAAAAAAAAAAAAAAAAGAAAAAAAAA 437 | 438 | Here are 10 more successive mutations: 439 | 440 | AAAAAAAAAAAAAAAAAAAAGACAAAAAAA 441 | AAAAAAAAAAAAAAAAAAAAGACAAAAAAA 442 | AAAAAAAAAAAAAAAAAAAAGACAAAAAAA 443 | AAAAAAAAAAAAAACAAAAAGACAAAAAAA 444 | AAAAAAAAAAAAAACAACAAGACAAAAAAA 445 | AAAAAAAAAAAAAACAACAAGACAAAAAAA 446 | AAAAAAAAAGAAAACAACAAGACAAAAAAA 447 | AAAAAATAAGAAAACAACAAGACAAAAAAA 448 | AAAAAATAAGAAAACAACAAGACAAAAAAA 449 | AAAAAATTAGAAAACAACAAGACAAAAAAA 450 | \end{lstlisting} 451 | 452 | \autoref{exam:example7.2}在编程上有一定的挑战,但你最终看到(模拟的)DNA突变时还是会颇感欣慰。编写一个图形化的展示如何呢,这样每次碱基突变的时候,它都会有一个小的爆炸特效,而且颜色也高亮显示,这样你就可以实时观看突变的发生了。 453 | 454 | 在你对此进行嘲笑之前,你应该知道好的图形化展示对于大多数程序的成功是多么重要。这听起来可能有点像是一个雕虫小技的图形,但是如果你能够演示大多数常见的突变,比如用这种方式演示BRCA乳腺癌基因,它就会非常有用。 455 | 456 | \subsection{程序中的一个Bug?} 457 | 言归正传,在查看\autoref{exam:example7.2}的输出时你可能已经注意到了某些事情。看一下``10 more successive mutations"部分的前两行吧,它们是完全一样的!在欣喜若狂、对自己能够完成如此漂亮的工作而颇感自豪之际,竟然发现了一个bug? 458 | 459 | 你该如何追踪它呢?就像在\autoref{chap:chapter6}学习的那样,你可能想用Perl调试器来一步步地运行程序。但是这一次,不要这么做,停下来先思考一下你的设计吧。你使用随机选取的碱基来替换随机位置上的碱基。啊!有的时候,你随机选取的某个位置上的碱基和你随机选取用来进行替换该位置碱基的碱基是完全一样的!偶尔,你用一个碱基替换了它本身!\footnote{这有多频繁呢?对于DNA中的每一个碱基,其出现的概率都为1/4。对于一个由四种碱基等概率出现构成的DNA来说。这种情况发生的频率就高达1/4!} 460 | 461 | 我们假设,你觉得这种方式不是很有用,对于每一成功的突变,你都应该看到一个碱基的改变。你该如何修改代码来实现这一点呢?让我们先从\textit{mutate}子程序的伪代码开始吧: 462 | 463 | \begin{lstlisting} 464 | Select a random position in the string of DNA 465 | 466 | Repeat: 467 | 468 | Choose a random nucleotide 469 | 470 | Until: random nucleotide differs from the nucleotide in the random position 471 | 472 | Substitute the random nucleotide into the random position in the DNA 473 | \end{lstlisting} 474 | 475 | 这看起来应该管用,所以你修改了\textit{mutate}子程序,把它改名为\textit{mutate\_better}子程序: 476 | 477 | \begin{lstlisting} 478 | # mutate_better 479 | # 480 | # Subroutine to perform a mutation in a string of DNA--version 2, in which 481 | # it is guaranteed that one base will change on each call 482 | # 483 | # WARNING: make sure you call srand to seed the 484 | # random number generator before you call this function. 485 | 486 | sub mutate_better { 487 | 488 | my($dna) = @_; 489 | my(@nucleotides) = ('A', 'C', 'G', 'T'); 490 | 491 | # Pick a random position in the DNA 492 | my($position) = randomposition($dna); 493 | 494 | # Pick a random nucleotide 495 | my($newbase); 496 | 497 | do { 498 | $newbase = randomnucleotide(@nucleotides); 499 | 500 | # Make sure it's different than the nucleotide we're mutating 501 | }until ( $newbase ne substr($dna, $position,1)); 502 | 503 | # Insert the random nucleotide into the random position in the DNA 504 | # The substr arguments mean the following: 505 | # In the string $dna at position $position change 1 character to 506 | # the string in $newbase 507 | substr($dna,$position,1,$newbase); 508 | 509 | return $dna; 510 | } 511 | \end{lstlisting} 512 | 513 | 当你用这个子程序替换掉\textit{mutate}后,运行代码,你会得到下面的输出: 514 | 515 | \begin{lstlisting} 516 | Mutate DNA 517 | 518 | Here is the original DNA: 519 | 520 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 521 | 522 | Here is the mutant DNA: 523 | 524 | AAAAAAAAAAAAATAAAAAAAAAAAAAAAA 525 | 526 | Here are 10 more successive mutations: 527 | 528 | AAAAAAAAAAAAATAAAAAAAACAAAAAAA 529 | AAAAATAAAAAAATAAAAAAAACAAAAAAA 530 | AAATATAAAAAAATAAAAAAAACAAAAAAA 531 | AAATATAAAAAAATAAAAAAAACAACAAAA 532 | AATTATAAAAAAATAAAAAAAACAACAAAA 533 | AATTATTAAAAAATAAAAAAAACAACAAAA 534 | AATTATTAAAAAATAAAAAAAACAACACAA 535 | AATTATTAAAAAGTAAAAAAAACAACACAA 536 | AATTATTAAAAAGTGAAAAAAACAACACAA 537 | AATTATTAAAAAGTGATAAAAACAACACAA 538 | \end{lstlisting} 539 | 540 | 看起来,在每次迭代的时候,确实都有一个碱基发生了改变。 541 | 542 | 对于声明变量还需要注意一点。在\textit{mutate\_better}的代码中,如果你在循环中声明了 \verb|$newbase|变量,因为循环被包裹在了代码块中,所以变量 \verb|$newbase|在循环外就是不可见的。具体来说,在突变过程中实际进行碱基替换的 \verb|substr|调用中,它没法使用。所以,在\textit{mutate\_better}中,你必须要在循环外声明这个变量。 543 | 544 | 对于那些喜欢随用随声明变量的程序员来说,这常常是一些混乱的源头,这也是一个强有力的证据,让你养成在程序顶部收集所有变量定义的习惯。 545 | 546 | 即使这样,有的时候你还是想把变量隐藏在代码块中,因为那里是你唯一会用到这个变量的地方。这时你就会想在代码块中对其进行声明。(如果代码块很长,可能就会在代码块的顶部进行声明?) 547 | 548 | \section{生成随机DNA} 549 | 有时出于测试的目的,生成随机的数据会非常有用。同样可以使用随机DNA来研究生物体中真实DNA的组织方式。在本小节中,我们就来编写一些生成随机DNA序列的程序。 550 | 551 | 这样的随机DNA序列在很多方面都非常有用。比如,流行的BLAST程序(参看\autoref{chap:chapter12}),就要依赖于随机DNA的属性来获得对序列相似性打分进行评估的分析和经验性结果,以及用于对“击中”进行排序的统计结果,这会被BLAST反馈给用户。 552 | 553 | 假设我们需要的是一系列长短不一的随机DNA片段。你的程序必须要设定一个最大和最小的长度,以及生成DNA片段的数目。 554 | 555 | \subsection{自下而上 vs. 自上而下} 556 | 在\autoref{exam:example7.2}中,你编写了一些最基本的子程序,然后一个子程序调用这些基本的子程序,最后实现的是主程序。如果你忽略伪代码,这就是\textit{自下而上设计}的一个例子:从最基本的砖瓦开始,然后把它们组装成高楼大厦。 557 | 558 | 现在我们来看看另一种设计,它从主程序开始,然后是其中的子程序调用,当你发现需要子程序时你才编写它们。这就叫做\textit{自上而下设计}。 559 | 560 | \subsection{生成一系列随机DNA的子程序} 561 | 考虑到我们生成随机DNA的目标,你需要的可能是一个直接生成数据的子程序: 562 | 563 | \begin{lstlisting} 564 | @random_DNA = make_random_DNA_set( $minimum_length, $maximum_length, $size_of_set ); 565 | \end{lstlisting} 566 | 567 | 这看起来没有问题,但还是要看如何来真正完成整个任务。(对你来说这就是自上而下的设计!)所以你需要一步步深入,编写\textit{make\_random\_DNA\_set}子程序的伪代码: 568 | 569 | \begin{lstlisting} 570 | repeat $size_of_set times: 571 | 572 | $length = random number between minimum and maximum length 573 | 574 | $dna = make_random_DNA ( $length ); 575 | 576 | add $dna to @set 577 | } 578 | 579 | return @set 580 | \end{lstlisting} 581 | 582 | 现在,继续自上而下的设计,你需要\textit{make\_random\_DNA}子程序的伪代码: 583 | 584 | \begin{lstlisting} 585 | from 1 to $length 586 | 587 | $base = randomnucleotide 588 | 589 | $dna .= $base 590 | } 591 | 592 | return $dna 593 | \end{lstlisting} 594 | 595 | 不需要更加深入了,因为在\autoref{exam:example7.2}中你已经编写了\textit{randomnucleotide}子程序。 596 | 597 | (你是否对伪代码中不配对的大括号感到厌烦?此处,你依赖于缩进,并用右大括号来表明代码块。既然是伪代码,只要它能工作,一切都是允许的。) 598 | 599 | \subsection{把设计变成代码} 600 | 现在我们已经有了自上而下的设计,该如何编写代码呢?我们还是继续自上问下的设计,来看看它是如何工作的。 601 | 602 | \autoref{exam:example7.3}按照伪代码中自上而下的设计顺序一步步前进,从主程序开始,之后才是子程序。 603 | 604 | %\textbf{例7-3:生成随机DNA} 605 | \lstinputlisting[label=exam:example7.3,caption={例7.3:生成随机DNA}]{./scripts/example7-3.pl} 606 | 607 | 下面是\autoref{exam:example7.3}的输出: 608 | 609 | \begin{lstlisting} 610 | Here is an array of 12 randomly generated DNA sequences 611 | with lengths between 15 and 30: 612 | 613 | TACGCTTGTGTTTTCGGGGGAC 614 | GGGGTGTGGTAAGGCTGTCTCAGATGTGC 615 | TGAACGACAACCTCCTGGACTTTACT 616 | ATCTATGCTTTGCCATGCTAGT 617 | CCGCTCATTCCTCTTCCTCGGC 618 | TGTACCCCTAATACACTTTAGCCGAATTTA 619 | ATAGGTCGGGGCGACAGCGCCGG 620 | GATTGACCTCTGTAA 621 | AAAATCTCTAGGATCGAGC 622 | GTATGTGCTTGGGTAAAT 623 | ATGGAGTTGCGAGGAAGTAGCTGAGT 624 | GGCCCATGACCAGCATCCAGACAGCA 625 | \end{lstlisting} 626 | 627 | \section{分析DNA} 628 | 在处理随机化的最后这个例子中,你将收集DNA的一些统计信息,来回答这个问题:平均来说,对于两个随机的DNA序列,它们的碱基相同的百分比是多少?尽管一些简单的数学计算就可以帮你回答这个问题,但这个程序的要点在于表明你现在已经有必需的编程能力来提问并回答关于DNA序列的问题了。(如果你在使用真实的DNA,比如收集到的在不同生物中略有不同的某个特定基因,这个问题就更加有趣了。稍后你可能会想尝试一下。) 629 | 630 | 让我们生成一个随机DNA的集合,所有的DNA长度都相等,然后对这个集合思考下面的问题:对于集合中成对的DNA序列来说,相同碱基位置的百分比平均是多少? 631 | 632 | 像平常一样,我们先尝试用伪代码勾画出程序的思路: 633 | 634 | \begin{lstlisting} 635 | Generate a set of random DNA sequences, all the same length 636 | 637 | For each pair of DNA sequences 638 | 639 | How many positions in the two sequences are identical as a fraction? 640 | 641 | } 642 | 643 | Report the mean of the preceding calculations as a percentage 644 | \end{lstlisting} 645 | 646 | 显而易见,要编写这个代码,你至少可以重用已经完成的一部分工作。你已经知道如何生成一系列随机的DNA序列。此外,虽然你还没有按照位置逐个比较两条序列碱基的子程序,但你知道如何查找DNA字符串中的位置。所以,这样的子程序并不难写。事实上,我们写一些伪代码,来把一个序列上的每一个核苷酸和另一个序列上相同位置的核苷酸进行比较: 647 | 648 | \begin{lstlisting} 649 | assuming DNA1 is the same length as DNA2, 650 | 651 | for each position from 1 to length(DNA) 652 | 653 | if the character at that position is the same in DNA_1 and DNA_2 654 | 655 | ++$count 656 | } 657 | } 658 | 659 | return count/length 660 | \end{lstlisting} 661 | 662 | 这个问题已经迎刃而解了。当然,你还需要编写一些代码,来挑选成对的序列,收集计算结果,最终获得结果的平均值并以百分比的形式将它报告出来。所有这些都在主程序中。\autoref{exam:example7.4}就是这样的尝试,所有的内容都在其中。 663 | 664 | %\textbf{例7-4:计算成对随机DNA序列的平均一致性百分比} 665 | \lstinputlisting[label=exam:example7.4,caption={例7.4:计算成对随机DNA序列的平均一致性百分比}]{./scripts/example7-4.pl} 666 | 667 | \autoref{exam:example7.4}中的代码看起来和前面例子中的代码有些重复,确实是这样的。为了便于描述,我把子程序代码都放在了程序中。(在\autoref{chap:chapter8}中,你将开始使用模块,就会避免这种重复。) 668 | 669 | 下面是\autoref{exam:example7.4}的输出: 670 | 671 | \begin{lstlisting} 672 | In this run of the experiment, the average number of 673 | matching positions is 24% 674 | \end{lstlisting} 675 | 676 | 好吧,这看起来还算合理。你可能会说,这是显而易见的:四分之一的位置相匹配,因为一共有四种碱基。但是,这点并不足以验证基本概率,它只是让你明白,你已经有足够的编程技能傍身,来编写一些针对DNA序列提问和回答问题的程序了。 677 | 678 | \subsection{关于代码的一些注释} 679 | 注意,在主程序中,当调用: 680 | 681 | \begin{lstlisting} 682 | @random_DNA = make_random_DNA_set( 10, 10, 10 ); 683 | \end{lstlisting} 684 | 685 | \noindent 时,你并不需要声明并初始化像 \verb|$minimum_length|这样的变量。你只需要在调用子程序时填入真实的数值即可。(然而,把这样的东西存储在程序顶部声明的变量中,通常都是一个比较好的做法,因为这样比较容易寻找并修改它们。)这个例子中,你把最大和最小的长度都设置成了10,同时要求生成10条序列。 686 | 687 | 让我们重申一下刚刚解决的问题。你需要比较所有的DNA对,对每一对DNA,都要计算有相同核苷酸的位置的百分比。然后,你要得到这些百分比的平均值。 688 | 689 | 在\autoref{exam:example7.4}主程序中实现这一点的代码如下所示:: 690 | 691 | \begin{lstlisting} 692 | # Iterate through all pairs of sequences 693 | for (my $k = 0 ; $k < scalar @random_DNA - 1 ; ++$k) { 694 | for (my $i = ($k + 1) ; $i < scalar @random_DNA ; ++$i) { 695 | 696 | # Calculate and save the matching percentage 697 | $percent = matching_percentage($random_DNA[$k], $random_DNA[$i]); 698 | push(@percentages, $percent); 699 | } 700 | } 701 | \end{lstlisting} 702 | 703 | 为了比较每一对DNA,你使用了嵌套的循环。所谓\textit{嵌套循环}就是指在一个循环中还有另一个循环。这在编程中非常常见,但一定要小心处理它们。这看起来可能有一点复杂,花些时间来看看嵌套循环是如何工作的,因为当从一个集合中选取两个(或多个)元素的组合时这很常用。 704 | 705 | 这里的嵌套循环要查看$(n * (n-1)) / 2$对序列,这是数据集大小的平方函数。它会变得非常大!试着逐渐增加数据集的大小,然后重新运行程序,你会发现运算时间增加了,而且远比线性增加要大。 706 | 707 | 看看循环是如何工作的?首先,序列0(以 \verb|$k|进行索引)依次跟序列1、2、3、……9(以 \verb|$i|进行索引)进行配对。之后,序列1依次和2、3、……9进行配对,如此往复,最后,序列8和序列9进行配对。(回忆一下,数组元素的计数是从0开始的,所以有10个元素的数组的最后一个元素的索引是9。此外,回忆一下,标量 \verb|@random_DNA|返回的是数组中元素的数目。) 708 | 709 | 你可能发现这样做是比较值得的,就是把序列数目设置成一个小的数值,比如3或者4,然后思考(手中拿着纸笔)在程序运行过程中嵌套循环是如何工作的,变量 \verb|$k|和 \verb|$i|是如何一步步改变的。或者,你也可以使用Perl调试器来看看到底发生了什么。 710 | 711 | \section{练习题} 712 | \textcolor{black}{\textit{习题7.1}} 713 | \begin{adjustwidth}{4em}{} 714 | 编写一个程序,询问你选取一个氨基酸,然后(随机)猜测你选的是哪个氨基酸。 715 | \end{adjustwidth} 716 | 717 | \textcolor{black}{\textit{习题7.2}} 718 | \begin{adjustwidth}{4em}{} 719 | 编写一个程序,选取四个核苷酸中的一个,然后一直进行提示,直到你正确猜出选取的是哪个核苷酸。 720 | \end{adjustwidth} 721 | 722 | \textcolor{black}{\textit{习题7.3}} 723 | \begin{adjustwidth}{4em}{} 724 | 编写一个子程序,随机打乱数组的元素。子程序以一个数组作为参数,返回具有相同元素、但打乱成随机顺序的数组。原始数组中的每一个元素在输出的数组中都出现且仅出现一次,就像洗牌一样。 725 | \end{adjustwidth} 726 | 727 | \textcolor{black}{\textit{习题7.4}} 728 | \begin{adjustwidth}{4em}{} 729 | 编写一个程序来突变蛋白质序列,就像\autoref{exam:example7.2}中突变DNA的代码一样。 730 | \end{adjustwidth} 731 | 732 | \textcolor{black}{\textit{习题7.5}} 733 | \begin{adjustwidth}{4em}{} 734 | 编写一个子程序,给定一个密码子(一个长3bp的DNA片段),返回密码子中的一个随机突变。 735 | \end{adjustwidth} 736 | 737 | \textcolor{black}{\textit{习题7.6}} 738 | \begin{adjustwidth}{4em}{} 739 | 有些版本的Perl为随机数生成器自动设置种子,这样在使用 \verb|rand|生成随机数之前就不用多余使用 \verb|srand|来设置种子了。实验一下,看看 \verb|rand|是否会自动调用 \verb|srand|,还是需要你自己明确地去调用 \verb|srand|,就像你在本章的代码中看到的那样。 740 | \end{adjustwidth} 741 | 742 | \textcolor{black}{\textit{习题7.7}} 743 | \begin{adjustwidth}{4em}{} 744 | 有时,在随机选取的时候并不是所有的选项都会被选择到。编写一个子程序,随机返回一个核苷酸,而且是按照指定的每个核苷酸的几率。给这个子程序传递四个数字作为参数,代表每中核苷酸的几率。如果每种核苷酸的几率都是0.25,这个子程序在选取每种核苷酸时就是完全均等的。为了检查错误,子程序还要确保四个几率之和为1。 745 | 746 | \textit{提示:}实现这一点的一种方法就是,把从0到1的范围分成四个区间,每个区间的长度和相应核苷酸的几率相对应。然后,简单的从0到1之间随机选取一个数字,看看它落在了哪个区间中,就返回相对应的核苷酸即可。 747 | \end{adjustwidth} 748 | 749 | \textcolor{black}{\textit{习题7.8}} 750 | \begin{adjustwidth}{4em}{} 751 | \textit{这是一个有一定难度的练习题。}Perl中的\textit{study}函数可能能提高DNA或蛋白质中基序的查找速度。查看关于这个函数的Perl文档。它的用法非常简单:给定存储在 \verb|$sequence|变量中的一些序列数据,在进行搜索之前键入: 752 | 753 | \begin{lstlisting} 754 | study $sequence; 755 | \end{lstlisting} 756 | 757 | 基于你已经阅读的文档中的相关内容,你认为\textit{study}会提高DNA或蛋白质的搜索速度吗? 758 | \end{adjustwidth} 759 | 760 | \textit{可以得到大量更多的得分!}现在阅读标准模块Benchmark的Perl文档。(键入 \verb|perldoc Benchmark|,或者访问 \href{http://www.perl.com}{http://www.perl.com} 上的Perl主页。)编写一个程序,在使用和不使用\textit{study}的情况下,分别检测DNA和蛋白质基序的搜索速度,看看你的猜测是不是正确。 761 | -------------------------------------------------------------------------------- /Chapters/chapter9.tex: -------------------------------------------------------------------------------- 1 | \chapter{限制酶图谱和正则表达式} 2 | \label{chap:chapter9} 3 | \minitoc 4 | 5 | 在本章中,我会对Perl的正则表达式和操作符进行概述,这是我们一直在使用的Perl语言的两个基本特性。我们也会探讨一个标准的、基础的分子生物学技术的编程:找到一个序列的限制酶图谱。对DNA进行限制酶切消化是把它“指纹化”的最原始的方法之一,现在可以在计算机上对其进行模拟了。 6 | 7 | 在实验室中,限制酶图谱和与之相关的限制酶切消化都是非常常见的计算,并且多种软件包都可以进行这样的计算。它们是意欲进行克隆实验的基本工具,比如,应用它,可以把一个期望的DNA片段插入到克隆载体中。限制酶图谱在序列测序项目中也有其应用,比如鸟枪法或直接测序。 8 | 9 | \section{正则表达式} 10 | 现在我们已经使用了一段时间的正则表达式了。本小节将补充一些背景知识,并把本书前面部分中对正则表达式进行的那些零散的讨论串联起来。 11 | 12 | 正则表达式有趣、主要,而且应用潜能无限。Jeffrey 13 | Friedl的\textit{精通正则表达式} 14 | (O'Reilly出版)这本书就对它们进行了全面深入的讲解。Perl尤其擅长使用正则表达式,Perl的文档中对此进行了很好的讲解。当处理序列或者GenBank、PDB和BLAST文件等生物学数据时,正则表达式非常有用。 15 | 16 | 正则表达式是用一个字符串来表征并搜索多个字符串的方法。尽管严格来说它们并不是一样的东西,但是你可以把正则表达式看做是一种高度发展的通配符集合,这会对你有所帮助。正则表达式中的特殊字符通常叫做元字符。 17 | 18 | 许多人对通配符都非常熟悉,在搜索引擎或者纸牌游戏中都可以发现它的身影。举个例子,你可能会发现,通过键入 \verb|biolog*|可以指代所有以 \verb|biolog|起始的单词。或者,你可能发现自己的牌中有五张尖儿。(不同的情况下可能会使用不同的通配符。Perl的正则表达式中使用*表示“前面的字符重复0次或多次”,而不是刚才那个通配符例子中的“后面跟任何字符”。) 19 | 20 | 在计算机科学中,不管是在实践中还是在理论上,这种类型的通配符或者元字符都有一个重要的历史。被知名的逻辑学家发明之后,在实践中,星号字符就被叫做克莱尼闭包\footnote{译者注:亦称克莱尼星号。}了。作为对理论的致敬,我会提到有一个简单的计算机模型,它没有图灵机那么强大,但完全可以处理用正则表达式描述的同样类型的语言。这种机器模型叫做\textit{有限自动机}。现在理论知识已经够多了。 21 | 22 | 我们已经看到了好多正则表达式的例子,在DNA或者蛋白质序列中进行查找。此处,我将对正则表达式背后的一些基础观念进行简要的介绍,作为多一些术语的引言。在\autoref{chap:chapterab}中有一个非常有用的正则表达式特性的总结。最后,我们将看看如何在Perl的文档中对它们进行更加深入的学习。 23 | 24 | 所以让我们从一个实际的例子开始吧,对于逐章阅读至今的读者来说这应该已经非常熟悉了:使用字符集来查找DNA。假设有一个小的基序,你想在你的DNA库中进行查找,这个基序有六个碱基对之长:CT后面跟着C或G或T,之后是ACG。这个基序中的第三个核苷酸不是A,但可以是C、G或者T。你可以使用字符集[CGT]制作一个正则表达式来表示这个变异的位点。这样,基序就可以用这样一个正则表达式来进行表征了:CT[CGT]ACG。这是一个有六个碱基对之长的基序,在它的第三个位置是一个C、G或者T。如果你的DNA保存在标量变量 \verb|$dna|中,你就可以检测一下其中是否存在这个基序,在模式匹配语句的条件测试中使用正则表达式即可,就像这样: 25 | 26 | \begin{lstlisting} 27 | if( $dna =~ /CT[CGT]ACG/ ) { 28 | print "I found the motif!!\n"; 29 | } 30 | \end{lstlisting} 31 | 32 | 正则表达式基于三个基础的理念: 33 | 34 | \textcolor{black}{\textit{重复(或闭包)}} 35 | \begin{adjustwidth}{4em}{} 36 | \hspace*{2em}星号(*),也叫做克莱尼闭包或克莱尼星号,表示前面的字符重复0次或多次。比如, \verb|abc*|匹配所有这些字符串: \verb|ab|, \verb|abc|, \verb|abcc|, \verb|abccc|, \verb|abcccc|等等。这个正则表达式匹配无穷多个字符串。 37 | \end{adjustwidth} 38 | 39 | \textcolor{black}{\textit{择一}} 40 | \begin{adjustwidth}{4em}{} 41 | \hspace*{2em}在Perl中,模式 \verb=(a|b)=(读作: \verb|a or b|)匹配字符串 \verb|a|或者字符串 \verb|b|。 42 | \end{adjustwidth} 43 | 44 | \textcolor{black}{\textit{连接}} 45 | \begin{adjustwidth}{4em}{} 46 | \hspace*{2em}这是显而易见的一点。在Perl中,字符串 \verb|ab|表示字符 \verb|a|后面跟着(与之相连接)字符 \verb|b|。 47 | \end{adjustwidth} 48 | 49 | 使用小括号进行分组是非常重要的:它们也是元字符。所以,举个例子,字符串 \verb=(abc|def)z*x=匹配 \verb|abcx|、 \verb|abczx|、 \verb|abczzx|、 \verb|defx|、 \verb|defzx|、 \verb|defzzzzzx|等等这样的字符串。用白话来说,它匹配的是 \verb|abc|或者 \verb|def|后面跟着零个或多个 \verb|z|,并且最后是一个 \verb|x|。这个例子把分组、择一、闭包和连接的理念整合在了一起。通过把这三个基础的理念整合起来,就可以真正看出正则表达式的强大之处来了。 50 | 51 | Perl有许多正则表达式的特性。它们基本上都是我们刚刚提到的三个基础理念——重复、择一和连接的快捷键而已。比如,前面演示的字符集使用择一可以写成 \verb=(C|G|T)=。另外一个常见的特性是点号,它可以用来表示除换行符以外的任意字符。所以 \verb|ACG.*GCA|表示任意起始于 \verb|ACG|、终止于 \verb|GCA|的DNA。用白话来说,它读作: \verb|ACG|后面跟着零个或者多个字符,然后是 \verb|GCA|。 52 | 53 | 在Perl中,正则表达式通常被用作模式匹配界定符的正斜线包裹在中间。查看 \verb|m//|的文档(或者是\autoref{chap:chapterab}),其中包括影响正则表达式行为的一些选项。就像你将看到的那样,正则表达式也被用在许多Perl的内置命令中。 54 | 55 | Perl文档是最基本的:从 \href{http://www.perldoc.com/perl5.6/pod/perlre.html\#top}{http://www.perldoc.com/perl5.6/pod/perlre.html\#top} 上的Perl手册中的\textit{perlre}小节开始吧。 56 | 57 | \section{限制酶切图谱和限制性内切酶} 58 | 分子生物学的重大发现之一就是限制性内切酶的发现,它为生物学研究的当今黄金时代铺平了道路。为了非生物学家,同时也为后面准备好编程材料,这里先对其进行一个概述。 59 | 60 | \subsection{背景} 61 | \textit{限制性内切酶}是把DNA切割成短的、特定序列的蛋白质,比如,最常见的限制性内切酶\textit{Eco}RI和\textit{Hin}dIII就在实验室中被广泛应用。\textit{Eco}RI切割找到的 \verb|GAATTC|,切割位点在 \verb|G|和 \verb|A|之间。实际上,它同时切割互补的两条链,在每一端都留下一个突出部分。这些在单链上有几个碱基的“粘性末端”,使得片段有可能被重排,比如在克隆和测序中它使得把DNA插入到载体中成为可能。\textit{Hin}dIII切割 \verb|AAGCTT|,切割位点在两个 \verb|A|之间。有些限制性内切酶会在中间进行切割,从而产生没有突出的“平滑末端”。已知大约有1,000种限制性内切酶。 62 | 63 | 如果你查看限制性内切酶\textit{Eco}RI的反向互补链,你会看到同样的序列 \verb|GAATTC|。这是一种生物学的回文,也就是说正反读都一样。许多限制性位点都是回文结构。 64 | 65 | 在实验室中,计算限制酶图谱是一个常见且实用的生物信息学工作。通过计算限制酶图谱,可以对实验进行规划,找到切割DNA并插入基因的最佳方法,进行特定位点的突变,或者是其他重组DNA技术的各种应用。通过初步的计算,实验室科学家就可以不用在实验台上不断得进行试错性的实验了。在 \href{http://rebase.neb.com/rebase/rebase.html}{http://rebase.neb.com/rebase/rebase.html} 上可以查阅更多关于限制性内切酶的相关内容。 66 | 67 | 现在我们要编写一个在实验室中非常有用的程序:它会在DNA序列中查找限制性内切酶,并报告限制酶切图谱以及这个限制性内切酶出现在DNA上的精确位点。 68 | 69 | \subsection{程序规划} 70 | 在前面的\autoref{chap:chapter5}中,你已经看到如何在文本中查找正则表达式了。所以你也知道如何使用Perl来查找序列中的基序。现在让我们想想,该如何利用这些技术来生成限制酶切图谱。下面是需要询问的一些问题: 71 | 72 | \textcolor{black}{\textit{我在哪里可以找到限制性内切酶的数据?}} 73 | \begin{adjustwidth}{4em}{} 74 | \hspace*{2em}限制性内切酶的数据可以在限制性酶切酶数据库(REBASE,Restriction Enzyme Database)中找到,它的网址是 \href{http://rebase.neb.com/rebase/rebase.html}{http://rebase.neb.com/rebase/rebase.html}。 75 | \end{adjustwidth} 76 | 77 | \textcolor{black}{\textit{我该如何使用正则表达式表征限制性内切酶?}} 78 | \begin{adjustwidth}{4em}{} 79 | \hspace*{2em}浏览那个网站,你会看到限制性内切酶用它们自己的语言进行了表征。我们会尝试把这种语言翻译成正则表达式的语言。 80 | \end{adjustwidth} 81 | 82 | \textcolor{black}{\textit{我该如何存储限制性内切酶的数据?}} 83 | \begin{adjustwidth}{4em}{} 84 | \hspace*{2em}大约有1,000种有名字和定义的限制性内切酶。这使得可以使用散列提供的快速的键-值查找对它们进行处理。当你编写一个真正的应用程序时,比如应用于网站,最好是创建一个DBM文件来存储这些信息,当程序需要进行查找时立马就可以使用它。我会在\autoref{chap:chapter10}中对DBM文件进行介绍。此处,我们仅仅是指出这种方式而已。我们将只在程序中保存几个限制性内切酶的定义。 85 | \end{adjustwidth} 86 | 87 | \textcolor{black}{\textit{我该如何接受用户的查询?}} 88 | \begin{adjustwidth}{4em}{} 89 | \hspace*{2em}你可以询问一个限制性内切酶的名字,或者可以让用户直接键入一个正则表达式。我们将采用第一种方法。此外,你想要让用户指定使用的序列。再重复一次,为了简化问题,你将只从一个DNA样本文件中读入数据。 90 | \end{adjustwidth} 91 | 92 | \textcolor{black}{\textit{我该如何向用户报告返回限制酶切图谱呢?}} 93 | \begin{adjustwidth}{4em}{} 94 | \hspace*{2em}这是一个非常重要的问题。最简单的方式就是生成一个位置以及在此处找到的限制性内切酶的名字的列表。因为它呈现的信息非常简单,所以对于进一步的处理非常有用。 95 | 96 | 但是如果你不想进行进一步的处理,只想把限制酶切图谱展示给用户呢?这时,进行一个图形化展示就会更加有用,可能是打印出序列,并在其上用一条线来标明限制性内切酶存在的位置。 97 | 98 | 你可以使用各种精致花哨的东西,但我们现在只采用简单的方式来进行处理,输出一个列表。 99 | \end{adjustwidth} 100 | 101 | 所以,我们的规划就是编写一个程序,包括把限制性内切酶的数据翻译成正则表达式,并把它存储为以限制性内切酶名字作为键的值中。DNA序列数据从文件中读入,用户将被提示输入限制性内切酶的名字。相应的正则表达式会从散列中提取出来,我们将会查找正则表达式所有的出现,以及出现的位置。最后,返回找到的位置列表。 102 | 103 | \subsection{限制性内切酶数据} 104 | 访问REBASE网站时你会看到,有多种格式的限制性内切酶数据可供使用。在查看之后,你决定使用存储在\textit{bionet}文件中的信息,它有一个相当简单的排版。下面是这个文件的头信息以及一些限制性内切酶的信息: 105 | 106 | \begin{lstlisting} 107 | REBASE version 104 bionet.104 108 | 109 | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 110 | REBASE, The Restriction Enzyme Database http://rebase.neb.com 111 | Copyright (c) Dr. Richard J. Roberts, 2001. All rights reserved. 112 | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 113 | 114 | Rich Roberts Mar 30 2001 115 | 116 | AaaI (XmaIII) C^GGCCG 117 | AacI (BamHI) GGATCC 118 | AaeI (BamHI) GGATCC 119 | AagI (ClaI) AT^CGAT 120 | AaqI (ApaLI) GTGCAC 121 | AarI CACCTGCNNNN^ 122 | AarI ^NNNNNNNNGCAGGTG 123 | AatI (StuI) AGG^CCT 124 | AatII GACGT^C 125 | AauI (Bsp1407I) T^GTACA 126 | AbaI (BclI) T^GATCA 127 | AbeI (BbvCI) CC^TCAGC 128 | AbeI (BbvCI) GC^TGAGG 129 | AbrI (XhoI) C^TCGAG 130 | AcaI (AsuII) TTCGAA 131 | AcaII (BamHI) GGATCC 132 | AcaIII (MstI) TGCGCA 133 | AcaIV (HaeIII) GGCC 134 | AccI GT^MKAC 135 | AccII (FnuDII) CG^CG 136 | AccIII (BspMII) T^CCGGA 137 | Acc16I (MstI) TGC^GCA 138 | Acc36I (BspMI) ACCTGCNNNN^ 139 | Acc36I (BspMI) ^NNNNNNNNGCAGGT 140 | Acc38I (EcoRII) CCWGG 141 | Acc65I (KpnI) G^GTACC 142 | Acc113I (ScaI) AGT^ACT 143 | AccB1I (HgiCI) G^GYRCC 144 | AccB2I (HaeII) RGCGC^Y 145 | AccB7I (PflMI) CCANNNN^NTGG 146 | AccBSI (BsrBI) CCG^CTC 147 | AccBSI (BsrBI) GAG^CGG 148 | AccEBI (BamHI) G^GATCC 149 | AceI (TseI) G^CWGC 150 | AceII (NheI) GCTAG^C 151 | AceIII CAGCTCNNNNNNN^ 152 | AceIII ^NNNNNNNNNNNGAGCTG 153 | AciI C^CGC 154 | AciI G^CGG 155 | AclI AA^CGTT 156 | AclNI (SpeI) A^CTAGT 157 | AclWI (BinI) GGATCNNNN^ 158 | \end{lstlisting} 159 | 160 | 你的第一个任务就是读入这个文件,获取每一个酶的名字和识别位点(或说是限制性内切位点)。现在为了简化问题,简单的把括号中的限制性内切酶的名字丢掉。 161 | 162 | 该如何读入这个数据呢? 163 | 164 | \begin{lstlisting} 165 | Discard header lines 166 | 167 | For each data line: 168 | 169 | remove parenthesized names, for simplicity's sake 170 | 171 | get and store the name and the recognition site 172 | 173 | Translate the recognition sites to regular expressions 174 | --but keep the recognition site, for printing out results 175 | } 176 | 177 | return the names, recognition sites, and the regular expressions 178 | \end{lstlisting} 179 | 180 | 这是一个高等级的粗犷的伪代码,所以让我们来把它细化扩展开。(注意大括号并没有配对。这样是完全可以的,因为对于伪代码来说没有什么语法规则,只要它能使用就行了!)下面是丢弃头信息行的伪代码: 181 | 182 | \begin{lstlisting} 183 | foreach line 184 | 185 | if /Rich Roberts/ 186 | 187 | break out of the foreach loop 188 | 189 | } 190 | \end{lstlisting} 191 | 192 | 这是基于文件的格式,你寻找的字符串是数据行开始之前的最后一行文本。(当然,如果文件的格式发生了变化,它可能就无法再使用了。) 193 | 194 | 现在,我们来进一步展开伪代码,想想如何来完成下面的任务: 195 | 196 | \begin{lstlisting} 197 | # Discard header lines 198 | # This keeps reading lines, up to a line containing "Rich Roberts" 199 | foreach line 200 | if /Rich Roberts/ 201 | break out of the foreach loop 202 | } 203 | 204 | For each data line: 205 | 206 | # Split the two or three (if there's a parenthesized name) fields 207 | @fields = split( " ", $_); 208 | 209 | # Get and store the name and the recognition site 210 | $name = shift @fields; 211 | 212 | $site = pop @fields; 213 | 214 | # Translate the recognition sites to regular expressions 215 | --but keep the recognition site, for printing out results 216 | } 217 | 218 | return the names, recognition sites, and the regular expressions 219 | \end{lstlisting} 220 | 221 | 这并不是翻译,但让我们来看看你都做了哪些事情。 222 | 223 | 首先,你想从一个字符串中提取出名字和识别位点的数据。在Perl中把一行分割成单词的最常用的方法,就是使用Perl的内置函数 \textit{split},尤其是当字符串有着很规整的格式时。 224 | 225 | 对于有空白的一行,如果其中有两三个单词被空白分隔开来,你可以把它们提取保存到数组中,使用下面这个简单的\textit{split}调用即可(它处理的是存储在特殊变量 \verb|$_|中的行): 226 | 227 | \begin{lstlisting} 228 | @fields = split( " ", $_); 229 | \end{lstlisting} 230 | 231 | 取决于是否有用括号括起来的酶的别名, \verb|@fields|数组可能有两个或三个元素。但你总可以这样提取出第一个和最后一个元素: 232 | 233 | \begin{lstlisting} 234 | $name = shift@fields; 235 | $site = pop@fields; 236 | \end{lstlisting} 237 | 238 | 现在,你面临的问题是要把识别位点翻译成正则表达式。 239 | 240 | 仔细查看这些识别位点,并阅读网站上找到的REBASE的文档后,你知道切割位点是用脱字符(\^~)来表示的。这对于在序列中查找位点用的正则表达式的制作并没有什么帮助,所以你应该把它删除掉(参看\autoref{sect:section9.4}中的Exercise 9.6)。 241 | 242 | 还要注意,识别位点中的碱基并不仅仅只是A、C、G和T四种碱基,它们还使用到了\autoref{tab:table4.1}中的更多的扩展字符。这些额外的字母包括代表两个、三个或四个碱基的所有可能组合的字母。在这方面,它们真的很像字符集的简写。奥!我们来编写一个子程序,把这些代码都替换成字符集,这样我们就有了我们要的正则表达式。 243 | 244 | 当然,REBASE使用它们,是因为一个限制性内切酶可能能匹配几个不同的识别位点。 245 | 246 | \autoref{exam:example9.1}是一个子程序,对于给定的一个字符串,它会把这样的代码转换成字符集。 247 | 248 | %\textbf{例9-1:把IUB的模糊代码翻译成正则表达式} 249 | \lstinputlisting[label=exam:example9.1,caption={例9.1:把IUB的模糊代码翻译成正则表达式}]{./scripts/example9-1.pl} 250 | 251 | 看起来你已经准备好编写一个子程序,从REBASE的数据文件中提取数据。但还有一个重要的问题没有解决:你想要返回的数据有多精确? 252 | 253 | 对于原始的REBASE文件的每一行,你打算返回三个数据项:酶的名字、识别位点和正则表达式。这并不能很容易的转换成散列。你可以返回一个数组,把这三个数据项连续的存储在一起。这是可行的:要读入数据,你必须从数组中读取成组的三个项目。这是完全可以的,但使得查询有些困难。随着你学习更多Perl的进阶知识,你会发现你可以创建自己的复杂数据结构。 254 | 255 | 既然你已经学习了\textit{split},也许你可以使用一个散列,它的键是酶的名字,它的值是包含用空白分隔开的识别位点和正则表达式的字符串。然后你就可以对数据进行快速的查找,并使用\textit{split}提取出需要的值。\autoref{exam:example9.2}展示了这种方法。 256 | 257 | %\textbf{例9-2:解析REBASE数据文件的子程序} 258 | \lstinputlisting[label=exam:example9.2,caption={例9.2:解析REBASE数据文件的子程序}]{./scripts/example9-2.pl} 259 | 260 | 这个\textit{parseREBASE}子程序做了大量的工作。对于一个子程序来说,做的事情是不是太多了,要不要重新编写它?当你编写代码时,这是你应该问自己的一个很好的问题。在这个例子中,就先这样吧。然而,除了做了大量的事情以外,它也采用了一些新的处理方法,现在我们就来看看吧。 261 | 262 | \subsection{逻辑操作符和范围操作符} 263 | 你使用\textit{foreach}循环来处理存储在 \verb|@rebasefile|数组中的\textit{bionet}文件的每一行。 264 | 265 | 在这个循环中,你使用了一个Perl的新特性来跳过头信息行,这就是\textit{范围操作符}(..),它出现在这一行中: 266 | 267 | \begin{lstlisting} 268 | ( 1 .. /Rich Roberts/ ) and next; 269 | \end{lstlisting} 270 | 271 | 它的作用是跳过从第一行到包含“Rich Roberts”这一行的所有行,换句话说,就是头信息行。(范围操作符必须至少有一个可以作为数字的终点,就像这样,它才能正常工作。) 272 | 273 | \textit{and}函数是一个\textit{逻辑操作符}。在绝大多数编程语言中都有逻辑操作符。在Perl,它们变得非常流行,所以尽管我们在本书中并没有大量使用它们,但你将来会经常遇到使用它们的代码。事实上,随着本书的深入,你将开始越来越多的看到它们。 274 | 275 | 逻辑操作符可以用来测试两个条件是不是都为 \verb|真|,例如: 276 | 277 | \begin{lstlisting} 278 | if( $string eq 'kinase' and $num == 3 ) { 279 | ... 280 | } 281 | \end{lstlisting} 282 | 283 | 只有当两个条件都为 \verb|真|时,整个语句才为 \verb|真|。 284 | 285 | 类似的,通过逻辑操作符,使用\textit{or}操作符,你可以测试是不是至少有一个条件为 \verb|真|,例如: 286 | 287 | \begin{lstlisting} 288 | if( $string eq 'kinase' or $num == 3 ) { 289 | ... 290 | } 291 | \end{lstlisting} 292 | 293 | 这里,如果两个条件至少有一个为 \verb|真|,那么 \verb|if|语句就为 \verb|真|。 294 | 295 | 此外,还有一个\textit{not}逻辑操作符,一个否定操作符,使用它你可以测试某个东西是不是为 \verb|假|: 296 | 297 | \begin{lstlisting} 298 | if( not 6 == 9 ) { 299 | ... 300 | } 301 | \end{lstlisting} 302 | 303 | \verb|6 == 9|返回 \verb|假|,但它被\textit{not}操作符否定了,所以真个条件测试返回 \verb|真|。 304 | 305 | 此外还有非常相关的操作符,与\textit{and}相关的是 \verb=&&=,与\textit{or}相关的是 \verb=||=,与\textit{not}相关的是 \verb=!=。它们在行为上有少许的不同(实际上,优先级不同)。大多数Perl代码都使用我演示的版本,但两者都很常见。 306 | 307 | 当你对优先级有所怀疑时,你总是可以把表达式用小括号包裹起来,确保你的语句的执行结果就是你所期望的那样。(参看本章后面的\autoref{sect:section9.3.1}。) 308 | 309 | 逻辑操作符也有一定的求值顺序,这使得它们在控制程序流程方面非常有用。让我们看一下\textit{and}操作符是如何对它的两个参数进行求值的。它首先对左边的参数进行求值,当且仅当它为 \verb|真|时,才会对右边的参数求值并返回结果。如果左边参数的求值结果为 \verb|假|,右边的参数就永远不会被求值了。所以\textit{and}操作符的行为就像一个小的 \verb|if|语句。举个例子,下面这两个语句就是完全等同的: 310 | 311 | \begin{lstlisting} 312 | if( $verbose ) { 313 | print $helpful_but_verbose_message; 314 | } 315 | 316 | $verbose and print $helpful_but_verbose_message; 317 | \end{lstlisting} 318 | 319 | 当然,\textit{if}语句要更加灵活一些,因为它允许你轻松地向代码块中添加更多的语句,对于\textit{elsif}和\textit{else}条件和它们的代码块也是一样。但对于简单的情况, \verb|and|操作符会更好一些。\footnote{你甚至可以把逻辑操作符一个接一个地串成长串,来构建更加复杂的表达式,并用括号对它们进行分组。个人而言,我不太喜欢这种风格,但在Perl中,方法不止一种!} 320 | 321 | 逻辑操作符\textit{or}会对左边的参数求值,如果它为 \verb|真|就会返回求值结果;如果左边的参数求值结果不为 \verb|真|,\textit{or}操作符就会对右边的参数求值并返回结果。所以还有另一种方法来编写单行的语句,在Perl程序中你会经常看到: 322 | 323 | \begin{lstlisting} 324 | open(MYFILE, $file) or die "I cannot open file $file: $!"; 325 | \end{lstlisting} 326 | 327 | 这和我们常用的基本上是等同的: 328 | 329 | \begin{lstlisting} 330 | unless(open(MYFILE, $file)) { 331 | print "I cannot open file $file\n"; 332 | exit; 333 | } 334 | \end{lstlisting} 335 | 336 | 言归正传,来看一下\textit{parseREBASE}子程序中的这一行: 337 | 338 | \begin{lstlisting} 339 | ( 1 .. /Rich Roberts/ ) and next; 340 | \end{lstlisting} 341 | 342 | 左边的参数是 \verb|1 .. /Rich Roberts/|这个范围。当你在这些行的范围之中时,范围操作符返回 \verb|真|值。因为它为 \verb|真|,所以 \verb|and|逻辑操作符就会继续看看另一边的值是不是也为 \verb|true|,它会找到\textit{next}函数,它的求值为 \verb|true|,而它则会把你带到包裹在\textit{foreach}循环中的“下一个”迭代。所以当你在第一行和 \verb|Rich Roberts|这一行之间时,会直接跳过循环的剩余部分。 343 | 344 | 类似的,这一行: 345 | 346 | \begin{lstlisting} 347 | /^\s*$/ and next; 348 | \end{lstlisting} 349 | 350 | 也会把你带回到 \verb|foreach|的下一个迭代,当左边的参数为 \verb|真|、也就是匹配一个空行时。 351 | 352 | 353 | 在设计阶段,我们已经讨论过\textit{parseREBASE}子程序的其他部分了。 354 | 355 | \subsection{寻找限制性内切位点} 356 | 所以现在是时候来编写主程序了,看看我们的代码的实际表现。让我们从一个小的伪代码开始,看看我们还需要做什么: 357 | 358 | \begin{lstlisting} 359 | # 360 | # Get DNA 361 | # 362 | get_file_data 363 | 364 | extract_sequence_from_fasta_data 365 | 366 | # 367 | # Get the REBASE data into a hash, from file "bionet" 368 | # 369 | parseREBASE('bionet'); 370 | 371 | for each user query 372 | 373 | If query is defined in the hash 374 | Get positions of query in DNA 375 | 376 | Report on positions, if any 377 | 378 | } 379 | \end{lstlisting} 380 | 381 | 你现在需要编写一个子程序,在DNA中寻找查询的位置。记住\autoref{exam:example5.7}在 \verb|foreach|循环中进行全局查找的技巧,并且牢记在心。说到做到: 382 | 383 | \begin{lstlisting} 384 | Given arguments $query and $dna 385 | 386 | while ( $dna =~ /$query/ig ) { 387 | save the position of the match 388 | } 389 | 390 | return @positions 391 | \end{lstlisting} 392 | 393 | 在你之前使用这个技巧的时候,你仅仅计数了有多少匹配,而没有处理匹配的位置。我们来看看文档找点线索,尤其是文档中的内置函数列表。看起来, \verb|pos|函数可以解决这个问题。它给出了 \verb|m//g|查找中最后一次变量匹配的位置。\autoref{exam:example9.3}演示了主程序,其后是需要的子程序。这是一个简单的子程序,因为像\textit{pos}这样的Perl函数使得问题简单了许多。 394 | 395 | %\textbf{例9-3:为用户的查询制作限制酶切图谱} 396 | \lstinputlisting[label=exam:example9.3,caption={例9.3:为用户的查询制作限制酶切图谱}]{./scripts/example9-3.pl} 397 | 398 | 下面是\autoref{exam:example9.3}的一些示例输出: 399 | 400 | \begin{lstlisting} 401 | Search for what restriction enzyme (or quit)?: AceI 402 | Searching for AceI G^CWGC GC[AT]GC 403 | A restriction site for AceI at locations: 404 | 54 94 582 660 696 702 840 855 957 405 | 406 | Search for what restriction enzyme (or quit)?: AccII 407 | Searching for AccII CG^CG CGCG 408 | A restriction site for AccII at locations: 409 | 181 410 | 411 | Search for what restriction enzyme (or quit)?: AaeI 412 | A restriction site for AaeI is not in the DNA: 413 | 414 | Search for what restriction enzyme (or quit)?: quit 415 | \end{lstlisting} 416 | 417 | 注意子程序\textit{match\_positions}中的 \verb|length($&)|。 \verb|$&|是在正则表达式匹配成功后设置的一个特殊变量。它表示匹配正则表达式的序列。因为\textit{pos}给出的是匹配序列\textit{后面}的第一个碱基的位置,所以你必须减去匹配序列的长度并加一(让碱基开始于位置1而非位置0),这样才是匹配开始的位置。其他的特殊变量包括包含字符串中成功匹配前面的所有内容的 \verb|$`|,和包含字符串中成功匹配后面的所有内容的 \verb|$'|。所以,举个例子: \verb|'123456' =~ /34/|匹配成功,并把这些特殊变量设置为: \verb|$` = '12'|, \verb|$& = '34'|,以及 \verb|$' = '56'|。 418 | 419 | 不可否认我们此处完成的仅仅是个赤裸的骨架而已,但它确实可以工作。参看本章末尾的练习题,其中给出了扩展这个代码的方法。 420 | 421 | \section{Perl的操作} 422 | 在这本指南性的编程书籍中,我们没有讨论基本的算术运算,就已经做的很好的,因为实际上你并不需要比增加计数器的加法更多的内容。 423 | 424 | 然而,包括Perl在内的编程语言的一个重要部分,就是进行数学计算的能力。参看\autoref{chap:chapterab},它展示了Perl中的基本运算。 425 | 426 | \subsection{运算和括号的优先级} 427 | \label{sect:section9.3.1} 428 | 运算有一套优先级规则。这使得语言可以在一行中有多个运算时决定先进行哪个运算。运算的顺序会改变运算的结果,就像下面的例子演示的那样。 429 | 430 | 假设你有 \verb|8 + 4 / 2|这样的代码。如果你先进行除法预算,你会得到 \verb|8 + 2|,或者是 \verb|10|。然而,如果你先进行加法运算,你就会得到 \verb|12 / 2|,或者是 \verb|6|. 431 | 432 | 现在编程语言对运算都赋予了优先级。如果你知道这些优先级,你可以编写 \verb|8 + 4 / 2|这样的表达式,并且你知道它的运算结果。但是这并不可靠。 433 | 434 | 首先,要是你得到了错误的结果会怎样呢?或者,要是其他查看代码的人并没有你这样的记忆力会怎样呢?再或者,要是你记住了一种语言的优先级、但Perl采用的是不同的优先级会怎样呢?(不同的语言确实有不同的优先级规则。) 435 | 436 | 有一种解决办法,这就是\textit{使用括号}。对于\autoref{exam:example9.3},如果你简单的添加上括号: \verb|(8 + ( 4 / 2))|,对于你自己、其他读者以及Perl程序来说,都可以明确无误地知道你想首先进行除法运算。注意包裹在另外一对括号中的“内部”括号,会被首先求值。 437 | 438 | 记住,在复杂的表达式中使用括号来指明运算的顺序。另外,它会让你避免大量的程序调试! 439 | 440 | \section{练习题} 441 | \label{sect:section9.4} 442 | \textcolor{black}{\textit{习题9.1}} 443 | \begin{adjustwidth}{4em}{} 444 | 修改\autoref{exam:example9.3},让它可以从命令行接收DNA;如果它没有被指定,提示用户键入FASTA文件名并读入DNA序列数据。 445 | \end{adjustwidth} 446 | 447 | \textcolor{black}{\textit{习题9.2}} 448 | \begin{adjustwidth}{4em}{} 449 | 修改Exercise 450 | 9.1,从\textit{bionet}文件中读入全部的REBASE限制性内切位点数据,并把它制作成一个散列。 451 | \end{adjustwidth} 452 | 453 | \textcolor{black}{\textit{习题9.3}} 454 | \begin{adjustwidth}{4em}{} 455 | 修改Exercise 9.2,如果不存在DBM文件,就通过存储的REBASE散列生成一个DBM文件,如果DBM文件存在,就直接使用DBM文件。(提前查阅\autoref{chap:chapter10}中关于DBM的更多的信息。) 456 | \end{adjustwidth} 457 | 458 | \textcolor{black}{\textit{习题9.4}} 459 | \begin{adjustwidth}{4em}{} 460 | 修改\autoref{exam:example5.3},报告它找到的基序的位置,即使基序在序列数据中出现多次。 461 | \end{adjustwidth} 462 | 463 | \textcolor{black}{\textit{习题9.5}} 464 | \begin{adjustwidth}{4em}{} 465 | 通过打印出序列、并用酶的名字把限制性内切位点标记出来,为限制酶切图谱添加一个切割位点的图形化展示。你能制作一个处理多个限制性内切酶的图谱吗?你该如何处理重叠的限制性内切位点呢? 466 | \end{adjustwidth} 467 | 468 | \textcolor{black}{\textit{习题9.6}} 469 | \begin{adjustwidth}{4em}{} 470 | 编写一个子程序,返回限制酶切消化片段,就是进行限制性酶切反应后留下的DNA片段。记住要考虑切割位点的位置。(这需要你以另一种方式解析REBASE的\textit{bionet}文件。如果你愿意的话,可以把没有用\^~指明切割位点的限制性内切酶忽略掉。) 471 | \end{adjustwidth} 472 | 473 | 474 | \textcolor{black}{\textit{习题9.7}} 475 | \begin{adjustwidth}{4em}{} 476 | 扩展限制酶切图谱软件,对于非回文识别位点,把相反的另一条链也考虑在内。 477 | \end{adjustwidth} 478 | 479 | \textcolor{black}{\textit{习题9.8}} 480 | \begin{adjustwidth}{4em}{} 481 | 对于没有括号的算术运算,编写一个子程序,根据Perl的优先级规则为其添加上合适的括号。(警告:这是一个相当有难度的练习题,除非你确信有足够的课余时间,否则请跳过该题。对于优先级规则,可以参看Perl的文档。) 482 | \end{adjustwidth} 483 | 484 | -------------------------------------------------------------------------------- /Chapters/chapter_aa.tex: -------------------------------------------------------------------------------- 1 | \chapter{资源} 2 | \label{chap:chapteraa} 3 | \minitoc 4 | 5 | 对于Perl和生物信息学编程来说,有大量的相关资源与材料。此处并不对其进行穷举,但是它包含一些在线的资源和一些印刷版的资源,我认为在你拓展Perl编程技能的时候,你会发现这些资源比较有趣且有用。 6 | 7 | \section{Perl} 8 | Perl的文档非常详尽。它包括FAQs(常见问题集,附带解答)列表,指南,以Unix风格的man手册页形式整理的精确定义,以及特定领域的讨论。有大量的网站,一个叫做CPAN的组织良好的有用的Perl程序仓库,具有可检索档案的新闻组,会议,和许多好的书籍。非常值得花一定的时间去寻找并结交当地的Perl社团。不要害怕去叨扰你的同事,随着你编程技能的提升,他们也会慢慢开始向你进行咨询。 9 | 10 | 我前面已经提到过,Perl是免费的。它是更加庞大的开源运动的一部分,它包括Linux、Apache网络服务器等的开发。既然Perl是免费的,它就依赖于同道中人组成的一个社区团体来开发代码并撰写文档。正因为如此,你可能注意到了有不少文档都有点破碎(对某些来说简直是支离破碎)。尽管如此,这些项目的支持水平绝不亚于最好的商业软件包的支持程度。 11 | 12 | \subsection{网站} 13 | \href{http://www.perl.com}{http://www.perl.com} 14 | 15 | \begin{adjustwidth}{4em}{} 16 | 这是Perl所有内容的起点。不管怎么样,去看看吧。在这里,你会发现更多关于Perl编程各方各面的站点。在这其中,你可能会发现 \href{http://www.perl.org}{http://www.perl.org} 尤其有用。 17 | \end{adjustwidth} 18 | 19 | \subsection{CPAN(Comprehensive Perl Archive Network):Perl综合典藏网} 20 | \href{http://www.cpan.org/}{http://www.cpan.org/} 21 | 22 | \begin{adjustwidth}{4em}{} 23 | CPAN是一个非常重要的资源,也是寻找Perl模块的地方。此外,它还是其他软件、文档和网页链接的仓库。在花时间编写自己的程序之前,先到这里看看是不是已经有写好的程序了。 24 | \end{adjustwidth} 25 | 26 | \subsection{FAQs(Frequently Asked Questions):常见问答集} 27 | \href{http://www.perl.com/pub/v/faqs}{http://www.perl.com/pub/v/faqs} 28 | 29 | \begin{adjustwidth}{4em}{} 30 | FAQs是一个新手最常询问的问题的摘要,同时附带解答,这些解答通常都非常有用。作为一个程序员菜鸟,要想尽快上手,花点时间去读一下FAQs绝对是一个不错的选择,必要时可以进行跳读。 31 | \end{adjustwidth} 32 | 33 | 你至少应该花费足够的时间来阅读FAQs,对哪些问题在FAQs中有对应的存档要有一个大概的了解。在向当地专家寻求帮助或者在新闻组中提问之前,一定要先去检查一下FAQs。重复询问那些在FAQs中已经进行了详尽解答的问题,通常会让人生厌,尤其是在Perl的新闻组中。 34 | 35 | 你会发现Perl的FAQs分成了几个部分。当查阅FAQs时,看看它们上次更新的日期。这对于Perl来说不算是个大问题,当通常来说,你在网上会找到许多过时的信息。 36 | 37 | \subsubsection{初学者} 38 | 在FAQs和文档中有许多专门针对初学者的资料。除了本书以外,还有许多其他适用于初学者的书籍,在该附录的其他地方提到了。在 \href{http://learn.perl.org}{http://learn.perl.org}(当我撰写本书时这还是一个比较新的站点,但看起来非常有前途)上也有一些关于Perl的在线指南和初学者文章。此外,还有一些邮件列表,你可以去订阅,包括叫做 \href{mailto:beginners@perl.org}{beginners@perl.org} 的邮件列表,通过访问 \href{http://lists.perl.org}{http://lists.perl.org} 你可以订阅它。 39 | 40 | \subsection{在线手册} 41 | \href{http://www.perl.com/pub/v/documentation}{http://www.perl.com/pub/v/documentation} 42 | 43 | \begin{adjustwidth}{4em}{} 44 | Perl的手册是在线的,位于前面提到的Perl网站上。同时它也应该安装在了你的计算机上。通过键入 \verb|perldoc perl|你可以访问它。在Unix/Linux系统上,你也可以键入 \verb|man perl|来得到初始的man手册。如其所述,手册被分割成了几部分。比如,要找到Perl内置函数的手册,需要键入 \verb|man perlfunc|或者 \verb|perldoc|。也有HTML版本的手册,可以把它们安装在你本地的计算机上。这是我最喜欢的获取文档的方法,它会给你链接使得导航更加容易,并且如果它被安装在了本地上,甚至在没有联网的情况下都可以使用它。 45 | \end{adjustwidth} 46 | 47 | \subsection{书籍} 48 | 有许多Perl的书籍。其中不少都非常出色,但有些也不好。下面是一个简短的Perl书籍列表,我发现在我的工作中它们是最有用的。 49 | 50 | \textit{Programming Perl, Third Edition},Larry Wall、Tom Christiansen和Jon Orwant著,O'Reilly \& Associates出版\footnote{《Perl语言编程》(第四版):\href{http://item.jd.com/11544992.html}{http://item.jd.com/11544992.html}。}。这是Perl语言发明人撰写的关于Perl的标准书籍。尽管它滞后于最新版本的Perl,但它非常好得解释了一切。所以你安装的绝对权威还是在线的手册。\textit{Programming Perl}涵盖了大量的内部细节,所以它更适合作为参考、指南,当你需要深入细节的内容时,可以把它作为绝妙的故事来看。它展示了语言背后的一些哲学,所以可以通过理解一些计算机科学的思维方式。如果你正好有早期的版本,也是完全可以的;我个人尤其喜欢它的第一版。 51 | 52 | \textit{Perl Cookbook},Tom Christiansen和Nathan Torkington著,O'Reilly \& Associates出版。它被宣称为\textit{Programming Perl}的姊妹篇,确实如此。在这里,你会发现使用Perl来完成不同任务的实例。在许多情况下它都非常有用,如果你要进行许多的Perl编程,花费至少几个小时去研读它是非常值得的。 53 | 54 | \textit{Mastering Algorithms with Perl},Jon Orwant、Jarkho Hietaniemi和John Macdonald著,O'Reilly \& Associates出版。我已经提到过学习算法的重要性,而该书就用Perl演示了许多重要的算法。它解释概念并给出代码,但它并不教授分析和测试算法的数学知识。真正严谨的学习算法的学生可以在Corman、Leiserson和Rivest著的\textit{Introduction to Algorithms}中找到相应的信息。即使你是一个程序员新手,这也是一本很有价值的书,你会找到许多你可以使用的代码。 55 | 56 | \textit{Mastering Regular Expressions},Jeffrey R. Friedl著,O'Reilly \& Associates出版\footnote{《精通正则表达式》(第3版):\href{http://item.jd.com/11070361.html}{http://item.jd.com/11070361.html}。}。一本关于重要主题的好书,很好地涵盖了Perl。 57 | 58 | \textit{Elements of Programming in Perl},Andrew L. Johnson著,Manning Publications出版。这是针对初学者的另一本书。这本书非常好,我推荐把它作为本书的补充。 59 | 60 | \textit{Learning Perl, Third Edition},Randall L. Schwartz和Tom Christiansen著,O'Reilly \& Associates出版\footnote{《Perl语言入门》(第6版):\href{http://item.jd.com/10972653.html}{http://item.jd.com/10972653.html}。}。这是Perl的经典入门指南书籍。它的编写和组织都非常好。如果你从头到尾学习了\textit{Beginning Perl for Bioinformatics},那你阅读\textit{Learning Perl}应该没有什么困难。 61 | 62 | \textit{Object-Oriented Perl},Damian Conway著,Manning Publications出版。一本很棒的书,其中涵盖的主题对于程序员菜鸟和老鸟都能受益匪浅。 63 | 64 | \subsection{会议} 65 | \textit{O'Reilly开源大会(O'Reilly Open Source Convention)}。该大会现在包括一年一度的Perl会议。这是一个机会,可以参加各种各样的讨论和报告,结识形形色色的Perl实践者。此外还有常规的YAPC(yet another Perl conference)会议;你可以在Perl的主站点上找到它的详细信息。 66 | 67 | \subsection{新闻组} 68 | Per新闻组是程序员的一个重要资源。如果你从未看到过它们,那是因为它们通过网络(以及其他方式)进行交流。它们让你可以给网络上的一大组人写一个信息,可以针对成百上千个特定主题中的一个。如果你遇到了一个问题,在Perl文档和FAQs中都找不到解答方法,在新闻组中搜索针对这个问题的主题往往能得到答案。如果找不到现成的答案,你也可以在新闻组中发表一个问题,但这通常并不是必需的。 69 | 70 | 我想强调一下这个资源真的非常有用。弊端就是这通常倾向于“低信噪比”:换言之,在新闻组中常常有大量的无信息材料。但它还是值得一看的,即使是负面的回复(没有给出问题的已知解决方法)也会节省你的时间和精力。 71 | 72 | 在comp.lang.perl层级中有许多和Perl相关的新闻组。搜索引擎deja.com(最近卖给了google.com,但是仍然可以访问)\footnote{请使用:\href{https://groups.google.com}{https://groups.google.com}。}让你可以搜索这些新闻组的档案。对于特定新闻组的更多信息可以在Perl的FAQs中找到。比如,许多特定的Perl模块都有它们自己的新闻组、邮件列表或者网站。CPAN网站是另一个可以找到可检索新闻组档案的地方。 73 | 74 | \section{计算机科学} 75 | 尽管你是通过编程编写生物学应用,你还是会发现自己常常一不留神就进入了传统计算机科学的世界。这里是一些已经发表的资源,可以帮助你找到自己的方向。 76 | 77 | \subsection{算法} 78 | \textit{Mastering Algorithms with Perl},Jon Orwant、Jarkho Hietaniemi和John Macdonald著,O'Reilly \& Associates出版。对于使用Perl编程的非计算机专业的科学家来说,这是最好的书籍。 79 | 80 | \textit{Introduction to Algorithms},Thomas H. Cormen、Charles E. Leiserson和Ronald L. Rivest著,MIT Press and McGraw-Hill出版\footnote{《算法导论》(原书第3版):\href{http://item.jd.com/11144230.html}{http://item.jd.com/11144230.html}。}。这绝对是关于算法的一本好书——从许多方面来说,这是最好的一本书。不管对于研究生还是大学生,它都是标准的大学教材之一(按理来说就是标准的教材)。不管是作为教材书籍还是作为参考书籍,它都完全能够胜任。它的目标读者是计算机科学专业的学生,所以里面涉及相当数量的数学知识,但即使是非数学的程序员来说,也会发现这本书非常有用。 81 | 82 | \textit{Fundamentals of Algorithmics},Gilles Brassard和Paul Bratley著,Prentice Hall出版。对于算法技术的浅显概述。 83 | 84 | \textit{Algorithms on Strings, Trees, and Sequences: Computer Science and Computational Biology},Dan Gusfield著,Cambridge University Press出版。这本书专注于字符串相关的算法,包括序列比对等主题。它非常详尽,但即使是这样,也不是面面俱到,因为这是一个一场庞大的领域。这是专门针对字符串算法的最后的资源,有大量关于生物学序列相似性的信息。 85 | 86 | 下面的书籍共进阶学习使用。 87 | 88 | \textit{The Design and Analysis of Computer Algorithms},Alfred V. Aho、John E. Hopcroft和Jeffrey D. Ullman著,Addison-Wesley出版。这是关于算法科学的经典书籍。 89 | 90 | \textit{Introduction to Parallel Algorithms and Architectures: Arrays, Trees, Hypercubes},Frank Thomson Leighton著,Morgan Kaufmann出版。一个全面且严谨的教材和参考。 91 | 92 | \textit{Randomized Algorithms},Rajeev Motwani和Prabhakar Raghavan著,Cambridge University Press出版\footnote{《随机算法 》:\href{http://item.jd.com/10000060.html}{http://item.jd.com/10000060.html}。}。一本清晰而严谨的书。 93 | 94 | \subsection{软件工程} \textit{Software Engineering, Second Edition},Ian Sommerville著,Addison-Wesley出版\footnote{《软件工程》(原书第9版):\href{http://item.jd.com/10645053.html}{http://item.jd.com/10645053.html}。}。一本好的通用的书,它涵盖了重要的主题,同时避开了对立的竞争性理论的相关讨论。 95 | 96 | \subsection{计算机科学理论} 97 | \textit{Introduction to Automata Theory, Languages, and Computation, Second Edition},John E. Hopcroft、Rajeev Motwani和Jeffrey D. Ullman著,Addison-Wesley出版\footnote{《自动机理论、语言和计算导论》(原书第3版):\href{http://item.jd.com/10058560.html}{http://item.jd.com/10058560.html}。}。关于计算机科学理论的经典教材。 98 | 99 | \textit{Computers and Intractability: A Guide to the Theory of Np-Completeness},Michael R. Garey和David S. Johnson著,W.H. Freeman \& Co出版。关于这个主题的经典、超赞的一本书。 100 | 101 | \subsection{通用编程} 102 | \textit{The Unix Programmers Manual},Steven V. Earhart等著,Harcourt、Brace和Jovanovich School出版。关于Unix(不管是那个版本的Unix)的这个手册,是计算机科学中重点针对编程的速成课。交互式程序的设计,以及管道、重定向、进程的概念,等等都已经称为编程中巨大成功的范例之一。该手册对系统进行了概述:第一部分描述用户程序;第二部分和第三部分描述编程界面。可编程的shell,以及grep、awk和sed程序是Perl的主要灵感。 103 | 104 | \textit{The C Programming Language},Brian W. Kernighan和Dennis M. Ritchie著,Prentice Hall PTR出版\footnote{《C程序设计语言》(第2版):\href{http://item.jd.com/10057446.html}{http://item.jd.com/10057446.html}。}。C和C++是生物信息学中的重要编程语言,而这本经典的书籍教授的是C。如果你研读了全书,并且尝试了所有的编程练习,那么你已经有了良好的编程训练。 105 | 106 | \textit{Structure and Interpretation of Computer Programs},Harold Abelson、Gerald Jay Sussman和Juke Sussman著,MIT Press出版\footnote{《计算机程序的构造和解释》(原书第2版):\href{http://item.jd.com/10057478.html}{http://item.jd.com/10057478.html}。}。一本真的非常有趣的书籍,在学习Lisp方言的过程中对编程进行了深入讲解。 107 | 108 | \textit{The Unix Programming Environment},Brian W. Kernighan和Robert Pike著,Prentice Hall出版\footnote{《UNIX编程环境》:\href{http://item.jd.com/11423589.html}{http://item.jd.com/11423589.html}。}。这本书非常有趣,并且它讨论了好的软件设计。 109 | 110 | \section{Linux} 111 | 如果你有一个Linux操作系统,你就有了整个系统的源代码(对于一些Unix系统来说也是这样)。(如果它没有被安装,你可以从发行版CD中得到它,从网站 \href{http://www.linux.org}{http://www.linux.org} 或者制造你使用的Linux版本的公司的网站上得到发行版CD。)这是一个巨大的资源。你可以看看任何一个程序,甚至是操作系统,是如何被编写的。现在你真的进入编程的世界了。 112 | 113 | \section{生物信息学} 114 | 生物信息学是一个相对较新的学科,吸引了众多的目光,所以可用的资源也在飞速增长。下面是一些帮助你入门的书籍和其他资源。 115 | 116 | \subsection{书籍} 117 | \textit{Developing Bioinformatics Computer Skills},by Cynthia Gibas and Per Jambeck著,O'Reilly \& Associates出版\footnote{《生物信息学中的计算机技术》。}。对于初学者来说,这是相当好的一本书。它涵盖了Linux工作站的构建,以及许多优秀且廉价的生物信息学程序的安装与使用。它教授的是如何去使用生物信息学程序,而非如何去编程。它是现有的最实用的一本生物信息学书籍。 118 | 119 | \textit{Introduction to Computational Biology: Maps, Sequences and Genomes},Michael S. Waterman著,CRC Press出版\footnote{《计算生物学导论:图谱、序列和基因组》:\href{http://item.jd.com/10005674.html}{http://item.jd.com/10005674.html}。}。这是一本经典的书籍,主要从统计学的角度进行讲解。 120 | 121 | \textit{Bioinformatics: A Practical Guide to the Analysis of Genes and Proteins, Second Edition}Andreas D. Baxecvanis和B.F. Francis Ouellette编著,John Wiley \& Sons出版。包括由众多作者编写的多个章节,涉及比较广泛的主题。 122 | 123 | \subsection{政府组织} 124 | 最基本的东西。下面这些网站是最重要的由政府资助的生物信息学组织。 125 | 126 | \href{http://www.ncbi.nlm.nih.gov/}{http://www.ncbi.nlm.nih.gov/}: 127 | 128 | \begin{adjustwidth}{4em}{} 129 | NCBI(National Center for Biotechnology Information):国家生物技术信息中心,美国政府中心。 130 | \end{adjustwidth} 131 | 132 | \href{http://www.embl.org/}{http://www.embl.org/}: 133 | 134 | \begin{adjustwidth}{4em}{} 135 | EMBL(European Molecular Biology Laboratory):欧洲分子生物学实验室,欧洲联合实验室。 136 | \end{adjustwidth} 137 | 138 | \href{http://www.ebi.ac.uk/}{http://www.ebi.ac.uk/}: 139 | 140 | \begin{adjustwidth}{4em}{} 141 | EMBL中的EBI(European Bioinformatics Institute):欧洲生物信息研究所。 142 | \end{adjustwidth} 143 | 144 | \subsection{会议} 145 | 生物信息学一直是各种生物学会议的一部分,比如,关于测序的冷泉港会议(Cold Spring Harbor conferences)。现在有许多涉及该方面的会议,通常都被冠以“基因组学”。下面是几个有趣的会议: 146 | 147 | \begin{itemize} 148 | \item \textit{ISMB(Intelligent Systems for Molecular Biology):国际分子生物学智能系统会议},现在是它的第九个年头\footnote{译者注:指的是2001年。一年一届,2015年举办的是第23届。} 149 | \item \textit{生物信息学开放源代码会议(Bioinformatics Open Source Conference)},\href{http://www.bioinformatics.org/}{http://www.bioinformatics.org/} 150 | \item \textit{RECOMB(Conference on Computational Molecular Biology)}:计算分子生物学会议 151 | \end{itemize} 152 | 153 | \section{分子生物学} 154 | \textit{Recombinant DNA},James Watson等著,W.H. Freeman \& Co出版。相对于这么一个快速发展的领域,该书显得有点陈旧了,但它还是一本引领程序员和计算机科学家进入生物信息学领域的佳作。许多标准的技术都用精彩的插图进行了清晰简洁的解释。去找一下它的第二版,看看能不能找到。 155 | 156 | \textit{Molecular Biology of the Gene, Fourth Edition},James Watson等著,Addison-Wesley出版\footnote{《基因的分子生物学》(第七版):\href{http://item.jd.com/11672603.html}{http://item.jd.com/11672603.html}。}。分子生物学的经典书籍。它非常详尽,从知识面的覆盖来说,它确实有些过时了,但仍不失为经典之作。对于基础知识可以好好参考该书。 157 | 158 | \textit{Molecular Cell Biology, Fourth Edition},Harvey Lodish等著,W.H. Freeman \& Co出版。关于细胞生物学的优秀且宽泛的介绍性概述。 159 | 160 | \textit{《Lewin基因X(中文版)》\footnote{译者补充。}:\href{http://item.jd.com/11159665.html}{http://item.jd.com/11159665.html}}。该书对分子生物学和分子遗传学进行了精彩的论述,内容涵盖了基因的结构、序列、组织和表达,是分子生物学和分子遗传学最经典的名著之一。 161 | -------------------------------------------------------------------------------- /Chapters/chapter_colophon.tex: -------------------------------------------------------------------------------- 1 | \chapter*{版权页} 2 | \label{chap:colophon} 3 | %\minitoc 4 | 5 | 我们希望看到的结果是读者的评论、我们自己的实验,以及来自分布式频道的反馈。独特的封面反映了我们对于不同技术主题的独特的态度,把个性和人性引入到了可能枯燥无味的主题中。 6 | 7 | \textit{Beginning Perl for Bioinformatics}这本书封面上的动物是青铜蛙(\textit{Rana clamitans})和美国牛蛙(\textit{Rana catesbeiana})的蝌蚪。 8 | 9 | 蝌蚪是青蛙和蟾蜍的幼虫。它们是水生动物,刚孵化出来的时候,有着大而圆的头部和长而扁的尾巴。经过一个复杂的变态过程,蝌蚪从小的鱼形生物变成了更为人熟知的青蛙和蟾蜍。根据物种的不同,变态过程需要从10天到3年不等的时间。 10 | 11 | 在变态的第一个阶段,蝌蚪的后腿先萌芽,头部开始扁平起来,尾巴逐渐变短。在它生命的早期,蝌蚪主要以硅藻、水藻和少量的浮游生物为食。随着变态的继续,当它的消化系统从以素食为主变成肉食时,它停止进食,并开始重吸收自己的尾巴作为营养来源。在变态的最后阶段,蝌蚪的前腿出现、鄂形成、骨架硬化,并且随着肺的发育腮会逐渐消失。一个短暂的时间之后,蝌蚪从水中出来,重吸收尾巴的最后部分,开始像青蛙或者蟾蜍那样跳跃。 12 | 13 | Mary Anne Weeks Mayo是\textit{Beginning Perl for Bioinformatics}的出版商编辑和文字编辑。Matt Hutchinson和Jane Ellin进行了质量控制。Edie Shapiro、Matt Hutchinson和Derek DiMatteo提供了出版援助。Ellen Troutman-Zaig编写了索引。 14 | 15 | Ellie Volckhausen基于Edie Freedman的系列设计,设计了本书的封面。封面图片是Lorrie LeJeune创作的原版插图。Emma Colby使用Adobe's ITC Garamond字体、基于Quark\texttrademark XPress 4.1对封面进行了排版。 16 | 17 | Melanie Wang基于David Futato的系列设计,设计了内部的版式布局。Neil Walls使用Mike Sierra创建的工具把文件从SGML转换到了FrameMaker 5.5.6。文本的字体是Linotype Birka,标题的字体是Adobe Myriad Condensed,代码的字体是LucasFont's TheSans Mono Condensed。书中出现的插图都是由Robert Romano和Jessamyn Read使用Macromedia FreeHand 9和Adobe Photoshop 6制作的。忠告和警告由Christopher Bing绘制。Lorrie LeJeune撰写了该版权页。 18 | -------------------------------------------------------------------------------- /Chapters/chapter_perface.tex: -------------------------------------------------------------------------------- 1 | \setcounter{page}{1} 2 | \chapter*{前\quad 言} 3 | \markboth{前言}{} 4 | %\minitoc % Creating an actual minitoc 5 | 6 | \section*{什么是生物信息学?} 7 | \markboth{前言}{什么是生物信息学?} 8 | 生物学数据正在飞速增长。一段时间一来,GenBank和PDB(Protein Data 9 | Bank)等公共数据库都在以指数级别增长。随着万维网(World Wide 10 | Web)的到来,以及快速的网络连接,在世界上的任意一个地方,都可以快速、简便且廉价地获取到这些数据库中的数据和大量具有特定用途的程序。作为结果,在生物学研究的进步中,基于计算机的工具现在正起着越来越关键的作用。 11 | 12 | \textit{生物信息学}是一个快速发展的学科领域,它应用计算工具和技术来管理并分析生物学数据。生物信息学这个术语还相对较新,在此处的定义,它还包含了“计算生物学”和其他专业术语的含义。在生物学研究中使用计算机,要比生物信息学专业术语的使用早许多年。比如,通过X射线晶体数据来确定蛋白质的3D结构,一直以来都是依赖于计算机分析。在本书中,我把在生物学研究中计算机的使用就看做生物信息学。但是,需要强调的重要一点是,其他人可能会把这些术语严格区分开来。特别的是,当指代对于\textit{C. elegans}(线虫)、\textit{Arabidopsis}(拟南芥)和\textit{Homo sapiens}(人)等物种的全基因组进行大规模测序和分析时的数据和技术时,通常都会使用生物信息学这个术语。 13 | 14 | \subsection*{生物信息学能做什么} 15 | \markboth{前言}{生物信息学能做什么} 16 | 这是在实际中应用生物信息学的一个简单的例子。假设你发现了一个非常有趣的小鼠DNA的片段,你猜想它可能会为人类的致命脑肿瘤的发生发展提供线索。在对DNA进行测序后,你使用基于网络的序列比对工具,比如BLAST,在GenBank和其他数据资源中进行了检索。尽管你找到了一些相关的序列,但是你并没有找到你猜想的它和脑肿瘤之间联系的直接的证据或其他信息。你知道这些公共的遗传数据库每天都在快速增长这。你可能会想每天都进行一次检索,把结果和上一次的检索结果进行比较,来看看在数据库中是不是有新的东西出现。但这每天都会花费一两个小时的时间!幸运的是,你会Perl。经过一天的努力,你(使用BioPerl等模块)编写了一个程序,可以自动每天对你的DNA序列在GenBank中进行一次BLAST,并把结果和前一天的结果进行比较,如果有任何变换它就会发送邮件给你。这个程序是如此的有用,以至于你开始把它应用在其他的序列上,而你的同时也开始使用它。在几个月的时间内,你一天的努力节省了你团队数周的时间。这个例子来源于真实事件。现在你已经可以使用现成的程序来达成你的目的,甚至有网站可以让你提交自己的DNA序列和邮箱地址,它们会为你完成所有的工作! 17 | 18 | 当你把计算的强大能力应用的生物学问题中时,这只是一个很小的例子。这就是生物信息学。 19 | 20 | \section*{关于本书} 21 | \markboth{前言}{关于本书} 22 | 本书是一个指南,直到生物学家如何去编程,并且它是为程序员新手设计的。除了极个别以外,所有的例子和练习题使用的都是生物学数据。本书的目的有两个:教授编程技能,同时把它们应用到感兴趣的生物学领域中。 23 | 24 | 我想让你快速上手,并且尽快且愉快得进行编程。我会进行简洁的解释,而不会把一切都囊括其中。我不会对编程概念进行严格的定义,因为这可能会喧兵夺主,干扰你的学习。 25 | 26 | Perl语言使得通过快速编写真实的程序来开始学习称为可能。当你继续阅读本书和在线的Perl文档时,你会逐渐补充细节性的知识,在实践中学习,不断提高你对编程概念的理解。 27 | 28 | 根据你学习风格的不同,可能会通过不同的方式找到这些材料。一种方式,就像国王郑重地对爱丽丝说的那样,“从开始的地方开始吧,一直读到末尾,然后停止。”(《爱丽丝漫游仙境》中的这句话常常被用来作为算法的一个诙谐的定义。)作为一本叙述性的教材,本书的材料就是以从头到尾阅读的方式进行组织的。 29 | 30 | 另一种方式是把程序摘抄下来,放到你的计算机中,运行它们,看看它们都做了什么,可能还尝试一下去改变程序中的某个地方,看看你的修改有什么影响。这种方式可能会和快速浏览各章节的文字结合起来。当程序员学习一个新的编程语言时,这是最常用的一种学习方式。基本上,你通过人造例子进行学习,目的是真实的程序。 31 | 32 | 任何因为生物信息学而学习perl编程的读者,都应该尝试一下大多数章节末尾的练习题。它们基本上是按照由易到难的顺序进行排列的,并且排在后面的一些练习题相当有难度,可能作为课堂项目更加合适一些。因为在Perl中处理问题的方法不止一种,所以对于每一个练习题来说都没有绝对正确的唯一答案。如果你是一个程序员新手,你可以尝试尽量用不同的方法来解答一个练习题,那么对于这个练习题你就已经很好的掌握了。对于练习题,我推荐的解答可以在 \href{http://www.oreilly.com/catalog/begperlbio}{http://www.oreilly.com/catalog/begperlbio} 找到。 33 | 34 | 我希望,本书中的材料不仅仅作为实践性的指南。如果你觉得生物信息学本身是一个前途无限的研究方向或者是正在进行的研究的附属物,它还能引领你编写出研究性的程序。 35 | 36 | \section*{本书为谁编写} 37 | \markboth{前言}{本书为谁编写} 38 | 本书是为生物学家编写的实践性编程指南。 39 | 40 | 在生物学研究和发展中,编程技能现在已经是必需的了。历史上,对于实验室的生物学家来说,编程并不被看做一个关键性的技能。然而,如今生物学的发展趋势使得对于大规模数据的计算机分析成为了许多研究程序的重中之重。本书意在作为繁忙的生物学家手头的一本不算厚的教程,帮助它们获得实践性的生物信息学编程技能。所以,如果你是一个午休要学习编程的生物学家,这本书就是为你编写的。它的目的是教会你快速、愉快地编写有用的实践性的生物信息学程序。 41 | 42 | 本书把编程作为一个重要的实验室技能,它是一个编程指南,包括了一堆的手册或者编程技术,这些在实验室中都是急需且非常有用的。但是它的初衷还是教授编程,而不是构建一个全面的工具包。 43 | 44 | 在实验室的实验台和计算机程序之间,确实有一些技能和方法上的相似之处。不管是在一天的课程中,还是在整个的生物学研究职业生涯中,许多人确实都能够从跑胶转到编写Perl程序。当然,编程是一个有着自己独特方法和专业术语的独特学科,所以必须以其独特的方式学习特有的术语。但确实有“杂交”存在(如果你能原谅这两个学科之间的隐喻)。 45 | 46 | 本书的练习题由不同难度的题目组成,因此既可以把它当做课堂教材,也可以用来自学。(几乎)所有的例子和练习都是基于真实的生物学问题,所以本书将对大多数常见的生物信息学编程问题和最常见的基于计算机的生物学数据进行一个很好的介绍。 47 | 48 | 本书的网站,\href{http://www.oreilly.com/catalog/begperlbio}{http://www.oreilly.com/catalog/begperlbio},包含了书中的所有程序代码便于下载,既包括练习和解答,也包括勘误表和其他的一些信息。\footnote{程序代码,或者简称代码,表示一个计算机程序——一个程序员写到一个文件中的真实的Perl语言命令。} 49 | 50 | \section*{为什么我应该学习编程?} 51 | \markboth{前言}{为什么我应该学习编程?} 52 | 因为许多研究人员把他们的工作描述为“生物信息学”,但它们并不编写程序,而是使用其他人编写的程序,所以你可能会问,“我真的需要学习编程才能做生物信息学吗?”在某种层面上讲,答案是否定的,你并不需要学习编程。使用现成的工具,你可以完成很多的工作,而且有相关的书籍和文档帮助你学习这些工具的使用。但是从另一个更高的层面上讲,答案因问题的不同而异。当你用现成的工具无法完成你要做的东西时会发生什么?当你无法找到一个工具来完成你实际的一个任务、而且你找不到一个人可以为你编写程序时会发生什么? 53 | 54 | 从这点来看,你需要学习编程。即使你仍然主要依赖于现有的程序和工具,去学习编程从而能够写出小的程序也是值得的。小的程序会令人难以置信的有用。比如,通过一定的练习,你会学会编写程序来运行其他的程序,从而节省你大把的时间,避免你坐在计算机前手动去做这些事情。 55 | 56 | 许多科学家都是从编写小的程序开始的,然后发现他们真的很喜欢编程。作为一名程序员,你永远都不需要担心找不到满足你需要的合适的工具,因为你可以自己编写它们。本书就是助你起步的。 57 | 58 | \section*{本书的结构} 59 | \markboth{前言}{本书的结构} 60 | 本书总共包含十三章和两个附录。下面是对它们的一个简短介绍: 61 | 62 | \autoref{chap:chapter1} 63 | \begin{adjustwidth}{4em}{0cm} 64 | 本章涵盖了分子生物学中一些关键性的概念,以及生物学和计算机科学是纠缠在一起的。 65 | \end{adjustwidth} 66 | 67 | \autoref{chap:chapter2} 68 | \begin{adjustwidth}{4em}{0cm} 69 | 本章向你展示如何让Perl在你的计算机上运行起来。 70 | \end{adjustwidth} 71 | 72 | \autoref{chap:chapter3} 73 | \begin{adjustwidth}{4em}{0cm} 74 | \autoref{chap:chapter3}对程序员完成他们工作的方式进行了概述。解释了一些好的程序员使用的最重要的实践性的策略,并对如何寻找编程过程中遇到的问题的答案进行了详细的规划。通过简短的描述性实例的分析,使这些观点更加具体化,展示程序员是如何针对一个问题寻找解决方案的。 75 | \end{adjustwidth} 76 | 77 | \autoref{chap:chapter4} 78 | \begin{adjustwidth}{4em}{0cm} 79 | 在\autoref{chap:chapter4}中,你开始使用DNA和蛋白质来编写Perl程序。编写程序把DNA转录成RNA,把序列片段连接起来,获得DNA的反向互补序列,从文件读取序列数据,等等。 80 | \end{adjustwidth} 81 | 82 | \autoref{chap:chapter5} 83 | \begin{adjustwidth}{4em}{0cm} 84 | 本章继续示范Perl语言的基础,编写程序查找DNA或蛋白质中的基序,实现通过键盘与用户的交互,把数据保存到文件中,使用循环和条件测试,使用正则表达式,以及操作字符串和数组。 85 | \end{adjustwidth} 86 | 87 | \autoref{chap:chapter6} 88 | \begin{adjustwidth}{4em}{0cm} 89 | 本章在两个方向上拓展了Perl的基础知识:一个是子程序,它是进行结构化编程的一种重要的方式,一个是Perl调试器的使用,它可以在运行Perl程序的时候对其进行详细的检查。 90 | \end{adjustwidth} 91 | 92 | \autoref{chap:chapter7} 93 | \begin{adjustwidth}{4em}{0cm} 94 | 遗传突变对于生物学来说是最基本的,通过使用Perl中的随机数生成器可以把以随机事件对其进行建模。本章使用随机数来生成DNA序列数据集,不断得突变DNA序列。循环,子程序和词汇作用域也会在本章中进行讨论。 95 | \end{adjustwidth} 96 | 97 | \autoref{chap:chapter8} 98 | \begin{adjustwidth}{4em}{0cm} 99 | 本章演示了如何使用遗传密码把DNA翻译成蛋白质。它还涵盖了Perl编程语言的更多内容,比如散列数据类型、排序和未排序的数组、折半查找、关系型数据库、DBM以及如何处理FASTA格式的序列数据。 100 | \end{adjustwidth} 101 | 102 | \autoref{chap:chapter9} 103 | \begin{adjustwidth}{4em}{0cm} 104 | 本章包含对Perl正则表达式的介绍。本章的主要焦点是编写程序来计算一个DNA序列的限制酶切图谱。 105 | \end{adjustwidth} 106 | 107 | \autoref{chap:chapter10} 108 | \begin{adjustwidth}{4em}{0cm} 109 | GenBank(Genetic Sequence Data Bank)对于现代生物学和生物信息学是非常重要的。在本章中,你会学习如何编写程序从GenBank文件和库中提取信息。你也会制作一个数据库,来创建自己的对于GenBank库的快速访问和检索。 110 | \end{adjustwidth} 111 | 112 | \autoref{chap:chapter11} 113 | \begin{adjustwidth}{4em}{0cm} 114 | 本章编写一个能解析PDB(Protein Data Bank)文件的程序。在编写这个程序的过程中,会遇到一些有趣的Perl技术,比如查找并迭代大量的文件,以及在Perl程序中控制其他的生物信息学程序。 115 | \end{adjustwidth} 116 | 117 | \autoref{chap:chapter12} 118 | \begin{adjustwidth}{4em}{0cm} 119 | \autoref{chap:chapter12}逐步编写一些可以解析BLAST输出文件的代码。此外还会提到BioPerl项目与它的BLAST解析器,以及在Perl中格式化输出的其他一些方法。 120 | \end{adjustwidth} 121 | 122 | \autoref{chap:chapter13} 123 | \begin{adjustwidth}{4em}{0cm} 124 | \autoref{chap:chapter13}展望了一些超越本书范畴的主题。 125 | \end{adjustwidth} 126 | 127 | \autoref{chap:chapteraa} 128 | \begin{adjustwidth}{4em}{0cm} 129 | 此处收集的是Perl和生物信息学编程的相关资源,比如书籍和网站。 130 | \end{adjustwidth} 131 | 132 | \autoref{chap:chapterab} 133 | \begin{adjustwidth}{4em}{0cm} 134 | 这是对本书中涉及到的Perl知识点的总结,还有一些其他的东西。 135 | \end{adjustwidth} 136 | 137 | \section*{本书中使用的约定} 138 | \markboth{前言}{本书中使用的约定} 139 | 本书中使用下面这些约定: 140 | 141 | \textit{斜体(Italic)} 142 | \begin{adjustwidth}{4em}{0cm} 143 | 用于命令、文件名、目录名、变量、模块、URLs和术语的第一次使用 144 | \end{adjustwidth} 145 | 146 | \texttt{等宽(Constant width)} 147 | \begin{adjustwidth}{4em}{0cm} 148 | 用于代码实例和展示命令的输出 149 | \end{adjustwidth} 150 | 151 | %\begin{adjustwidth}{4em}{4em} 152 | %\shadowbox{ 153 | %\parpic[l]{ 154 | %\includegraphics[width=1cm]{../figures/note.png} 155 | %\includegraphics[width=1cm]{note.png} 156 | %} 157 | %\noindent 158 | %该图标表示提醒,注意旁边的文字非常重要。 159 | %} 160 | %\end{adjustwidth} 161 | 162 | %\vspace*{\baselineskip} 163 | 164 | %\begin{adjustwidth}{4em}{4em} 165 | %\shadowbox{ 166 | %\parpic[l]{ 167 | %\includegraphics[width=1.1cm]{warning.png} 168 | %} 169 | %\noindent 170 | %该图表表示和旁边文字相关的一个警告。 171 | %\hspace{2.55cm} 172 | %} 173 | %\end{adjustwidth} 174 | 175 | \begin{table}[h] 176 | \begin{center} 177 | \begin{tabu} to 0.85\linewidth {|X[1,r,m]X[15,l,m]|} 178 | \tabucline{-} 179 | \includegraphics[width=1cm]{note.png} & 该图标表示提醒,注意旁边的文字非常重要。\\ 180 | \tabucline{-} 181 | \end{tabu} 182 | \end{center} 183 | \end{table} 184 | \vspace{-25pt} 185 | 186 | \begin{table}[h] 187 | \begin{center} 188 | \begin{tabu} to 0.85\linewidth {|X[1,r,m]X[15,l,m]|} 189 | \tabucline{-} 190 | \includegraphics[width=1.1cm]{warning.png} & 该图标表示和旁边文字相关的一个警告。\\ 191 | \tabucline{-} 192 | \end{tabu} 193 | \end{center} 194 | \end{table} 195 | \vspace{-25pt} 196 | 197 | \section*{评论和问题} 198 | \markboth{前言}{评论和问题} 199 | 请把关于本书的评论和问题邮寄给出版商: 200 | 201 | \begin{adjustwidth}{4em}{0cm} 202 | O'Reilly \& Associates, Inc.\\ 203 | 1005 Gravenstein Highway North\\ 204 | Sebastopol, CA 95472\\ 205 | (800) 998-9938 (in the United States or Canada)\\ 206 | (707) 829-0515 (international/local)\\ 207 | (707) 829-0104 (fax) 208 | \end{adjustwidth} 209 | 210 | 本书有一个网页,上面罗列了勘误表、例子以及其他的一些信息。你可以访问该网页: 211 | 212 | \href{http://www.oreilly.com/catalog/begperlbio}{http://www.oreilly.com/catalog/begperlbio} 213 | 214 | 要对本书进行评论或者询问技术性的问题,请发邮件至: 215 | 216 | \href{bookquestions@oreilly.com}{bookquestions@oreilly.com} 217 | 218 | 关于书籍、会议、资源中心和O'Reilly网络的更多信息,请访问O'Reilly的网站: 219 | 220 | \href{http://www.oreilly.com}{http://www.oreilly.com} 221 | 222 | \section*{致谢} 223 | \markboth{前言}{致谢} 224 | 我想感谢我的编辑Lorrie LeJeune,以及O'Reilly \& Associates中的每一个人,感谢它们的技能、热情、支持和耐心;感谢我的技术审阅人Cynthia Gibas、Joel Greshock、Ian Korf、Andrew Martin、Jon Orwant和Clay Shirky,感谢它们的帮助和细节性的审阅。我还要感谢M. Immaculada Barrasa、Michael Caudy、Muhammad Muquit和Nat Torkington,感谢他们对特定章节给出的杰出的帮助。 225 | 226 | 此外,还要感谢James Watson,是他的经典教材\textit{The Molecular Biology of the Gene}\footnote{译者注:《基因的分子生物学》。}首次让我对生物学产生了兴趣;感谢Larry Wall发明发展了Perl;感谢Murray Hill, NJ的贝尔实验室中的同事,是他们教授了我计算机科学。感谢Beverly Emmanuel、David Searls以及后来的Chris Overton,他们在宾夕法尼亚大学和费城儿童医院中创建了计算生物学和信息实验室,负责人类基因组计划中的第22号染色体,它们给我提供了我的第一份生物信息学工作。感谢贝尔实验室和Upenn的计算机与信息科学系的Mitch Marcus,他坚持让我借走它的\textit{Programming Perl}\footnote{译者注:《Perl语言编程》。}并进行尝试。我还要感谢墨卡托遗传学和福克斯$\textbullet$蔡斯癌症中心的同事,感谢他们对我生物信息学工作的支持。 227 | 228 | 最后,我要感谢支持我写作的朋友们,尤其是我的父母Edward和Geraldine,我的兄弟姐妹Judi、John和Thom,我的妻子Elizabeth,以及我的孩子们Rose、Eamon和Joe。 229 | 230 | %\newpage 231 | \clearpage 232 | \thispagestyle{empty} 233 | -------------------------------------------------------------------------------- /Chapters/cover.tex: -------------------------------------------------------------------------------- 1 | \begin{titlepage} 2 | \thispagestyle{empty} 3 | \begin{figure}[ht] 4 | \begin{center} 5 | \includepdf[width=\paperwidth]{Frontmatter.jpg} 6 | \end{center} 7 | \end{figure} 8 | \null 9 | \thispagestyle{empty} 10 | \newpage 11 | \end{titlepage} 12 | 13 | -------------------------------------------------------------------------------- /Chapters/cover_en.tex: -------------------------------------------------------------------------------- 1 | \thispagestyle{empty} 2 | %\begin{titlepage} 3 | \begin{center} 4 | \includegraphics[width=\textwidth,height=\textheight]{bpfb1.jpg} 5 | \end{center} 6 | 7 | % Insert a blank page 8 | \newpage 9 | \null 10 | \thispagestyle{empty} 11 | \newpage 12 | %\end{titlepage} 13 | 14 | -------------------------------------------------------------------------------- /Chapters/cover_zh.tex: -------------------------------------------------------------------------------- 1 | \begin{titlepage} 2 | \begin{center} 3 | 4 | %\vspace*{0.2cm} 5 | 6 | { \Large \itshape 天津医科大学\qquad 生物医学工程与技术学院}\\ 7 | { \Large \itshape 生物信息学专业\qquad 《分子生物计算》教材}\\ 8 | 9 | \vspace*{3cm} 10 | 11 | % Title 12 | %\rule{\linewidth}{0.5mm} \\[0.4cm] 13 | { \Huge \bfseries Perl语言在生物信息学中的应用\\} 14 | { \Huge \bfseries ——基础篇 \\[0.5cm] } 15 | %\rule{\linewidth}{0.5mm} \\[1.5cm] 16 | 17 | % Author and supervisor 18 | \noindent 19 | \begin{flushright} 20 | \LARGE 21 | \textit{伊现富}\qquad 译\\ 22 | 天津医科大学 23 | \end{flushright} 24 | 25 | \vspace*{1cm} 26 | \rule{\linewidth}{0.5mm} \\[1.5cm] 27 | 28 | { \Large \itshape An Introduction to Perl for Biologists}\\ 29 | \vspace*{1.5cm} 30 | 31 | { \Huge \bfseries Beginning Perl for Bioinformatics\\} 32 | \noindent 33 | \begin{flushright} 34 | \LARGE 35 | \textit{James Tisdall}\\ 36 | \end{flushright} 37 | 38 | \vfill 39 | 40 | % Bottom of the page 41 | {\Large \today} 42 | 43 | \end{center} 44 | 45 | % Insert a blank page 46 | \newpage 47 | \null 48 | \thispagestyle{empty} 49 | \newpage 50 | \end{titlepage} 51 | 52 | -------------------------------------------------------------------------------- /Chapters/header_zh.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt,a4paper,oneside]{book} 2 | 3 | \usepackage{fontspec} 4 | \usepackage[BoldFont,SlantFont,CJKchecksingle,CJKnumber]{xeCJK} 5 | % from package fontspec and xeCJK 6 | \setCJKmainfont[Path=Fonts/, 7 | BoldFont={sarasa-gothic-sc-bold.ttf}, 8 | ItalicFont={sarasa-gothic-sc-italic.ttf}, 9 | BoldItalicFont={sarasa-gothic-sc-bolditalic.ttf}, 10 | SlantedFont={sarasa-gothic-sc-regular.ttf}, 11 | BoldSlantedFont={sarasa-gothic-sc-bolditalic.ttf}, 12 | SmallCapsFont={sarasa-gothic-sc-regular.ttf} 13 | ]{sarasa-gothic-sc-regular.ttf} 14 | \setCJKsansfont[Path=Fonts/]{sarasa-gothic-sc-regular.ttf} 15 | \setCJKmonofont[Scale=0.9,Path=Fonts/]{SourceCodePro-Light.otf} 16 | 17 | \setmainfont[Path=Fonts/, 18 | BoldFont={sarasa-gothic-sc-bold.ttf}, 19 | ItalicFont={sarasa-gothic-sc-italic.ttf}, 20 | BoldItalicFont={sarasa-gothic-sc-bolditalic.ttf}, 21 | SlantedFont={sarasa-gothic-sc-regular.ttf}, 22 | BoldSlantedFont={sarasa-gothic-sc-bold.ttf}, 23 | SmallCapsFont={sarasa-gothic-sc-regular.ttf} 24 | ]{sarasa-gothic-sc-regular.ttf} 25 | \setsansfont[Path=Fonts/]{sarasa-gothic-sc-regular.ttf} 26 | % "Mapping={}" make quote symbol straight 27 | \setmonofont[Mapping={},Path=Fonts/]{SourceCodePro-Light.otf} 28 | 29 | \punctstyle{hangmobanjiao} 30 | 31 | \defaultfontfeatures{Mapping=tex-text} 32 | \usepackage{xunicode} 33 | \usepackage{xltxtra} 34 | 35 | \XeTeXlinebreaklocale "zh" 36 | \XeTeXlinebreakskip = 0pt plus 1pt minus 0.1pt 37 | 38 | %首行缩进 39 | %\usepackage{indentfirst} 40 | \makeatletter 41 | \let\@afterindentfalse\@afterindenttrue 42 | \@afterindenttrue 43 | \makeatother 44 | \setlength{\parindent}{2em} 45 | 46 | \linespread{1.2} 47 | 48 | %在每一章的开头列出section的列表 49 | \usepackage{minitoc} 50 | \setcounter{minitocdepth}{1} 51 | \renewcommand{\mtctitle}{目录} 52 | 53 | %修改目录中的章节格式 54 | \usepackage{titletoc} 55 | \titlecontents{chapter}[0pt]{\vspace{0.3\baselineskip}\bfseries}{第 \thecontentslabel 章\quad}{}{\hfill\contentspage} 56 | \titlecontents{section}[2em]{\vspace{0.05\baselineskip}}{\thecontentslabel\quad}{}{\hspace{.5em}\titlerule*[8pt]{$\cdot$}\contentspage} 57 | \titlecontents{subsection}[4em]{\vspace{0.02\baselineskip}}{\thecontentslabel\quad}{}{\hspace{.5em}\titlerule*[8pt]{$\cdot$}\contentspage} 58 | \titlecontents{figure}[0pt]{\vspace{0.05\baselineskip}}{\thecontentslabel\quad}{}{\hspace{.5em}\titlerule*[8pt]{$\cdot$}\contentspage} 59 | \titlecontents{table}[0pt]{\vspace{0.05\baselineskip}}{\thecontentslabel\quad}{}{\hspace{.5em}\titlerule*[8pt]{$\cdot$}\contentspage} 60 | 61 | %整段缩进 62 | \usepackage{changepage} 63 | 64 | %图文混排 65 | %\usepackage{picins} 66 | 67 | %在footnote中使用verb 68 | \usepackage{fancyvrb} 69 | %在section中使用\verb 70 | \usepackage{cprotect} 71 | 72 | %文本框 73 | %\usepackage{fancybox} 74 | 75 | \usepackage{fancyhdr} 76 | \pagestyle{fancy} 77 | \renewcommand{\chaptermark}[1]{\markboth{\small 第 \thechapter 章\quad #1}{}} 78 | \renewcommand{\sectionmark}[1]{\markright{\small \thesection \quad #1}{}} 79 | \fancyhf{} 80 | \fancyhead[ER]{\leftmark} 81 | \fancyhead[OL]{\rightmark} 82 | \fancyhead[EL,OR]{$\cdot$ \thepage \ $\cdot$} 83 | \renewcommand{\headrulewidth}{0.5pt} 84 | 85 | %单面模式 86 | %\newpagestyle{main}{ 87 | %\sethead[$\cdot$~\thepage~$\cdot$][][\chaptername\quad\chaptertitle]{\small\S\,\thesection\quad\sectiontitle}{}{$\cdot$~\thepage~$\cdot$} 88 | %\setfoot{}{}{}\headrule} 89 | %\pagestyle{main} 90 | 91 | \usepackage{titlesec} 92 | \titleformat{\chapter}{\centering\LARGE\bfseries}{第 \thechapter 章}{1em}{} 93 | 94 | %附录 95 | \usepackage{appendix} 96 | 97 | \usepackage{xcolor} 98 | %\usepackage[dvipsnames,tables]{xcolor} 99 | \graphicspath{{figures/}} 100 | %\usepackage[xetex,bookmarksnumbered=true,bookmarksopen=true,pdfborder=1,breaklinks,colorlinks,linkcolor=blue,urlcolor=blue,citecolor=blue]{hyperref} 101 | \usepackage[xetex,bookmarksnumbered=true,bookmarksopen=true,pdfborder=1,breaklinks, 102 | linkcolor=black, 103 | anchorcolor=black, 104 | citecolor=black 105 | ]{hyperref} 106 | %\usepackage[xetex,bookmarksnumbered=true,bookmarksopen=true,pdfborder=1,breaklinks]{hyperref} 107 | 108 | \hypersetup{ 109 | bookmarksnumbered = true, 110 | pdftitle = {Beginning Perl for Bioinformatics}, 111 | pdfcreator = {https://m-mono.github.io}, 112 | pdfauthor = {James D. Tisdall}, 113 | pdfsubject = {生物信息学 Perl 语言入门}, 114 | colorlinks = false, 115 | pdfborder = 0 0 0, 116 | pdfkeywords = {本书向只有很少、甚至没有编程经验的生物学家展示了如何使用Perl这一理想的编程语言进行生物学数据分析。每一章都集中解决特定的问题或者问题集,所以当你读完本书后,你会对Perl的基础知识有一个深刻的理解,收集到解析BLAST和GenBank等任务的程序,同时习得处理更加高级的生物信息学问题的技能。} 117 | } 118 | 119 | \def\chapterautorefname~#1\null{第{#1}章\null} 120 | \def\sectionautorefname~#1\null{第{#1}节\null} 121 | \def\subsectionautorefname~#1\null{第{#1}小节\null} 122 | \def\subsubsectionautorefname~#1\null{第{#1}小节\null} 123 | \def\figureautorefname{图} 124 | \def\tableautorefname{表} 125 | \def\Appendixautorefname~#1\null{附录{#1}\null} 126 | \def\lstlistingautorefname{例} 127 | 128 | \renewcommand{\today}{\number\year 年 \number\month 月 \number\day 日} 129 | \renewcommand{\contentsname}{目\quad 录} 130 | \renewcommand{\listfigurename}{图\quad 片} 131 | \renewcommand{\listtablename}{表\quad 格} 132 | \renewcommand{\figurename}{图} 133 | \renewcommand{\tablename}{表} 134 | %\renewcommand{\lstlistingname}{例} 135 | \renewcommand{\indexname}{索\quad 引} 136 | %\renewcommand{\figureautorefname}{图} 137 | %\renewcommand{\tableautorefname}{表} 138 | \renewcommand{\footnoteautorefname}{脚注} 139 | \renewcommand{\itemautorefname}{项} 140 | 141 | %使表格可以跨页 142 | \usepackage{booktabs,tabu,longtable} 143 | %调整表头和表格之间的间距 144 | \setlength\belowcaptionskip{0.2em} 145 | %调整表格行高 146 | \renewcommand{\arraystretch}{0.8} 147 | 148 | %调整列表间及其上下的间距 149 | \usepackage{enumitem} 150 | \setlist{nosep} 151 | 152 | %设置颜色的快捷命令 153 | \newcommand{\red}{\textcolor{black}} 154 | \newcommand{\gray}{\textcolor{gray}} 155 | \newcommand{\black}{\textcolor{black}} 156 | 157 | %罗马数字 158 | \makeatletter 159 | \newcommand{\rmnum}[1]{\romannumeral #1} 160 | \newcommand{\Rmnum}[1]{\expandafter\@slowromancap\romannumeral #1@} 161 | \makeatother 162 | 163 | %插入源代码 164 | \usepackage{listings} 165 | %The header name for the list of listings: Listings 166 | \renewcommand{\lstlistlistingname}{程\quad 序} 167 | %The caption label for listings: Listing 168 | \renewcommand{\lstlistingname}{例} 169 | \contentsuse{lstlisting}{lol} 170 | \titlecontents{lstlisting}[0pt]{\vspace{0.05\baselineskip}}{}{\thecontentslabel\quad}{\hspace{.5em}\titlerule*[8pt]{$\cdot$}\contentspage} 171 | \lstset{ 172 | language=Perl, 173 | %basicstyle=\normalsize\tt, 174 | basicstyle=\small\tt, 175 | frame=l, 176 | numbers=left, 177 | numberstyle=\footnotesize, 178 | showstringspaces=false, 179 | %breaklines=true, 180 | breaklines=false, 181 | breakatwhitespace=false, 182 | } 183 | \usepackage{caption} 184 | \captionsetup[lstlisting]{labelformat=empty,labelsep=none,format=plain,font=bf} 185 | %\captionsetup[lstlisting]{labelformat=empty,labelsep=none,textformat=empty,skip=-20pt} 186 | 187 | %suppresses page numbers and headings from appearing on empty pages. 188 | %remove headers and footers for pages between chapters 189 | \usepackage{emptypage} 190 | 191 | \usepackage{mdframed} 192 | \usepackage{graphics,graphicx,pdfpages} 193 | 194 | \let\stdsection\section 195 | \renewcommand\section{\newpage\stdsection} -------------------------------------------------------------------------------- /Fonts/SourceCodePro-It.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/Fonts/SourceCodePro-It.otf -------------------------------------------------------------------------------- /Fonts/SourceCodePro-Light.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/Fonts/SourceCodePro-Light.otf -------------------------------------------------------------------------------- /Fonts/sarasa-gothic-sc-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/Fonts/sarasa-gothic-sc-bold.ttf -------------------------------------------------------------------------------- /Fonts/sarasa-gothic-sc-bolditalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/Fonts/sarasa-gothic-sc-bolditalic.ttf -------------------------------------------------------------------------------- /Fonts/sarasa-gothic-sc-italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/Fonts/sarasa-gothic-sc-italic.ttf -------------------------------------------------------------------------------- /Fonts/sarasa-gothic-sc-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/Fonts/sarasa-gothic-sc-regular.ttf -------------------------------------------------------------------------------- /Fonts/sarasa-mono-sc-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/Fonts/sarasa-mono-sc-regular.ttf -------------------------------------------------------------------------------- /Frontmatter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/Frontmatter.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Beginning Perl for Bioinformatics · 生物信息学 Perl 语言入门(中文版) 2 | James D. Tisdall 3 | --- 4 | 5 | 该书向只有很少、甚至没有编程经验的生物学家展示了如何使用 Perl 这一理想的编程语言进行生物学数据分析。每一章都集中解决特定的问题或者问题集,所以当你读完本书后,你会对 Perl 的基础知识有一个深刻的理解,收集到解析 BLAST 和 GenBank 等任务的程序,同时习得处理更加高级的生物信息学问题的技能。 6 | 7 | ![Beginning Perl for Bioinformatics](https://github.com/M-Mono/Beginning-Perl-for-Bioinformatics/raw/master/Frontmatter.jpg) 8 | --- 9 | 编译环境: 10 | + **Fork** 11 | + [Yixf-Education](https://github.com/Yixf-Education/BP4B) 12 | 13 | ``` 14 | 译文版权声明 15 | 16 | - 本书的中文翻译(含封面)未得到原作者和原出版社的许可,中译本的翻译错误与原作者无关! 17 | - 本书的中译本封面由原书封面修改而成,仅供该中译本使用! 18 | - 本书的中译本初衷是作为天津医科大学、生物医学工程与技术学院、生物信息学专业、《分子生物计算》课程的教材。 19 | - 本书的中译本仅供参考学习只用,严禁贩卖、流通,后果自负! 20 | - 本书的翻译仍处于草稿阶段,疏漏、错误之处在所难免,欢迎读者予以指正。 21 | - 本书的中译本解释权归译者所有,如有任何疑问,请发邮件至yixfbio@gmail.com 与译者本人联系。 22 | 23 | 伊现富 24 | 25 | 2015 年 8 月 14 日 26 | 27 | 天医-生医-208 28 | ``` 29 | 30 | + **TeX Distribution** 31 | + [MacTeX 2019](https://www.tug.org/mactex/) [(License)](https://www.tug.org/mactex/src/License.rtf) 32 | + for Apple macOS 33 | 34 | 35 | + [TeX Live 2019](https://www.tug.org/texlive/) [(License)](https://www.tug.org/texlive/copying.html) 36 | + for GNU/Linux & Microsoft Windows 37 | 38 | 39 | + **Fonts** 40 | + [be5invis 更纱黑体 Sarasa Gothic 0.10.2](https://github.com/be5invis/Sarasa-Gothic) [(License)](https://github.com/be5invis/Sarasa-Gothic/blob/master/LICENSE) 41 | + [Adobe Source Code Pro 2.030](https://github.com/adobe-fonts/source-code-pro) [(License)](https://github.com/adobe-fonts/source-code-pro/blob/master/LICENSE.md) 42 | 43 | 44 | + **Editor** 45 | + [Visual Studio Code 1.40.1](https://code.visualstudio.com/) [(License)](https://code.visualstudio.com/License/) 46 | + [LaTeX Workshop 8.4.1](https://github.com/James-Yu/LaTeX-Workshop) [(License)](https://github.com/James-Yu/LaTeX-Workshop/blob/master/LICENSE.txt) 47 | + Configuration for LaTeX Workshop extension to complie XeTeX source code into PDF Version 1.7 (Acrobat 8.x) 48 | 49 | ```Visual Studio Code``` ⇢ ```File``` ⇢ ```Preferences``` ⇢ ```Settings``` ⇢ ```Extensions``` ⇢ ```LaTeX``` ⇢ ```Recipes``` 50 | 51 | 52 | ```JSON 53 | { 54 | "latex-workshop.view.pdf.viewer": "tab", 55 | "latex-workshop.latex.tools": [ 56 | { 57 | "name": "latexmk", 58 | "command": "latexmk", 59 | "args": [ 60 | "-synctex=1", 61 | "-interaction=nonstopmode", 62 | "-file-line-error", 63 | "-pdf", 64 | "%DOC%" 65 | ] 66 | }, 67 | { 68 | "name": "xelatex", 69 | "command": "xelatex", 70 | "args": [ 71 | "-synctex=1", 72 | "-interaction=nonstopmode", 73 | "-file-line-error", 74 | "--output-driver=xdvipdfmx -q -E -V 7", 75 | "%DOC%" 76 | ] 77 | }, 78 | { 79 | "name": "pdflatex", 80 | "command": "pdflatex", 81 | "args": [ 82 | "-synctex=1", 83 | "-interaction=nonstopmode", 84 | "-file-line-error", 85 | "%DOC%" 86 | ] 87 | }, 88 | { 89 | "name": "bibtex", 90 | "command": "bibtex", 91 | "args": [ 92 | "%DOCFILE%" 93 | ] 94 | } 95 | ], 96 | "latex-workshop.latex.recipes": [ 97 | { 98 | "name": "XeLaTeX / XeTeX", 99 | "tools": [ 100 | "xelatex" 101 | ] 102 | }, 103 | { 104 | "name": "latexmk", 105 | "tools": [ 106 | "latexmk" 107 | ] 108 | }, 109 | { 110 | "name": "pdflatex -> bibtex -> pdflatex*2", 111 | "tools": [ 112 | "pdflatex", 113 | "bibtex", 114 | "pdflatex", 115 | "pdflatex" 116 | ] 117 | } 118 | ], 119 | "workbench.startupEditor": "newUntitledFile", 120 | "window.zoomLevel": 0, 121 | "editor.minimap.enabled": false 122 | } 123 | ``` 124 | -------------------------------------------------------------------------------- /figures/figure1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/figures/figure1_1.png -------------------------------------------------------------------------------- /figures/figure4_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/figures/figure4_1.png -------------------------------------------------------------------------------- /figures/figure4_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/figures/figure4_2.png -------------------------------------------------------------------------------- /figures/figure8_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/figures/figure8_1.png -------------------------------------------------------------------------------- /figures/figureab1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/figures/figureab1.png -------------------------------------------------------------------------------- /figures/figureab2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/figures/figureab2.png -------------------------------------------------------------------------------- /figures/note.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/figures/note.png -------------------------------------------------------------------------------- /figures/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M-Mono/Beginning-Perl-for-Bioinformatics/9cb4f7c4387d6606337b569265194c6010f6d3ef/figures/warning.png -------------------------------------------------------------------------------- /scripts/example10-1.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 10-1 Extract annotation and sequence from GenBank file 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # declare and initialize variables 9 | my @annotation = (); 10 | my $sequence = ''; 11 | my $filename = 'record.gb'; 12 | 13 | parse1( \@annotation, \$sequence, $filename ); 14 | 15 | # Print the annotation, and then 16 | # print the DNA in new format just to check if we got it okay. 17 | print @annotation; 18 | 19 | print_sequence( $sequence, 50 ); 20 | 21 | exit; 22 | 23 | ################################################################################ 24 | # Subroutine 25 | ################################################################################ 26 | 27 | # parse1 28 | # 29 | # -parse annotation and sequence from GenBank record 30 | 31 | sub parse1 { 32 | 33 | my ( $annotation, $dna, $filename ) = @_; 34 | 35 | # $annotation-reference to array 36 | # $dna -reference to scalar 37 | # $filename -scalar 38 | 39 | # declare and initialize variables 40 | my $in_sequence = 0; 41 | my @GenBankFile = (); 42 | 43 | # Get the GenBank data into an array from a file 44 | @GenBankFile = get_file_data($filename); 45 | 46 | # Extract all the sequence lines 47 | foreach my $line (@GenBankFile) { 48 | 49 | if ( $line =~ /^\/\/\n/ ) { # If $line is end-of-record line //\n, 50 | last; #break out of the foreach loop. 51 | } 52 | elsif ($in_sequence) { # If we know we're in a sequence, 53 | $$dna .= $line; # add the current line to $$dna. 54 | } 55 | elsif ( $line =~ /^ORIGIN/ ) { # If $line begins a sequence, 56 | $in_sequence = 1; # set the $in_sequence flag. 57 | } 58 | else { # Otherwise 59 | push( @$annotation, $line ); # add the current line to @annotation. 60 | } 61 | } 62 | 63 | # remove whitespace and line numbers from DNA sequence 64 | $$dna =~ s/[\s0-9]//g; 65 | } 66 | -------------------------------------------------------------------------------- /scripts/example10-2.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 10-2 Extract the annotation and sequence sections from the first 3 | # record of a GenBank library 4 | 5 | use strict; 6 | use warnings; 7 | use BeginPerlBioinfo; # see Chapter 6 about this module 8 | 9 | # Declare and initialize variables 10 | my $annotation = ''; 11 | my $dna = ''; 12 | my $record = ''; 13 | my $filename = 'record.gb'; 14 | my $save_input_separator = $/; 15 | 16 | # Open GenBank library file 17 | unless ( open( GBFILE, $filename ) ) { 18 | print "Cannot open GenBank file \"$filename\"\n\n"; 19 | exit; 20 | } 21 | 22 | # Set input separator to "//\n" and read in a record to a scalar 23 | $/ = "//\n"; 24 | 25 | $record = ; 26 | 27 | # reset input separator 28 | $/ = $save_input_separator; 29 | 30 | # Now separate the annotation from the sequence data 31 | ( $annotation, $dna ) = ( $record =~ /^(LOCUS.*ORIGIN\s*\n)(.*)\/\/\n/s ); 32 | 33 | # Print the two pieces, which should give us the same as the 34 | # original GenBank file, minus the // at the end 35 | print $annotation, $dna; 36 | 37 | exit; 38 | -------------------------------------------------------------------------------- /scripts/example10-3.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 10-3 Parsing GenBank annotations using arrays 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # Declare and initialize variables 9 | my @genbank = (); 10 | my $locus = ''; 11 | my $accession = ''; 12 | my $organism = ''; 13 | 14 | # Get GenBank file data 15 | @genbank = get_file_data('record.gb'); 16 | 17 | # Let's start with something simple. Let's get some of the identifying 18 | # information, let's say the locus and accession number (here the same 19 | # thing) and the definition and the organism. 20 | 21 | for my $line (@genbank) { 22 | if ( $line =~ /^LOCUS/ ) { 23 | $line =~ s/^LOCUS\s*//; 24 | $locus = $line; 25 | } 26 | elsif ( $line =~ /^ACCESSION/ ) { 27 | $line =~ s/^ACCESSION\s*//; 28 | $accession = $line; 29 | } 30 | elsif ( $line =~ /^ ORGANISM/ ) { 31 | $line =~ s/^\s*ORGANISM\s*//; 32 | $organism = $line; 33 | } 34 | } 35 | 36 | print "*** LOCUS ***\n"; 37 | print $locus; 38 | print "*** ACCESSION ***\n"; 39 | print $accession; 40 | print "*** ORGANISM ***\n"; 41 | print $organism; 42 | 43 | exit; 44 | -------------------------------------------------------------------------------- /scripts/example10-4.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 10-4 Parsing GenBank annotations using arrays, take 2 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # Declare and initialize variables 9 | my @genbank = (); 10 | my $locus = ''; 11 | my $accession = ''; 12 | my $organism = ''; 13 | my $definition = ''; 14 | my $flag = 0; 15 | 16 | # Get GenBank file data 17 | @genbank = get_file_data('record.gb'); 18 | 19 | # Let's start with something simple. Let's get some of the identifying 20 | # information, let's say the locus and accession number (here the same 21 | # thing) and the definition and the organism. 22 | 23 | for my $line (@genbank) { 24 | if ( $line =~ /^LOCUS/ ) { 25 | $line =~ s/^LOCUS\s*//; 26 | $locus = $line; 27 | } 28 | elsif ( $line =~ /^DEFINITION/ ) { 29 | $line =~ s/^DEFINITION\s*//; 30 | $definition = $line; 31 | $flag = 1; 32 | } 33 | elsif ( $line =~ /^ACCESSION/ ) { 34 | $line =~ s/^ACCESSION\s*//; 35 | $accession = $line; 36 | $flag = 0; 37 | } 38 | elsif ($flag) { 39 | chomp($definition); 40 | $definition .= $line; 41 | } 42 | elsif ( $line =~ /^ ORGANISM/ ) { 43 | $line =~ s/^\s*ORGANISM\s*//; 44 | $organism = $line; 45 | } 46 | } 47 | 48 | print "*** LOCUS ***\n"; 49 | print $locus; 50 | print "*** DEFINITION ***\n"; 51 | print $definition; 52 | print "*** ACCESSION ***\n"; 53 | print $accession; 54 | print "*** ORGANISM ***\n"; 55 | print $organism; 56 | 57 | exit; 58 | -------------------------------------------------------------------------------- /scripts/example10-5.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 10-5 - test program of GenBank library subroutines) 3 | 4 | use strict; 5 | use warnings; 6 | 7 | # Don't use BeginPerlBioinfo 8 | # Since all subroutines defined in this file 9 | # use BeginPerlBioinfo; # see Chapter 6 about this module 10 | 11 | # Declare and initialize variables 12 | my $fh; # variable to store filehandle 13 | my $record; 14 | my $dna; 15 | my $annotation; 16 | my $offset; 17 | my $library = 'library.gb'; 18 | 19 | # Perform some standard subroutines for test 20 | $fh = open_file($library); 21 | 22 | $offset = tell($fh); 23 | 24 | while ( $record = get_next_record($fh) ) { 25 | 26 | ( $annotation, $dna ) = get_annotation_and_dna($record); 27 | 28 | if ( search_sequence( $dna, 'AAA[CG].' ) ) { 29 | print "Sequence found in record at offset $offset\n"; 30 | } 31 | if ( search_annotation( $annotation, 'homo sapiens' ) ) { 32 | print "Annotation found in record at offset $offset\n"; 33 | } 34 | 35 | $offset = tell($fh); 36 | } 37 | 38 | exit; 39 | 40 | ################################################################################ 41 | # Subroutines 42 | ################################################################################ 43 | 44 | # open_file 45 | # 46 | # - given filename, set filehandle 47 | 48 | sub open_file { 49 | 50 | my ($filename) = @_; 51 | my $fh; 52 | 53 | unless ( open( $fh, $filename ) ) { 54 | print "Cannot open file $filename\n"; 55 | exit; 56 | } 57 | return $fh; 58 | } 59 | 60 | # get_next_record 61 | # 62 | # - given GenBank record, get annotation and DNA 63 | 64 | sub get_next_record { 65 | 66 | my ($fh) = @_; 67 | 68 | my ($offset); 69 | my ($record) = ''; 70 | my ($save_input_separator) = $/; 71 | 72 | $/ = "//\n"; 73 | 74 | $record = <$fh>; 75 | 76 | $/ = $save_input_separator; 77 | 78 | return $record; 79 | } 80 | 81 | # get_annotation_and_dna 82 | # 83 | # - given filehandle to open GenBank library file, get next record 84 | 85 | sub get_annotation_and_dna { 86 | 87 | my ($record) = @_; 88 | 89 | my ($annotation) = ''; 90 | my ($dna) = ''; 91 | 92 | # Now separate the annotation from the sequence data 93 | ( $annotation, $dna ) = ( $record =~ /^(LOCUS.*ORIGIN\s*\n)(.*)\/\/\n/s ); 94 | 95 | # clean the sequence of any whitespace or / characters 96 | # (the / has to be written \/ in the character class, because 97 | # / is a metacharacter, so it must be "escaped" with \) 98 | $dna =~ s/[\s\/]//g; 99 | 100 | return ( $annotation, $dna ); 101 | } 102 | 103 | # search_sequence 104 | # 105 | # - search sequence with regular expression 106 | 107 | sub search_sequence { 108 | 109 | my ( $sequence, $regularexpression ) = @_; 110 | 111 | my (@locations) = (); 112 | 113 | while ( $sequence =~ /$regularexpression/ig ) { 114 | push( @locations, pos ); 115 | } 116 | 117 | return (@locations); 118 | } 119 | 120 | # search_annotation 121 | # 122 | # - search annotation with regular expression 123 | 124 | sub search_annotation { 125 | 126 | my ( $annotation, $regularexpression ) = @_; 127 | 128 | my (@locations) = (); 129 | 130 | # note the /s modifier-. matches any character including newline 131 | while ( $annotation =~ /$regularexpression/isg ) { 132 | push( @locations, pos ); 133 | } 134 | 135 | return (@locations); 136 | } 137 | -------------------------------------------------------------------------------- /scripts/example10-6.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 10-6 - test program for parse_annotation subroutine 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # Declare and initialize variables 9 | my $fh; 10 | my $record; 11 | my $dna; 12 | my $annotation; 13 | my %fields; 14 | my $library = 'library.gb'; 15 | 16 | # Open library and read a record 17 | $fh = open_file($library); 18 | 19 | $record = get_next_record($fh); 20 | 21 | # Parse the sequence and annotation 22 | ( $annotation, $dna ) = get_annotation_and_dna($record); 23 | 24 | # Extract the fields of the annotation 25 | %fields = parse_annotation($annotation); 26 | 27 | # Print the fields 28 | foreach my $key ( keys %fields ) { 29 | print "******** $key *********\n"; 30 | print $fields{$key}; 31 | } 32 | 33 | exit; 34 | 35 | ################################################################################ 36 | # Subroutine 37 | ################################################################################ 38 | 39 | # parse_annotation 40 | # 41 | # given a GenBank annotation, returns a hash with 42 | # keys: the field names 43 | # values: the fields 44 | 45 | sub parse_annotation { 46 | 47 | my ($annotation) = @_; 48 | my (%results) = (); 49 | 50 | while ( $annotation =~ /^[A-Z].*\n(^\s.*\n)*/gm ) { 51 | my $value = $&; 52 | ( my $key = $value ) =~ s/^([A-Z]+).*/$1/s; 53 | $results{$key} = $value; 54 | } 55 | 56 | return %results; 57 | } 58 | -------------------------------------------------------------------------------- /scripts/example10-7.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # - main program to test parse_features 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # Declare and initialize variables 9 | my $fh; 10 | my $record; 11 | my $dna; 12 | my $annotation; 13 | my %fields; 14 | my @features; 15 | my $library = 'library.gb'; 16 | 17 | # Get the fields from the first GenBank record in a library 18 | $fh = open_file($library); 19 | 20 | $record = get_next_record($fh); 21 | 22 | ( $annotation, $dna ) = get_annotation_and_dna($record); 23 | 24 | %fields = parse_annotation($annotation); 25 | 26 | # Extract the features from the FEATURES table 27 | @features = parse_features( $fields{'FEATURES'} ); 28 | 29 | # Print out the features 30 | foreach my $feature (@features) { 31 | 32 | # extract the name of the feature (or "feature key") 33 | my ($featurename) = ( $feature =~ /^ {5}(\S+)/ ); 34 | 35 | print "******** $featurename *********\n"; 36 | print $feature; 37 | } 38 | 39 | exit; 40 | 41 | ############################################################################ 42 | # Subroutine 43 | ############################################################################ 44 | 45 | # parse_features 46 | # 47 | # extract the features from the FEATURES field of a GenBank record 48 | 49 | sub parse_features { 50 | 51 | my ($features) = @_; # entire FEATURES field in a scalar variable 52 | 53 | # Declare and initialize variables 54 | my (@features) = (); # used to store the individual features 55 | 56 | # Extract the features 57 | while ( $features =~ /^ {5}\S.*\n(^ {21}\S.*\n)*/gm ) { 58 | my $feature = $&; 59 | push( @features, $feature ); 60 | } 61 | 62 | return @features; 63 | } 64 | -------------------------------------------------------------------------------- /scripts/example10-8.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 10-8 - make a DBM index of a GenBank library, 3 | # and demonstrate its use interactively 4 | 5 | use strict; 6 | use warnings; 7 | use BeginPerlBioinfo; # see Chapter 6 about this module 8 | 9 | # Declare and initialize variables 10 | my $fh; 11 | my $record; 12 | my $dna; 13 | my $annotation; 14 | my %fields; 15 | my %dbm; 16 | my $answer; 17 | my $offset; 18 | my $library = 'library.gb'; 19 | 20 | # open DBM file, creating if necessary 21 | unless ( dbmopen( %dbm, 'GB', 0644 ) ) { 22 | print "Cannot open DBM file GB with mode 0644\n"; 23 | exit; 24 | } 25 | 26 | # Parse GenBank library, saving accession number and offset in DBM file 27 | $fh = open_file($library); 28 | 29 | $offset = tell($fh); 30 | 31 | while ( $record = get_next_record($fh) ) { 32 | 33 | # Get accession field for this record. 34 | ( $annotation, $dna ) = get_annotation_and_dna($record); 35 | 36 | %fields = parse_annotation($annotation); 37 | 38 | my $accession = $fields{'ACCESSION'}; 39 | 40 | # extract just the accession number from the accession field 41 | # -remove any trailing spaces 42 | $accession =~ s/^ACCESSION\s*//; 43 | 44 | $accession =~ s/\s*$//; 45 | 46 | # store the key/value of accession/offset 47 | $dbm{$accession} = $offset; 48 | 49 | # get offset for next record 50 | $offset = tell($fh); 51 | } 52 | 53 | # Now interactively query the DBM database with accession numbers 54 | # to see associated records 55 | 56 | print "Here are the available accession numbers:\n"; 57 | 58 | print join( "\n", keys %dbm ), "\n"; 59 | 60 | print "Enter accession number (or quit): "; 61 | 62 | while ( $answer = ) { 63 | chomp $answer; 64 | if ( $answer =~ /^\s*q/ ) { 65 | last; 66 | } 67 | $offset = $dbm{$answer}; 68 | 69 | if ( defined $offset ) { 70 | seek( $fh, $offset, 0 ); 71 | $record = get_next_record($fh); 72 | print $record; 73 | } 74 | else { 75 | print "Do not have an entry for accession number $answer\n"; 76 | } 77 | 78 | print "\nEnter accession number (or quit): "; 79 | } 80 | 81 | dbmclose(%dbm); 82 | 83 | close($fh); 84 | 85 | exit; 86 | -------------------------------------------------------------------------------- /scripts/example11-1.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 11-1 Demonstrating how to open a folder and list its contents 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | my @files = (); 9 | my $folder = 'pdb'; 10 | 11 | # open the folder 12 | unless ( opendir( FOLDER, $folder ) ) { 13 | print "Cannot open folder $folder!\n"; 14 | exit; 15 | } 16 | 17 | # read the contents of the folder (i.e. the files and subfolders) 18 | @files = readdir(FOLDER); 19 | 20 | # close the folder 21 | closedir(FOLDER); 22 | 23 | # print them out, one per line 24 | print join( "\n", @files ), "\n"; 25 | 26 | exit; 27 | -------------------------------------------------------------------------------- /scripts/example11-2.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 11-2 Demonstrating how to open a folder and list its contents 3 | # -distinguishing between files and subfolders, which 4 | # are themselves listed 5 | 6 | use strict; 7 | use warnings; 8 | use BeginPerlBioinfo; # see Chapter 6 about this module 9 | 10 | my @files = (); 11 | my $folder = 'pdb'; 12 | 13 | # Open the folder 14 | unless ( opendir( FOLDER, $folder ) ) { 15 | print "Cannot open folder $folder!\n"; 16 | exit; 17 | } 18 | 19 | # Read the folder, ignoring special entries "." and ".." 20 | @files = grep ( !/^\.\.?$/, readdir(FOLDER) ); 21 | 22 | closedir(FOLDER); 23 | 24 | # If file, print its name 25 | # If folder, print its name and contents 26 | # 27 | # Notice that we need to prepend the folder name! 28 | foreach my $file (@files) { 29 | 30 | # If the folder entry is a regular file 31 | if ( -f "$folder/$file" ) { 32 | print "$folder/$file\n"; 33 | 34 | # If the folder entry is a subfolder 35 | } 36 | elsif ( -d "$folder/$file" ) { 37 | 38 | my $folder = "$folder/$file"; 39 | 40 | # open the subfolder and list its contents 41 | unless ( opendir( FOLDER, "$folder" ) ) { 42 | print "Cannot open folder $folder!\n"; 43 | exit; 44 | } 45 | 46 | my @files = grep ( !/^\.\.?$/, readdir(FOLDER) ); 47 | 48 | closedir(FOLDER); 49 | 50 | foreach my $file (@files) { 51 | print "$folder/$file\n"; 52 | } 53 | } 54 | } 55 | 56 | exit; 57 | -------------------------------------------------------------------------------- /scripts/example11-3.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 11-3 Demonstrate a recursive subroutine to list a subtree of a filesystem 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | list_recursively('pdb'); 9 | 10 | exit; 11 | 12 | ################################################################################ 13 | # Subroutine 14 | ################################################################################ 15 | 16 | # list_recursively 17 | # 18 | # list the contents of a directory, 19 | # recursively listing the contents of any subdirectories 20 | 21 | sub list_recursively { 22 | 23 | my ($directory) = @_; 24 | 25 | my @files = (); 26 | 27 | # Open the directory 28 | unless ( opendir( DIRECTORY, $directory ) ) { 29 | print "Cannot open directory $directory!\n"; 30 | exit; 31 | } 32 | 33 | # Read the directory, ignoring special entries "." and ".." 34 | # 35 | @files = grep ( !/^\.\.?$/, readdir(DIRECTORY) ); 36 | 37 | closedir(DIRECTORY); 38 | 39 | # If file, print its name 40 | # If directory, recursively print its contents 41 | 42 | # Notice that we need to prepend the directory name! 43 | foreach my $file (@files) { 44 | 45 | # If the directory entry is a regular file 46 | if ( -f "$directory/$file" ) { 47 | 48 | print "$directory/$file\n"; 49 | 50 | # If the directory entry is a subdirectory 51 | } 52 | elsif ( -d "$directory/$file" ) { 53 | 54 | # Here is the recursive call to this subroutine 55 | list_recursively("$directory/$file"); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /scripts/example11-4.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 11-4 Demonstrate File::Find 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | use File::Find; 9 | 10 | find( \&my_sub, ('pdb') ); 11 | 12 | sub my_sub { 13 | -f and ( print $File::Find::name, "\n" ); 14 | } 15 | 16 | exit; 17 | -------------------------------------------------------------------------------- /scripts/example11-5.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 11-5 Extract sequence chains from PDB file 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # Read in PDB file: Warning - some files are very large! 9 | my @file = get_file_data('pdb/c1/pdb1c1f.ent'); 10 | 11 | # Parse the record types of the PDB file 12 | my %recordtypes = parsePDBrecordtypes(@file); 13 | 14 | # Extract the amino acid sequences of all chains in the protein 15 | my @chains = extractSEQRES( $recordtypes{'SEQRES'} ); 16 | 17 | # Translate the 3-character codes to 1-character codes, and print 18 | foreach my $chain (@chains) { 19 | print "$chain\n"; 20 | print iub3to1($chain), "\n"; 21 | } 22 | 23 | exit; 24 | 25 | ################################################################################ 26 | # Subroutines for Example 11-5 27 | ################################################################################ 28 | 29 | # parsePDBrecordtypes 30 | # 31 | #-given an array of a PDB file, return a hash with 32 | # keys = record type names 33 | # values = scalar containing lines for that record type 34 | 35 | sub parsePDBrecordtypes { 36 | 37 | my @file = @_; 38 | 39 | use strict; 40 | use warnings; 41 | 42 | my %recordtypes = (); 43 | 44 | foreach my $line (@file) { 45 | 46 | # Get the record type name which begins at the 47 | # start of the line and ends at the first space 48 | 49 | # The pattern (\S+) is returned and saved in $recordtype 50 | my ($recordtype) = ( $line =~ /^(\S+)/ ); 51 | 52 | # .= fails if a key is undefined, so we have to 53 | # test for definition and use either .= or = depending 54 | if ( defined $recordtypes{$recordtype} ) { 55 | $recordtypes{$recordtype} .= $line; 56 | } 57 | else { 58 | $recordtypes{$recordtype} = $line; 59 | } 60 | } 61 | 62 | return %recordtypes; 63 | } 64 | 65 | # extractSEQRES 66 | # 67 | #-given an scalar containing SEQRES lines, 68 | # return an array containing the chains of the sequence 69 | 70 | sub extractSEQRES { 71 | 72 | use strict; 73 | use warnings; 74 | 75 | my ($seqres) = @_; 76 | 77 | my $lastchain = ''; 78 | my $sequence = ''; 79 | my @results = (); 80 | 81 | # make array of lines 82 | 83 | my @record = split( /\n/, $seqres ); 84 | 85 | foreach my $line (@record) { 86 | 87 | # Chain is in column 12, residues start in column 20 88 | my ($thischain) = substr( $line, 11, 1 ); 89 | my ($residues) = substr( $line, 19, 52 ); # add space at end 90 | 91 | # Check if a new chain, or continuation of previous chain 92 | if ( "$lastchain" eq "" ) { 93 | $sequence = $residues; 94 | } 95 | elsif ( "$thischain" eq "$lastchain" ) { 96 | $sequence .= $residues; 97 | 98 | # Finish gathering previous chain (unless first record) 99 | } 100 | elsif ($sequence) { 101 | push( @results, $sequence ); 102 | $sequence = $residues; 103 | } 104 | $lastchain = $thischain; 105 | } 106 | 107 | # save last chain 108 | push( @results, $sequence ); 109 | 110 | return @results; 111 | } 112 | 113 | # iub3to1 114 | # 115 | #-change string of 3-character IUB amino acid codes (whitespace separated) 116 | # into a string of 1-character amino acid codes 117 | 118 | sub iub3to1 { 119 | 120 | my ($input) = @_; 121 | 122 | my %three2one = ( 123 | 'ALA' => 'A', 124 | 'VAL' => 'V', 125 | 'LEU' => 'L', 126 | 'ILE' => 'I', 127 | 'PRO' => 'P', 128 | 'TRP' => 'W', 129 | 'PHE' => 'F', 130 | 'MET' => 'M', 131 | 'GLY' => 'G', 132 | 'SER' => 'S', 133 | 'THR' => 'T', 134 | 'TYR' => 'Y', 135 | 'CYS' => 'C', 136 | 'ASN' => 'N', 137 | 'GLN' => 'Q', 138 | 'LYS' => 'K', 139 | 'ARG' => 'R', 140 | 'HIS' => 'H', 141 | 'ASP' => 'D', 142 | 'GLU' => 'E', 143 | ); 144 | 145 | # clean up the input 146 | $input =~ s/\n/ /g; 147 | 148 | my $seq = ''; 149 | 150 | # This use of split separates on any contiguous whitespace 151 | my @code3 = split( ' ', $input ); 152 | 153 | foreach my $code (@code3) { 154 | 155 | # A little error checking 156 | if ( not defined $three2one{$code} ) { 157 | print "Code $code not defined\n"; 158 | next; 159 | } 160 | $seq .= $three2one{$code}; 161 | } 162 | return $seq; 163 | } 164 | -------------------------------------------------------------------------------- /scripts/example11-6.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 11-6 Extract atomic coordinates from PDB file 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # Read in PDB file 9 | my @file = get_file_data('pdb/c1/pdb1c1f.ent'); 10 | 11 | # Parse the record types of the PDB file 12 | my %recordtypes = parsePDBrecordtypes(@file); 13 | 14 | # Extract the atoms of all chains in the protein 15 | my %atoms = parseATOM( $recordtypes{'ATOM'} ); 16 | 17 | # Print out a couple of the atoms 18 | print $atoms{'1'}, "\n"; 19 | print $atoms{'1078'}, "\n"; 20 | 21 | exit; 22 | 23 | ################################################################################ 24 | # Subroutines of Example 11-6 25 | ################################################################################ 26 | 27 | # parseATOM 28 | # 29 | # -extract x, y, and z coordinates, serial number and element symbol 30 | # from PDB ATOM record type 31 | # Return a hash with key=serial number, value=coordinates in a string 32 | 33 | sub parseATOM { 34 | 35 | my ($atomrecord) = @_; 36 | 37 | use strict; 38 | use warnings; 39 | my %results = (); 40 | 41 | # Turn the scalar into an array of ATOM lines 42 | my (@atomrecord) = split( /\n/, $atomrecord ); 43 | 44 | foreach my $record (@atomrecord) { 45 | my $number = substr( $record, 6, 5 ); # columns 7-11 46 | my $x = substr( $record, 30, 8 ); # columns 31-38 47 | my $y = substr( $record, 38, 8 ); # columns 39-46 48 | my $z = substr( $record, 46, 8 ); # columns 47-54 49 | my $element = substr( $record, 76, 2 ); # columns 77-78 50 | 51 | # $number and $element may have leading spaces: strip them 52 | $number =~ s/^\s*//; 53 | $element =~ s/^\s*//; 54 | 55 | # Store information in hash 56 | $results{$number} = "$x $y $z $element"; 57 | } 58 | 59 | # Return the hash 60 | return %results; 61 | } 62 | -------------------------------------------------------------------------------- /scripts/example11-7.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 11-7 Call another program to perform secondary structure prediction 3 | 4 | use strict; 5 | use warnings; 6 | 7 | # Call "stride" on a file, collect the report 8 | my (@stride_output) = call_stride('pdb/c1/pdb1c1f.ent'); 9 | 10 | # Parse the stride report into primary sequence, and secondary 11 | # structure prediction 12 | my ( $sequence, $structure ) = parse_stride(@stride_output); 13 | 14 | # Print out the beginnings of the sequence and the secondary structure 15 | print substr( $sequence, 0, 80 ), "\n"; 16 | print substr( $structure, 0, 80 ), "\n"; 17 | 18 | exit; 19 | 20 | ################################################################################ 21 | # Subroutine for Example 11-7 22 | ################################################################################ 23 | 24 | # call_stride 25 | # 26 | # -given a PDB filename, return the output from the "stride" 27 | # secondary structure prediction program 28 | 29 | sub call_stride { 30 | 31 | use strict; 32 | use warnings; 33 | 34 | my ($filename) = @_; 35 | 36 | # The stride program options 37 | my ($stride) = '/usr/local/bin/stride'; 38 | my ($options) = ''; 39 | my (@results) = (); 40 | 41 | # Check for presence of PDB file 42 | unless ( -e $filename ) { 43 | print "File \"$filename\" doesn\'t seem to exist!\n"; 44 | exit; 45 | } 46 | 47 | # Start up the program, capture and return the output 48 | @results = `$stride $options $filename`; 49 | 50 | return @results; 51 | } 52 | 53 | # parse_stride 54 | # 55 | #-given stride output, extract the primary sequence and the 56 | # secondary structure prediction, returning them in a 57 | # two-element array. 58 | 59 | sub parse_stride { 60 | 61 | use strict; 62 | use warnings; 63 | 64 | my (@stridereport) = @_; 65 | my ($seq) = ''; 66 | my ($str) = ''; 67 | my $length; 68 | 69 | # Extract the lines of interest 70 | my (@seq) = grep( /^SEQ /, @stridereport ); 71 | 72 | my (@str) = grep( /^STR /, @stridereport ); 73 | 74 | # Process those lines to discard all but the sequence 75 | # or structure information 76 | for (@seq) { $_ = substr( $_, 10, 50 ) } 77 | for (@str) { $_ = substr( $_, 10, 50 ) } 78 | 79 | # Return the information as an array of two strings 80 | $seq = join( '', @seq ); 81 | $str = join( '', @str ); 82 | 83 | # Delete unwanted spaces from the ends of the strings. 84 | # ($seq has no spaces that are wanted, but $str may) 85 | $seq =~ s/(\s+)$//; 86 | 87 | $length = length($1); 88 | 89 | $str =~ s/\s{$length}$//; 90 | 91 | return ( ( $seq, $str ) ); 92 | } 93 | -------------------------------------------------------------------------------- /scripts/example12-1.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 12-1 Extract annotation and alignments from BLAST output file 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # declare and initialize variables 9 | my $beginning_annotation = ''; 10 | my $ending_annotation = ''; 11 | my %alignments = (); 12 | my $filename = 'blast.txt'; 13 | 14 | parse_blast( \$beginning_annotation, \$ending_annotation, \%alignments, 15 | $filename ); 16 | 17 | # Print the annotation, and then 18 | # print the DNA in new format just to check if we got it okay. 19 | print $beginning_annotation; 20 | 21 | foreach my $key ( keys %alignments ) { 22 | print "$key\nXXXXXXXXXXXX\n", $alignments{$key}, "\nXXXXXXXXXXX\n"; 23 | } 24 | 25 | print $ending_annotation; 26 | 27 | exit; 28 | 29 | ################################################################################ 30 | # Subroutines for Example 12-1 31 | ################################################################################ 32 | 33 | # parse_blast 34 | # 35 | # -parse beginning and ending annotation, and alignments, 36 | # from BLAST output file 37 | 38 | sub parse_blast { 39 | 40 | my ( $beginning_annotation, $ending_annotation, $alignments, $filename ) = 41 | @_; 42 | 43 | # $beginning_annotation-reference to scalar 44 | # $ending_annotation -reference to scalar 45 | # $alignments -reference to hash 46 | # $filename -scalar 47 | 48 | # declare and initialize variables 49 | my $blast_output_file = ''; 50 | my $alignment_section = ''; 51 | 52 | # Get the BLAST program output into an array from a file 53 | $blast_output_file = join( '', get_file_data($filename) ); 54 | 55 | # Extract the beginning annotation, alignments, and ending annotation 56 | ( $$beginning_annotation, $alignment_section, $$ending_annotation ) = 57 | ( $blast_output_file =~ /(.*^ALIGNMENTS\n)(.*)(^ Database:.*)/ms ); 58 | 59 | # Populate %alignments hash 60 | # key = ID of hit 61 | # value = alignment section 62 | %$alignments = parse_blast_alignment($alignment_section); 63 | } 64 | 65 | # parse_blast_alignment 66 | # 67 | # -parse the alignments from a BLAST output file, 68 | # return hash with 69 | # key = ID 70 | # value = text of alignment 71 | 72 | sub parse_blast_alignment { 73 | 74 | my ($alignment_section) = @_; 75 | 76 | # declare and initialize variables 77 | my (%alignment_hash) = (); 78 | 79 | # loop through the scalar containing the BLAST alignments, 80 | # extracting the ID and the alignment and storing in a hash 81 | # 82 | # The regular expression matches a line beginning with >, 83 | # and containing the ID between the first pair of | characters; 84 | # followed by any number of lines that don't begin with > 85 | 86 | while ( $alignment_section =~ /^>.*\n(^(?!>).*\n)+/gm ) { 87 | my ($value) = $&; 88 | my ($key) = ( split( /\|/, $value ) )[1]; 89 | $alignment_hash{$key} = $value; 90 | } 91 | 92 | return %alignment_hash; 93 | } 94 | -------------------------------------------------------------------------------- /scripts/example12-2.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 12-2 Parse alignments from BLAST output file 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # declare and initialize variables 9 | my $beginning_annotation = ''; 10 | my $ending_annotation = ''; 11 | my %alignments = (); 12 | my $alignment = ''; 13 | my $filename = 'blast.txt'; 14 | my @HSPs = (); 15 | my ( $expect, $query, $query_range, $subject, $subject_range ) = 16 | ( '', '', '', '', '' ); 17 | 18 | parse_blast( \$beginning_annotation, \$ending_annotation, \%alignments, 19 | $filename ); 20 | 21 | $alignment = $alignments{'AK017941.1'}; 22 | 23 | @HSPs = parse_blast_alignment_HSP($alignment); 24 | 25 | ( $expect, $query, $query_range, $subject, $subject_range ) = 26 | extract_HSP_information( $HSPs[1] ); 27 | 28 | # Print the results 29 | print "\n-> Expect value: $expect\n"; 30 | print "\n-> Query string: $query\n"; 31 | print "\n-> Query range: $query_range\n"; 32 | print "\n-> Subject String: $subject\n"; 33 | print "\n-> Subject range: $subject_range\n"; 34 | 35 | exit; 36 | 37 | ################################################################################ 38 | # Subroutines for Example 12-2 39 | ################################################################################ 40 | 41 | # parse_blast_alignment_HSP 42 | # 43 | # -parse beginning annotation, and HSPs, 44 | # from BLAST alignment 45 | # Return an array with first element set to the beginning annotation, 46 | # and each successive element set to an HSP 47 | 48 | sub parse_blast_alignment_HSP { 49 | 50 | my ($alignment) = @_; 51 | 52 | # declare and initialize variables 53 | my $beginning_annotation = ''; 54 | my $HSP_section = ''; 55 | my @HSPs = (); 56 | 57 | # Extract the beginning annotation and HSPs 58 | ( $beginning_annotation, $HSP_section ) = 59 | ( $alignment =~ /(.*?)(^ Score =.*)/ms ); 60 | 61 | # Store the $beginning_annotation as the first entry in @HSPs 62 | push( @HSPs, $beginning_annotation ); 63 | 64 | # Parse the HSPs, store each HSP as an element in @HSPs 65 | while ( $HSP_section =~ /(^ Score =.*\n)(^(?! Score =).*\n)+/gm ) { 66 | push( @HSPs, $& ); 67 | } 68 | 69 | # Return an array with first element = the beginning annotation, 70 | # and each successive element = an HSP 71 | return (@HSPs); 72 | } 73 | 74 | # extract_HSP_information 75 | # 76 | # -parse a HSP from a BLAST output alignment section 77 | # - return array with elements: 78 | # Expect value 79 | # Query string 80 | # Query range 81 | # Subject string 82 | # Subject range 83 | 84 | sub extract_HSP_information { 85 | 86 | my ($HSP) = @_; 87 | 88 | # declare and initialize variables 89 | my ($expect) = ''; 90 | my ($query) = ''; 91 | my ($query_range) = ''; 92 | my ($subject) = ''; 93 | my ($subject_range) = ''; 94 | 95 | ($expect) = ( $HSP =~ /Expect = (\S+)/ ); 96 | 97 | $query = join( '', ( $HSP =~ /^Query(.*)\n/gm ) ); 98 | 99 | $subject = join( '', ( $HSP =~ /^Sbjct(.*)\n/gm ) ); 100 | 101 | $query_range = join( '..', ( $query =~ /(\d+).*\D(\d+)/s ) ); 102 | 103 | $subject_range = join( '..', ( $subject =~ /(\d+).*\D(\d+)/s ) ); 104 | 105 | $query =~ s/[^acgt]//g; 106 | 107 | $subject =~ s/[^acgt]//g; 108 | 109 | return ( $expect, $query, $query_range, $subject, $subject_range ); 110 | } 111 | -------------------------------------------------------------------------------- /scripts/example12-3.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 12-3 Example of here document 3 | 4 | use strict; 5 | use warnings; 6 | 7 | my $DNA = 'AAACCCCCCGGGGGGGGTTTTTT'; 8 | 9 | for ( my $i = 0 ; $i < 2 ; ++$i ) { 10 | print <@<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<... 16 | $id, $description 17 | # The DNA lines 18 | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~ 19 | $DNA 20 | . 21 | 22 | # Print the fasta-formatted DNA output 23 | write; 24 | 25 | exit; 26 | -------------------------------------------------------------------------------- /scripts/example4-1.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 4-1 Storing DNA in a variable, and printing it out 3 | 4 | # First we store the DNA in a variable called $DNA 5 | $DNA = 'ACGGGAGGACGGGAAAATTACTACGGCATTAGC'; 6 | 7 | # Next, we print the DNA onto the screen 8 | print $DNA; 9 | 10 | # Finally, we'll specifically tell the program to exit. 11 | exit; 12 | -------------------------------------------------------------------------------- /scripts/example4-2.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 4-2 Concatenating DNA 3 | 4 | # Store two DNA fragments into two variables called $DNA1 and $DNA2 5 | $DNA1 = 'ACGGGAGGACGGGAAAATTACTACGGCATTAGC'; 6 | $DNA2 = 'ATAGTGCCGTGAGAGTGATGTAGTA'; 7 | 8 | # Print the DNA onto the screen 9 | print "Here are the original two DNA fragments:\n\n"; 10 | 11 | print $DNA1, "\n"; 12 | 13 | print $DNA2, "\n\n"; 14 | 15 | # Concatenate the DNA fragments into a third variable and print them 16 | # Using "string interpolation" 17 | $DNA3 = "$DNA1$DNA2"; 18 | 19 | print "Here is the concatenation of the first two fragments (version 1):\n\n"; 20 | 21 | print "$DNA3\n\n"; 22 | 23 | # An alternative way using the "dot operator": 24 | # Concatenate the DNA fragments into a third variable and print them 25 | $DNA3 = $DNA1 . $DNA2; 26 | 27 | print "Here is the concatenation of the first two fragments (version 2):\n\n"; 28 | 29 | print "$DNA3\n\n"; 30 | 31 | # Print the same thing without using the variable $DNA3 32 | print "Here is the concatenation of the first two fragments (version 3):\n\n"; 33 | 34 | print $DNA1, $DNA2, "\n"; 35 | 36 | exit; 37 | -------------------------------------------------------------------------------- /scripts/example4-3.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 4-3 Transcribing DNA into RNA 3 | 4 | # The DNA 5 | $DNA = 'ACGGGAGGACGGGAAAATTACTACGGCATTAGC'; 6 | 7 | # Print the DNA onto the screen 8 | print "Here is the starting DNA:\n\n"; 9 | 10 | print "$DNA\n\n"; 11 | 12 | # Transcribe the DNA to RNA by substituting all T's with U's. 13 | $RNA = $DNA; 14 | 15 | $RNA =~ s/T/U/g; 16 | 17 | # Print the RNA onto the screen 18 | print "Here is the result of transcribing the DNA to RNA:\n\n"; 19 | 20 | print "$RNA\n"; 21 | 22 | # Exit the program. 23 | exit; 24 | -------------------------------------------------------------------------------- /scripts/example4-4.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 4-4 Calculating the reverse complement of a strand of DNA 3 | 4 | # The DNA 5 | $DNA = 'ACGGGAGGACGGGAAAATTACTACGGCATTAGC'; 6 | 7 | # Print the DNA onto the screen 8 | print "Here is the starting DNA:\n\n"; 9 | 10 | print "$DNA\n\n"; 11 | 12 | # Calculate the reverse complement 13 | # Warning: this attempt will fail! 14 | # 15 | # First, copy the DNA into new variable $revcom 16 | # (short for REVerse COMplement) 17 | # Notice that variable names can use lowercase letters like 18 | # "revcom" as well as uppercase like "DNA". In fact, 19 | # lowercase is more common. 20 | # 21 | # It doesn't matter if we first reverse the string and then 22 | # do the complementation; or if we first do the complementation 23 | # and then reverse the string. Same result each time. 24 | # So when we make the copy we'll do the reverse in the same statement. 25 | # 26 | 27 | $revcom = reverse $DNA; 28 | 29 | # 30 | # Next substitute all bases by their complements, 31 | # A->T, T->A, G->C, C->G 32 | # 33 | 34 | $revcom =~ s/A/T/g; 35 | $revcom =~ s/T/A/g; 36 | $revcom =~ s/G/C/g; 37 | $revcom =~ s/C/G/g; 38 | 39 | # Print the reverse complement DNA onto the screen 40 | print "Here is the reverse complement DNA:\n\n"; 41 | 42 | print "$revcom\n"; 43 | 44 | # 45 | # Oh-oh, that didn't work right! 46 | # Our reverse complement should have all the bases in it, since the 47 | # original DNA had all the bases-but ours only has A and G! 48 | # 49 | # Do you see why? 50 | # 51 | # The problem is that the first two substitute commands above change 52 | # all the A's to T's (so there are no A's) and then all the 53 | # T's to A's (so all the original A's and T's are all now A's). 54 | # Same thing happens to the G's and C's all turning into G's. 55 | # 56 | 57 | print "\nThat was a bad algorithm, and the reverse complement was wrong!\n"; 58 | print "Try again ... \n\n"; 59 | 60 | # Make a new copy of the DNA (see why we saved the original?) 61 | $revcom = reverse $DNA; 62 | 63 | # See the text for a discussion of tr/// 64 | $revcom =~ tr/ACGTacgt/TGCAtgca/; 65 | 66 | # Print the reverse complement DNA onto the screen 67 | print "Here is the reverse complement DNA:\n\n"; 68 | 69 | print "$revcom\n"; 70 | 71 | print "\nThis time it worked!\n\n"; 72 | 73 | exit; 74 | -------------------------------------------------------------------------------- /scripts/example4-5.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 4-5 Reading protein sequence data from a file 3 | 4 | # The filename of the file containing the protein sequence data 5 | $proteinfilename = 'NM_021964fragment.pep'; 6 | 7 | # First we have to "open" the file, and associate 8 | # a "filehandle" with it. We choose the filehandle 9 | # PROTEINFILE for readability. 10 | open( PROTEINFILE, $proteinfilename ); 11 | 12 | # Now we do the actual reading of the protein sequence data from the file, 13 | # by using the angle brackets < and > to get the input from the 14 | # filehandle. We store the data into our variable $protein. 15 | $protein = ; 16 | 17 | # Now that we've got our data, we can close the file. 18 | close PROTEINFILE; 19 | 20 | # Print the protein onto the screen 21 | print "Here is the protein:\n\n"; 22 | 23 | print $protein; 24 | 25 | exit; 26 | -------------------------------------------------------------------------------- /scripts/example4-6.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 4-6 Reading protein sequence data from a file, take 2 3 | 4 | # The filename of the file containing the protein sequence data 5 | $proteinfilename = 'NM_021964fragment.pep'; 6 | 7 | # First we have to "open" the file, and associate 8 | # a "filehandle" with it. We choose the filehandle 9 | # PROTEINFILE for readability. 10 | open( PROTEINFILE, $proteinfilename ); 11 | 12 | # Now we do the actual reading of the protein sequence data from the file, 13 | # by using the angle brackets < and > to get the input from the 14 | # filehandle. We store the data into our variable $protein. 15 | # 16 | # Since the file has three lines, and since the read only is 17 | # returning one line, we'll read a line and print it, three times. 18 | 19 | # First line 20 | $protein = ; 21 | 22 | # Print the protein onto the screen 23 | print "\nHere is the first line of the protein file:\n\n"; 24 | 25 | print $protein; 26 | 27 | # Second line 28 | $protein = ; 29 | 30 | # Print the protein onto the screen 31 | print "\nHere is the second line of the protein file:\n\n"; 32 | 33 | print $protein; 34 | 35 | # Third line 36 | $protein = ; 37 | 38 | # Print the protein onto the screen 39 | print "\nHere is the third line of the protein file:\n\n"; 40 | 41 | print $protein; 42 | 43 | # Now that we've got our data, we can close the file. 44 | close PROTEINFILE; 45 | 46 | exit; 47 | -------------------------------------------------------------------------------- /scripts/example4-7.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 4-7 Reading protein sequence data from a file, take 3 3 | 4 | # The filename of the file containing the protein sequence data 5 | $proteinfilename = 'NM_021964fragment.pep'; 6 | 7 | # First we have to "open" the file 8 | open( PROTEINFILE, $proteinfilename ); 9 | 10 | # Read the protein sequence data from the file, and store it 11 | # into the array variable @protein 12 | @protein = ; 13 | 14 | # Print the protein onto the screen 15 | print @protein; 16 | 17 | # Close the file. 18 | close PROTEINFILE; 19 | 20 | exit; 21 | -------------------------------------------------------------------------------- /scripts/example4-8.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 4-8 Demonstration of "scalar context" and "list context" 3 | 4 | @bases = ( 'A', 'C', 'G', 'T' ); 5 | 6 | print "@bases\n"; 7 | 8 | $a = @bases; 9 | 10 | print $a, "\n"; 11 | 12 | ($a) = @bases; 13 | 14 | print $a, "\n"; 15 | 16 | exit; 17 | -------------------------------------------------------------------------------- /scripts/example5-1.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 5-1 if-elsif-else 3 | 4 | $word = 'MNIDDKL'; 5 | 6 | # if-elsif-else conditionals 7 | if ( $word eq 'QSTVSGE' ) { 8 | 9 | print "QSTVSGE\n"; 10 | 11 | } 12 | elsif ( $word eq 'MRQQDMISHDEL' ) { 13 | 14 | print "MRQQDMISHDEL\n"; 15 | 16 | } 17 | elsif ( $word eq 'MNIDDKL' ) { 18 | 19 | print "MNIDDKL-the magic word!\n"; 20 | 21 | } 22 | else { 23 | 24 | print "Is \"$word\" a peptide? This program is not sure.\n"; 25 | 26 | } 27 | 28 | exit; 29 | -------------------------------------------------------------------------------- /scripts/example5-2.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 5-2 Reading protein sequence data from a file, take 4 3 | 4 | # The filename of the file containing the protein sequence data 5 | $proteinfilename = 'NM_021964fragment.pep'; 6 | 7 | # First we have to "open" the file, and in case the 8 | # open fails, print an error message and exit the program. 9 | unless ( open( PROTEINFILE, $proteinfilename ) ) { 10 | 11 | print "Could not open file $proteinfilename!\n"; 12 | exit; 13 | } 14 | 15 | # Read the protein sequence data from the file in a "while" loop, 16 | # printing each line as it is read. 17 | while ( $protein = ) { 18 | 19 | print " ###### Here is the next line of the file:\n"; 20 | 21 | print $protein; 22 | } 23 | 24 | # Close the file. 25 | close PROTEINFILE; 26 | 27 | exit; 28 | -------------------------------------------------------------------------------- /scripts/example5-3.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 5-3 Searching for motifs 3 | 4 | # Ask the user for the filename of the file containing 5 | # the protein sequence data, and collect it from the keyboard 6 | print "Please type the filename of the protein sequence data: "; 7 | 8 | $proteinfilename = ; 9 | 10 | # Remove the newline from the protein filename 11 | chomp $proteinfilename; 12 | 13 | # open the file, or exit 14 | unless ( open( PROTEINFILE, $proteinfilename ) ) { 15 | 16 | print "Cannot open file \"$proteinfilename\"\n\n"; 17 | exit; 18 | } 19 | 20 | # Read the protein sequence data from the file, and store it 21 | # into the array variable @protein 22 | @protein = ; 23 | 24 | # Close the file - we've read all the data into @protein now. 25 | close PROTEINFILE; 26 | 27 | # Put the protein sequence data into a single string, as it's easier 28 | # to search for a motif in a string than in an array of 29 | # lines (what if the motif occurs over a line break?) 30 | $protein = join( '', @protein ); 31 | 32 | # Remove whitespace 33 | $protein =~ s/\s//g; 34 | 35 | # In a loop, ask the user for a motif, search for the motif, 36 | # and report if it was found. 37 | # Exit if no motif is entered. 38 | do { 39 | print "Enter a motif to search for: "; 40 | 41 | $motif = ; 42 | 43 | # Remove the newline at the end of $motif 44 | 45 | chomp $motif; 46 | 47 | # Look for the motif 48 | 49 | if ( $protein =~ /$motif/ ) { 50 | 51 | print "I found it!\n\n"; 52 | 53 | } 54 | else { 55 | 56 | print "I couldn\'t find it.\n\n"; 57 | } 58 | 59 | # exit on an empty user input 60 | } until ( $motif =~ /^\s*$/ ); 61 | 62 | # exit the program 63 | exit; 64 | -------------------------------------------------------------------------------- /scripts/example5-4.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 5-4 Determining frequency of nucleotides 3 | 4 | # Get the name of the file with the DNA sequence data 5 | print "Please type the filename of the DNA sequence data: "; 6 | 7 | $dna_filename = ; 8 | 9 | # Remove the newline from the DNA filename 10 | chomp $dna_filename; 11 | 12 | # open the file, or exit 13 | unless ( open( DNAFILE, $dna_filename ) ) { 14 | 15 | print "Cannot open file \"$dna_filename\"\n\n"; 16 | exit; 17 | } 18 | 19 | # Read the DNA sequence data from the file, and store it 20 | # into the array variable @DNA 21 | @DNA = ; 22 | 23 | # Close the file 24 | close DNAFILE; 25 | 26 | # From the lines of the DNA file, 27 | # put the DNA sequence data into a single string. 28 | $DNA = join( '', @DNA ); 29 | 30 | # Remove whitespace 31 | $DNA =~ s/\s//g; 32 | 33 | # Now explode the DNA into an array where each letter of the 34 | # original string is now an element in the array. 35 | # This will make it easy to look at each position. 36 | # Notice that we're reusing the variable @DNA for this purpose. 37 | @DNA = split( '', $DNA ); 38 | 39 | # Initialize the counts. 40 | # Notice that we can use scalar variables to hold numbers. 41 | $count_of_A = 0; 42 | $count_of_C = 0; 43 | $count_of_G = 0; 44 | $count_of_T = 0; 45 | $errors = 0; 46 | 47 | # In a loop, look at each base in turn, determine which of the 48 | # four types of nucleotides it is, and increment the 49 | # appropriate count. 50 | foreach $base (@DNA) { 51 | 52 | if ( $base eq 'A' ) { 53 | ++$count_of_A; 54 | } 55 | elsif ( $base eq 'C' ) { 56 | ++$count_of_C; 57 | } 58 | elsif ( $base eq 'G' ) { 59 | ++$count_of_G; 60 | } 61 | elsif ( $base eq 'T' ) { 62 | ++$count_of_T; 63 | } 64 | else { 65 | print "!!!!!!!! Error - I don\'t recognize this base: $base\n"; 66 | ++$errors; 67 | } 68 | } 69 | 70 | # print the results 71 | print "A = $count_of_A\n"; 72 | print "C = $count_of_C\n"; 73 | print "G = $count_of_G\n"; 74 | print "T = $count_of_T\n"; 75 | print "errors = $errors\n"; 76 | 77 | # exit the program 78 | exit; 79 | -------------------------------------------------------------------------------- /scripts/example5-5.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 5-5 Demonstration of Perl's built-in knowledge about numbers and strings 3 | 4 | $num = 1234; 5 | 6 | $str = '1234'; 7 | 8 | # print the variables 9 | print $num, " ", $str, "\n"; 10 | 11 | # add the variables as numbers 12 | $num_or_str = $num + $str; 13 | 14 | print $num_or_str, "\n"; 15 | 16 | # concatenate the variables as strings 17 | $num_or_str = $num . $str; 18 | 19 | print $num_or_str, "\n"; 20 | 21 | exit; 22 | -------------------------------------------------------------------------------- /scripts/example5-6.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 5-6 Determining frequency of nucleotides, take 2 3 | 4 | # Get the DNA sequence data 5 | print "Please type the filename of the DNA sequence data: "; 6 | 7 | $dna_filename = ; 8 | 9 | chomp $dna_filename; 10 | 11 | # Does the file exist? 12 | unless ( -e $dna_filename ) { 13 | 14 | print "File \"$dna_filename\" doesn\'t seem to exist!!\n"; 15 | exit; 16 | } 17 | 18 | # Can we open the file? 19 | unless ( open( DNAFILE, $dna_filename ) ) { 20 | 21 | print "Cannot open file \"$dna_filename\"\n\n"; 22 | exit; 23 | } 24 | 25 | @DNA = ; 26 | 27 | close DNAFILE; 28 | 29 | $DNA = join( '', @DNA ); 30 | 31 | # Remove whitespace 32 | $DNA =~ s/\s//g; 33 | 34 | # Initialize the counts. 35 | # Notice that we can use scalar variables to hold numbers. 36 | $count_of_A = 0; 37 | $count_of_C = 0; 38 | $count_of_G = 0; 39 | $count_of_T = 0; 40 | $errors = 0; 41 | 42 | # In a loop, look at each base in turn, determine which of the 43 | # four types of nucleotides it is, and increment the 44 | # appropriate count. 45 | for ( $position = 0 ; $position < length $DNA ; ++$position ) { 46 | 47 | $base = substr( $DNA, $position, 1 ); 48 | 49 | if ( $base eq 'A' ) { 50 | ++$count_of_A; 51 | } 52 | elsif ( $base eq 'C' ) { 53 | ++$count_of_C; 54 | } 55 | elsif ( $base eq 'G' ) { 56 | ++$count_of_G; 57 | } 58 | elsif ( $base eq 'T' ) { 59 | ++$count_of_T; 60 | } 61 | else { 62 | print "!!!!!!!! Error - I don\'t recognize this base: $base\n"; 63 | ++$errors; 64 | } 65 | } 66 | 67 | # print the results 68 | print "A = $count_of_A\n"; 69 | print "C = $count_of_C\n"; 70 | print "G = $count_of_G\n"; 71 | print "T = $count_of_T\n"; 72 | print "errors = $errors\n"; 73 | 74 | # exit the program 75 | exit; 76 | -------------------------------------------------------------------------------- /scripts/example5-7.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 5-7 Determining frequency of nucleotides, take 3 3 | 4 | # Get the DNA sequence data 5 | print "Please type the filename of the DNA sequence data: "; 6 | 7 | $dna_filename = ; 8 | 9 | chomp $dna_filename; 10 | 11 | # Does the file exist? 12 | unless ( -e $dna_filename ) { 13 | 14 | print "File \"$dna_filename\" doesn\'t seem to exist!!\n"; 15 | exit; 16 | } 17 | 18 | # Can we open the file? 19 | unless ( open( DNAFILE, $dna_filename ) ) { 20 | 21 | print "Cannot open file \"$dna_filename\"\n\n"; 22 | exit; 23 | } 24 | 25 | @DNA = ; 26 | 27 | close DNAFILE; 28 | 29 | $DNA = join( '', @DNA ); 30 | 31 | # Remove whitespace 32 | $DNA =~ s/\s//g; 33 | 34 | # Initialize the counts. 35 | # Notice that we can use scalar variables to hold numbers. 36 | $a = 0; 37 | $c = 0; 38 | $g = 0; 39 | $t = 0; 40 | $e = 0; 41 | 42 | # Use a regular expression "trick", and five while loops, 43 | # to find the counts of the four bases plus errors 44 | while ( $DNA =~ /a/ig ) { $a++ } 45 | while ( $DNA =~ /c/ig ) { $c++ } 46 | while ( $DNA =~ /g/ig ) { $g++ } 47 | while ( $DNA =~ /t/ig ) { $t++ } 48 | while ( $DNA =~ /[^acgt]/ig ) { $e++ } 49 | 50 | print "A=$a C=$c G=$g T=$t errors=$e\n"; 51 | 52 | # Also write the results to a file called "countbase" 53 | $outputfile = "countbase"; 54 | 55 | unless ( open( COUNTBASE, ">$outputfile" ) ) { 56 | 57 | print "Cannot open file \"$outputfile\" to write to!!\n\n"; 58 | exit; 59 | } 60 | 61 | print COUNTBASE "A=$a C=$c G=$g T=$t errors=$e\n"; 62 | 63 | close(COUNTBASE); 64 | 65 | # exit the program 66 | exit; 67 | -------------------------------------------------------------------------------- /scripts/example6-1.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 6-1 A program with a subroutine to append ACGT to DNA 3 | 4 | # The original DNA 5 | $dna = 'CGACGTCTTCTCAGGCGA'; 6 | 7 | # The call to the subroutine "addACGT". 8 | # The argument being passed in is $dna; the result is saved in $longer_dna 9 | $longer_dna = addACGT($dna); 10 | 11 | print "I added ACGT to $dna and got $longer_dna\n\n"; 12 | 13 | exit; 14 | 15 | ################################################################################ 16 | # Subroutines for Example 6-1 17 | ################################################################################ 18 | 19 | # Here is the definition for subroutine "addACGT" 20 | 21 | sub addACGT { 22 | my ($dna) = @_; 23 | 24 | $dna .= 'ACGT'; 25 | return $dna; 26 | } 27 | -------------------------------------------------------------------------------- /scripts/example6-2.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 6-2 Illustrating the pitfalls of not using my variables 3 | 4 | $dna = 'AAAAA'; 5 | 6 | $result = A_to_T($dna); 7 | 8 | print "I changed all the A's in $dna to T's and got $result\n\n"; 9 | 10 | exit; 11 | 12 | ################################################################################ 13 | # Subroutines 14 | ################################################################################ 15 | sub A_to_T { 16 | my ($input) = @_; 17 | 18 | $dna = $input; 19 | 20 | $dna =~ s/A/T/g; 21 | 22 | return $dna; 23 | } 24 | -------------------------------------------------------------------------------- /scripts/example6-3.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 6-3 Counting the number of G's in some DNA on the command line 3 | 4 | use strict; 5 | 6 | # Collect the DNA from the arguments on the command line 7 | # when the user calls the program. 8 | # If no arguments are given, print a USAGE statement and exit. 9 | 10 | # $0 is a special variable that has the name of the program. 11 | my ($USAGE) = "$0 DNA\n\n"; 12 | 13 | # @ARGV is an array containing all command-line arguments. 14 | # 15 | # If it is empty, the test will fail and the print USAGE and exit 16 | # statements will be called. 17 | unless (@ARGV) { 18 | print $USAGE; 19 | exit; 20 | } 21 | 22 | # Read in the DNA from the argument on the command line. 23 | my ($dna) = $ARGV[0]; 24 | 25 | # Call the subroutine that does the real work, and collect the result. 26 | my ($num_of_Gs) = countG($dna); 27 | 28 | # Report the result and exit. 29 | print "\nThe DNA $dna has $num_of_Gs G\'s in it!\n\n"; 30 | 31 | exit; 32 | 33 | ################################################################################ 34 | # Subroutines for Example 6-3 35 | ################################################################################ 36 | 37 | sub countG { 38 | 39 | # return a count of the number of G's in the argument $dna 40 | 41 | # initialize arguments and variables 42 | my ($dna) = @_; 43 | 44 | my ($count) = 0; 45 | 46 | # Use the fourth method of counting nucleotides in DNA, as shown in 47 | # Chapter Four, "Motifs and Loops" 48 | $count = ( $dna =~ tr/Gg// ); 49 | 50 | return $count; 51 | } 52 | -------------------------------------------------------------------------------- /scripts/example6-4.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Example 6-4 A program with a bug or two 3 | # 4 | # An optional argument, for where to start printing the sequence, 5 | # is a two-base subsequence. 6 | # 7 | # Print everything from the subsequence ( or TA if no subsequence 8 | # is given as an argument) to the end of the DNA. 9 | 10 | # declare and initialize variables 11 | my $dna = 'CGACGTCTTCTAAGGCGA'; 12 | my @dna; 13 | my $receivingcommittment; 14 | my $previousbase = ''; 15 | 16 | my $subsequence = ''; 17 | 18 | if (@ARGV) { 19 | my $subsequence = $ARGV[0]; 20 | } 21 | else { 22 | $subsequence = 'TA'; 23 | } 24 | 25 | my $base1 = substr( $subsequence, 0, 1 ); 26 | my $base2 = substr( $subsequence, 1, 1 ); 27 | 28 | # explode DNA 29 | @dna = split( '', $dna ); 30 | 31 | ######### Pseudocode of the following loop: 32 | # 33 | # If you've received a committment, print the base and continue. Otherwise: 34 | # 35 | # If the previous base was $base1, and this base is $base2, print them. 36 | # You have now received a committment to print the rest of the string. 37 | # 38 | # At each loop, save the previous base. 39 | 40 | foreach (@dna) { 41 | if ($receivingcommittment) { 42 | print; 43 | next; 44 | } 45 | elsif ( $previousbase eq $base1 ) { 46 | if (/$base2/) { 47 | print $base1, $base2; 48 | $recievingcommitment = 1; 49 | } 50 | } 51 | $previousbase = $_; 52 | } 53 | 54 | print "\n"; 55 | 56 | exit; 57 | -------------------------------------------------------------------------------- /scripts/example7-1.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 7-1 Children's game, demonstrating primitive artificial intelligence, 3 | # using a random number generator to randomly select parts of sentences. 4 | 5 | use strict; 6 | use warnings; 7 | 8 | # Declare the variables 9 | my $count; 10 | my $input; 11 | my $number; 12 | my $sentence; 13 | my $story; 14 | 15 | # Here are the arrays of parts of sentences: 16 | my @nouns = ( 17 | 'Dad', 'TV', 'Mom', 'Groucho', 18 | 'Rebecca', 'Harpo', 'Robin Hood', 'Joe and Moe', 19 | ); 20 | 21 | my @verbs = ( 22 | 'ran to', 'giggled with', 'put hot sauce into the orange juice of', 23 | 'exploded', 'dissolved', 'sang stupid songs with', 24 | 'jumped with', 25 | ); 26 | 27 | my @prepositions = ( 28 | 'at the store', 29 | 'over the rainbow', 30 | 'just for the fun of it', 31 | 'at the beach', 32 | 'before dinner', 33 | 'in New York City', 34 | 'in a dream', 35 | 'around the world', 36 | ); 37 | 38 | # Seed the random number generator. 39 | # time|$$ combines the current time with the current process id 40 | # in a somewhat weak attempt to come up with a random seed. 41 | srand( time | $$ ); 42 | 43 | # This do-until loop composes six-sentence "stories". 44 | # until the user types "quit". 45 | do { 46 | 47 | # (Re)set $story to the empty string each time through the loop 48 | $story = ''; 49 | 50 | # Make 6 sentences per story. 51 | for ( $count = 0 ; $count < 6 ; $count++ ) { 52 | 53 | # Notes on the following statements: 54 | # 1) scalar @array gives the number of elements in the array. 55 | # 2) rand returns a random number greater than 0 and 56 | # less than scalar(@array). 57 | # 3) int removes the fractional part of a number. 58 | # 4) . joins two strings together. 59 | $sentence = 60 | $nouns[ int( rand( scalar @nouns ) ) ] . " " 61 | . $verbs[ int( rand( scalar @verbs ) ) ] . " " 62 | . $nouns[ int( rand( scalar @nouns ) ) ] . " " 63 | . $prepositions[ int( rand( scalar @prepositions ) ) ] . '. '; 64 | 65 | $story .= $sentence; 66 | } 67 | 68 | # Print the story. 69 | print "\n", $story, "\n"; 70 | 71 | # Get user input. 72 | print "\nType \"quit\" to quit, or press Enter to continue: "; 73 | 74 | $input = ; 75 | 76 | # Exit loop at user's request 77 | } until ( $input =~ /^\s*q/i ); 78 | 79 | exit; 80 | -------------------------------------------------------------------------------- /scripts/example7-2.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 7-2 Mutate DNA 3 | # using a random number generator to randomly select bases to mutate 4 | 5 | use strict; 6 | use warnings; 7 | 8 | # Declare the variables 9 | 10 | # The DNA is chosen to make it easy to see mutations: 11 | my $DNA = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'; 12 | 13 | # $i is a common name for a counter variable, short for "integer" 14 | my $i; 15 | 16 | my $mutant; 17 | 18 | # Seed the random number generator. 19 | # time|$$ combines the current time with the current process id 20 | srand( time | $$ ); 21 | 22 | # Let's test it, shall we? 23 | $mutant = mutate($DNA); 24 | 25 | print "\nMutate DNA\n\n"; 26 | 27 | print "\nHere is the original DNA:\n\n"; 28 | print "$DNA\n"; 29 | 30 | print "\nHere is the mutant DNA:\n\n"; 31 | print "$mutant\n"; 32 | 33 | # Let's put it in a loop and watch that bad boy accumulate mutations: 34 | print "\nHere are 10 more successive mutations:\n\n"; 35 | 36 | for ( $i = 0 ; $i < 10 ; ++$i ) { 37 | $mutant = mutate($mutant); 38 | print "$mutant\n"; 39 | } 40 | 41 | exit; 42 | ################################################################################ 43 | # Subroutines for Example 7-2 44 | ################################################################################ 45 | 46 | # Notice, now that we have a fair number of subroutines, we 47 | # list them alphabetically 48 | 49 | # A subroutine to perform a mutation in a string of DNA 50 | # 51 | # WARNING: make sure you call srand to seed the 52 | # random number generator before you call this function. 53 | 54 | sub mutate { 55 | 56 | my ($dna) = @_; 57 | 58 | my (@nucleotides) = ( 'A', 'C', 'G', 'T' ); 59 | 60 | # Pick a random position in the DNA 61 | my ($position) = randomposition($dna); 62 | 63 | # Pick a random nucleotide 64 | my ($newbase) = randomnucleotide(@nucleotides); 65 | 66 | # Insert the random nucleotide into the random position in the DNA 67 | # The substr arguments mean the following: 68 | # In the string $dna at position $position change 1 character to 69 | # the string in $newbase 70 | substr( $dna, $position, 1, $newbase ); 71 | 72 | return $dna; 73 | } 74 | 75 | # A subroutine to randomly select an element from an array 76 | # 77 | # WARNING: make sure you call srand to seed the 78 | # random number generator before you call this function. 79 | 80 | sub randomelement { 81 | 82 | my (@array) = @_; 83 | 84 | return $array[ rand @array ]; 85 | } 86 | 87 | # randomnucleotide 88 | # 89 | # A subroutine to select at random one of the four nucleotides 90 | # 91 | # WARNING: make sure you call srand to seed the 92 | # random number generator before you call this function. 93 | 94 | sub randomnucleotide { 95 | 96 | my (@nucleotides) = ( 'A', 'C', 'G', 'T' ); 97 | 98 | # scalar returns the size of an array. 99 | # The elements of the array are numbered 0 to size-1 100 | return randomelement(@nucleotides); 101 | } 102 | 103 | # randomposition 104 | # 105 | # A subroutine to randomly select a position in a string. 106 | # 107 | # WARNING: make sure you call srand to seed the 108 | # random number generator before you call this function. 109 | 110 | sub randomposition { 111 | 112 | my ($string) = @_; 113 | 114 | # Notice the "nested" arguments: 115 | # 116 | # $string is the argument to length 117 | # length($string) is the argument to rand 118 | # rand(length($string))) is the argument to int 119 | # int(rand(length($string))) is the argument to return 120 | # But we write it without parentheses, as permitted. 121 | # 122 | # rand returns a decimal number between 0 and its argument. 123 | # int returns the integer portion of a decimal number. 124 | # 125 | # The whole expression returns a random number between 0 and length-1, 126 | # which is how the positions in a string are numbered in Perl. 127 | # 128 | 129 | return int rand length $string; 130 | } 131 | -------------------------------------------------------------------------------- /scripts/example7-3.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 7-3 Generate random DNA 3 | # using a random number generator to randomly select bases 4 | 5 | use strict; 6 | use warnings; 7 | 8 | # Declare and initialize the variables 9 | my $size_of_set = 12; 10 | my $maximum_length = 30; 11 | my $minimum_length = 15; 12 | 13 | # An array, initialized to the empty list, to store the DNA in 14 | my @random_DNA = (); 15 | 16 | # Seed the random number generator. 17 | # time|$$ combines the current time with the current process id 18 | srand( time | $$ ); 19 | 20 | # And here's the subroutine call to do the real work 21 | @random_DNA = 22 | make_random_DNA_set( $minimum_length, $maximum_length, $size_of_set ); 23 | 24 | # Print the results, one per line 25 | print "Here is an array of $size_of_set randomly generated DNA sequences\n"; 26 | print " with lengths between $minimum_length and $maximum_length:\n\n"; 27 | 28 | foreach my $dna (@random_DNA) { 29 | 30 | print "$dna\n"; 31 | } 32 | 33 | print "\n"; 34 | 35 | exit; 36 | 37 | ################################################################################ 38 | # Subroutines 39 | ################################################################################ 40 | 41 | # make_random_DNA_set 42 | # 43 | # Make a set of random DNA 44 | # 45 | # Accept parameters setting the maximum and minimum length of 46 | # each string of DNA, and the number of DNA strings to make 47 | # 48 | # WARNING: make sure you call srand to seed the 49 | # random number generator before you call this function. 50 | 51 | sub make_random_DNA_set { 52 | 53 | # Collect arguments, declare variables 54 | my ( $minimum_length, $maximum_length, $size_of_set ) = @_; 55 | 56 | # length of each DNA fragment 57 | my $length; 58 | 59 | # DNA fragment 60 | my $dna; 61 | 62 | # set of DNA fragments 63 | my @set; 64 | 65 | # Create set of random DNA 66 | for ( my $i = 0 ; $i < $size_of_set ; ++$i ) { 67 | 68 | # find a random length between min and max 69 | $length = randomlength( $minimum_length, $maximum_length ); 70 | 71 | # make a random DNA fragment 72 | $dna = make_random_DNA($length); 73 | 74 | # add $dna fragment to @set 75 | push( @set, $dna ); 76 | } 77 | 78 | return @set; 79 | } 80 | 81 | # Notice that we've just discovered a new subroutine that's 82 | # needed: randomlength, which will return a random 83 | # number between (or including) the min and max values. 84 | # Let's write that first, then do make_random_DNA 85 | 86 | # randomlength 87 | # 88 | # A subroutine that will pick a random number from 89 | # $minlength to $maxlength, inclusive. 90 | # 91 | # WARNING: make sure you call srand to seed the 92 | # random number generator before you call this function. 93 | 94 | sub randomlength { 95 | 96 | # Collect arguments, declare variables 97 | my ( $minlength, $maxlength ) = @_; 98 | 99 | # Calculate and return a random number within the 100 | # desired interval. 101 | # Notice how we need to add one to make the endpoints inclusive, 102 | # and how we first subtract, then add back, $minlength to 103 | # get the random number in the correct interval. 104 | return ( int( rand( $maxlength - $minlength + 1 ) ) + $minlength ); 105 | } 106 | 107 | # make_random_DNA 108 | # 109 | # Make a string of random DNA of specified length. 110 | # 111 | # WARNING: make sure you call srand to seed the 112 | # random number generator before you call this function. 113 | 114 | sub make_random_DNA { 115 | 116 | # Collect arguments, declare variables 117 | my ($length) = @_; 118 | 119 | my $dna; 120 | 121 | for ( my $i = 0 ; $i < $length ; ++$i ) { 122 | 123 | $dna .= randomnucleotide(); 124 | } 125 | 126 | return $dna; 127 | } 128 | 129 | # We also need to include the previous subroutine 130 | # randomnucleotide. 131 | # Here it is again for completeness. 132 | 133 | # randomnucleotide 134 | # 135 | # Select at random one of the four nucleotides 136 | # 137 | # WARNING: make sure you call srand to seed the 138 | # random number generator before you call this function. 139 | 140 | sub randomnucleotide { 141 | 142 | my (@nucleotides) = ( 'A', 'C', 'G', 'T' ); 143 | 144 | # scalar returns the size of an array. 145 | # The elements of the array are numbered 0 to size-1 146 | return randomelement(@nucleotides); 147 | } 148 | 149 | # randomelement 150 | # 151 | # randomly select an element from an array 152 | # 153 | # WARNING: make sure you call srand to seed the 154 | # random number generator before you call this function. 155 | 156 | sub randomelement { 157 | 158 | my (@array) = @_; 159 | 160 | return $array[ rand @array ]; 161 | } 162 | -------------------------------------------------------------------------------- /scripts/example7-4.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 7-4 Calculate the average percentage of positions that are the same 3 | # between two random DNA sequences, in a set of 10 sequences. 4 | 5 | use strict; 6 | use warnings; 7 | 8 | # Declare and initialize the variables 9 | my $percent; 10 | my @percentages; 11 | my $result; 12 | 13 | # An array, initialized to the empty list, to store the DNA in 14 | my @random_DNA = (); 15 | 16 | # Seed the random number generator. 17 | # time|$$ combines the current time with the current process id 18 | srand( time | $$ ); 19 | 20 | # Generate the data set of 10 DNA sequences. 21 | @random_DNA = make_random_DNA_set( 10, 10, 10 ); 22 | 23 | # Iterate through all pairs of sequences 24 | for ( my $k = 0 ; $k < scalar @random_DNA - 1 ; ++$k ) { 25 | for ( my $i = ( $k + 1 ) ; $i < scalar @random_DNA ; ++$i ) { 26 | 27 | # Calculate and save the matching percentage 28 | $percent = matching_percentage( $random_DNA[$k], $random_DNA[$i] ); 29 | push( @percentages, $percent ); 30 | } 31 | } 32 | 33 | # Finally, the average result: 34 | $result = 0; 35 | 36 | foreach $percent (@percentages) { 37 | $result += $percent; 38 | } 39 | 40 | $result = $result / scalar(@percentages); 41 | 42 | #Turn result into a true percentage 43 | $result = int( $result * 100 ); 44 | print "In this run of the experiment, the average percentage of \n"; 45 | print "matching positions is $result%\n\n"; 46 | 47 | exit; 48 | 49 | ################################################################################ 50 | # Subroutines 51 | ################################################################################ 52 | 53 | # matching_percentage 54 | # 55 | # Subroutine to calculate the percentage of identical bases in two 56 | # equal length DNA sequences 57 | 58 | sub matching_percentage { 59 | 60 | my ( $string1, $string2 ) = @_; 61 | 62 | # we assume that the strings have the same length 63 | my ($length) = length($string1); 64 | my ($position); 65 | my ($count) = 0; 66 | 67 | for ( $position = 0 ; $position < $length ; ++$position ) { 68 | if ( 69 | substr( $string1, $position, 1 ) eq substr( $string2, $position, 1 ) 70 | ) 71 | { 72 | ++$count; 73 | } 74 | } 75 | 76 | return $count / $length; 77 | } 78 | 79 | # make_random_DNA_set 80 | # 81 | # Subroutine to make a set of random DNA 82 | # 83 | # Accept parameters setting the maximum and minimum length of 84 | # each string of DNA, and the number of DNA strings to make 85 | # 86 | # WARNING: make sure you call srand to seed the 87 | # random number generator before you call this function. 88 | 89 | sub make_random_DNA_set { 90 | 91 | # Collect arguments, declare variables 92 | my ( $minimum_length, $maximum_length, $size_of_set ) = @_; 93 | 94 | # length of each DNA fragment 95 | my $length; 96 | 97 | # DNA fragment 98 | my $dna; 99 | 100 | # set of DNA fragments 101 | my @set; 102 | 103 | # Create set of random DNA 104 | for ( my $i = 0 ; $i < $size_of_set ; ++$i ) { 105 | 106 | # find a random length between min and max 107 | $length = randomlength( $minimum_length, $maximum_length ); 108 | 109 | # make a random DNA fragment 110 | $dna = make_random_DNA($length); 111 | 112 | # add $dna fragment to @set 113 | push( @set, $dna ); 114 | } 115 | 116 | return @set; 117 | } 118 | 119 | # randomlength 120 | # 121 | # A subroutine that will pick a random number from 122 | # $minlength to $maxlength, inclusive. 123 | # 124 | # WARNING: make sure you call srand to seed the 125 | # random number generator before you call this function. 126 | 127 | sub randomlength { 128 | 129 | # Collect arguments, declare variables 130 | my ( $minlength, $maxlength ) = @_; 131 | 132 | # Calculate and return a random number within the 133 | # desired interval. 134 | # Notice how we need to add one to make the endpoints inclusive, 135 | # and how we first subtract, then add back, $minlength to 136 | # get the random number in the correct interval. 137 | return ( int( rand( $maxlength - $minlength + 1 ) ) + $minlength ); 138 | } 139 | 140 | # make_random_DNA 141 | # 142 | # Make a string of random DNA of specified length. 143 | # 144 | # WARNING: make sure you call srand to seed the 145 | # random number generator before you call this function. 146 | 147 | sub make_random_DNA { 148 | 149 | # Collect arguments, declare variables 150 | my ($length) = @_; 151 | 152 | my $dna; 153 | 154 | for ( my $i = 0 ; $i < $length ; ++$i ) { 155 | $dna .= randomnucleotide(); 156 | } 157 | 158 | return $dna; 159 | } 160 | 161 | # randomnucleotide 162 | # 163 | # Select at random one of the four nucleotides 164 | # 165 | # WARNING: make sure you call srand to seed the 166 | # random number generator before you call this function. 167 | 168 | sub randomnucleotide { 169 | 170 | my (@nucleotides) = ( 'A', 'C', 'G', 'T' ); 171 | 172 | # scalar returns the size of an array. 173 | # The elements of the array are numbered 0 to size-1 174 | return randomelement(@nucleotides); 175 | } 176 | 177 | # randomelement 178 | # 179 | # randomly select an element from an array 180 | # 181 | # WARNING: make sure you call srand to seed the 182 | # random number generator before you call this function. 183 | 184 | sub randomelement { 185 | 186 | my (@array) = @_; 187 | 188 | return $array[ rand @array ]; 189 | } 190 | -------------------------------------------------------------------------------- /scripts/example8-1.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 8-1 Translate DNA into protein 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # Initialize variables 9 | my $dna = 'CGACGTCTTCGTACGGGACTAGCTCGTGTCGGTCGC'; 10 | my $protein = ''; 11 | my $codon; 12 | 13 | # Translate each three-base codon into an amino acid, and append to a protein 14 | for ( my $i = 0 ; $i < ( length($dna) - 2 ) ; $i += 3 ) { 15 | $codon = substr( $dna, $i, 3 ); 16 | $protein .= codon2aa($codon); 17 | } 18 | 19 | print "I translated the DNA\n\n$dna\n\n into the protein\n\n$protein\n\n"; 20 | 21 | exit; 22 | -------------------------------------------------------------------------------- /scripts/example8-2.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 8-2 Read a fasta file and extract the sequence data 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # Declare and initialize variables 9 | my @file_data = (); 10 | my $dna = ''; 11 | 12 | # Read in the contents of the file "sample.dna" 13 | @file_data = get_file_data("sample.dna"); 14 | 15 | # Extract the sequence data from the contents of the file "sample.dna" 16 | $dna = extract_sequence_from_fasta_data(@file_data); 17 | 18 | # Print the sequence in lines 25 characters long 19 | print_sequence( $dna, 25 ); 20 | 21 | exit; 22 | -------------------------------------------------------------------------------- /scripts/example8-3.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 8-3 Read a fasta file and extract the DNA sequence data 3 | # Translate it to protein and print it out in 25-character-long lines 4 | 5 | use strict; 6 | use warnings; 7 | use BeginPerlBioinfo; # see Chapter 6 about this module 8 | 9 | # Initialize variables 10 | my @file_data = (); 11 | my $dna = ''; 12 | my $protein = ''; 13 | 14 | # Read in the contents of the file "sample.dna" 15 | @file_data = get_file_data("sample.dna"); 16 | 17 | # Extract the sequence data from the contents of the file "sample.dna" 18 | $dna = extract_sequence_from_fasta_data(@file_data); 19 | 20 | # Translate the DNA to protein 21 | $protein = dna2peptide($dna); 22 | 23 | # Print the sequence in lines 25 characters long 24 | print_sequence( $protein, 25 ); 25 | 26 | exit; 27 | -------------------------------------------------------------------------------- /scripts/example8-4.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 8-4 Translate a DNA sequence in all six reading frames 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # Initialize variables 9 | my @file_data = (); 10 | my $dna = ''; 11 | my $revcom = ''; 12 | my $protein = ''; 13 | 14 | # Read in the contents of the file "sample.dna" 15 | @file_data = get_file_data("sample.dna"); 16 | 17 | # Extract the sequence data from the contents of the file "sample.dna" 18 | $dna = extract_sequence_from_fasta_data(@file_data); 19 | 20 | # Translate the DNA to protein in six reading frames 21 | # and print the protein in lines 70 characters long 22 | print "\n -------Reading Frame 1--------\n\n"; 23 | $protein = translate_frame( $dna, 1 ); 24 | print_sequence( $protein, 70 ); 25 | 26 | print "\n -------Reading Frame 2--------\n\n"; 27 | $protein = translate_frame( $dna, 2 ); 28 | print_sequence( $protein, 70 ); 29 | 30 | print "\n -------Reading Frame 3--------\n\n"; 31 | $protein = translate_frame( $dna, 3 ); 32 | print_sequence( $protein, 70 ); 33 | 34 | # Calculate reverse complement 35 | $revcom = revcom($dna); 36 | 37 | print "\n -------Reading Frame 4--------\n\n"; 38 | $protein = translate_frame( $revcom, 1 ); 39 | print_sequence( $protein, 70 ); 40 | 41 | print "\n -------Reading Frame 5--------\n\n"; 42 | $protein = translate_frame( $revcom, 2 ); 43 | print_sequence( $protein, 70 ); 44 | 45 | print "\n -------Reading Frame 6--------\n\n"; 46 | $protein = translate_frame( $revcom, 3 ); 47 | print_sequence( $protein, 70 ); 48 | 49 | exit; 50 | -------------------------------------------------------------------------------- /scripts/example9-1.pl: -------------------------------------------------------------------------------- 1 | # Example 9-1 Translate IUB ambiguity codes to regular expressions 2 | # IUB_to_regexp 3 | # 4 | # A subroutine that, given a sequence with IUB ambiguity codes, 5 | # outputs a translation with IUB codes changed to regular expressions 6 | # 7 | # These are the IUB ambiguity codes 8 | # (Eur. J. Biochem. 150: 1-5, 1985): 9 | # R = G or A 10 | # Y = C or T 11 | # M = A or C 12 | # K = G or T 13 | # S = G or C 14 | # W = A or T 15 | # B = not A (C or G or T) 16 | # D = not C (A or G or T) 17 | # H = not G (A or C or T) 18 | # V = not T (A or C or G) 19 | # N = A or C or G or T 20 | 21 | sub IUB_to_regexp { 22 | 23 | my ($iub) = @_; 24 | 25 | my $regular_expression = ''; 26 | 27 | my %iub2character_class = ( 28 | 29 | A => 'A', 30 | C => 'C', 31 | G => 'G', 32 | T => 'T', 33 | R => '[GA]', 34 | Y => '[CT]', 35 | M => '[AC]', 36 | K => '[GT]', 37 | S => '[GC]', 38 | W => '[AT]', 39 | B => '[CGT]', 40 | D => '[AGT]', 41 | H => '[ACT]', 42 | V => '[ACG]', 43 | N => '[ACGT]', 44 | ); 45 | 46 | # Remove the ^ signs from the recognition sites 47 | $iub =~ s/\^//g; 48 | 49 | # Translate each character in the iub sequence 50 | for ( my $i = 0 ; $i < length($iub) ; ++$i ) { 51 | $regular_expression .= $iub2character_class{ substr( $iub, $i, 1 ) }; 52 | } 53 | 54 | return $regular_expression; 55 | } 56 | -------------------------------------------------------------------------------- /scripts/example9-2.pl: -------------------------------------------------------------------------------- 1 | # Example 9-2 Subroutine to parse a REBASE datafile 2 | # parseREBASE-Parse REBASE bionet file 3 | # 4 | # A subroutine to return a hash where 5 | # key = restriction enzyme name 6 | # value = whitespace-separated recognition site and regular expression 7 | 8 | sub parseREBASE { 9 | 10 | my ($rebasefile) = @_; 11 | 12 | use strict; 13 | use warnings; 14 | use BeginPerlBioinfo; # see Chapter 6 about this module 15 | 16 | # Declare variables 17 | my @rebasefile = (); 18 | my %rebase_hash = (); 19 | my $name; 20 | my $site; 21 | my $regexp; 22 | 23 | # Read in the REBASE file 24 | my $rebase_filehandle = open_file($rebasefile); 25 | 26 | while (<$rebase_filehandle>) { 27 | 28 | # Discard header lines 29 | ( 1 .. /Rich Roberts/ ) and next; 30 | 31 | # Discard blank lines 32 | /^\s*$/ and next; 33 | 34 | # Split the two (or three if includes parenthesized name) fields 35 | my @fields = split( " ", $_ ); 36 | 37 | # Get and store the name and the recognition site 38 | 39 | # Remove parenthesized names, for simplicity's sake, 40 | # by not saving the middle field, if any, 41 | # just the first and last 42 | $name = shift @fields; 43 | 44 | $site = pop @fields; 45 | 46 | # Translate the recognition sites to regular expressions 47 | $regexp = IUB_to_regexp($site); 48 | 49 | # Store the data into the hash 50 | $rebase_hash{$name} = "$site $regexp"; 51 | } 52 | 53 | # Return the hash containing the reformatted REBASE data 54 | return %rebase_hash; 55 | } 56 | -------------------------------------------------------------------------------- /scripts/example9-3.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # Example 9-3 Make restriction map from user queries on names of restriction enzymes 3 | 4 | use strict; 5 | use warnings; 6 | use BeginPerlBioinfo; # see Chapter 6 about this module 7 | 8 | # Declare and initialize variables 9 | my %rebase_hash = (); 10 | my @file_data = (); 11 | my $query = ''; 12 | my $dna = ''; 13 | my $recognition_site = ''; 14 | my $regexp = ''; 15 | my @locations = (); 16 | 17 | # Read in the file "sample.dna" 18 | @file_data = get_file_data("sample.dna"); 19 | 20 | # Extract the DNA sequence data from the contents of the file "sample.dna" 21 | $dna = extract_sequence_from_fasta_data(@file_data); 22 | 23 | # Get the REBASE data into a hash, from file "bionet" 24 | %rebase_hash = parseREBASE('bionet'); 25 | 26 | # Prompt user for restriction enzyme names, create restriction map 27 | do { 28 | print "Search for what restriction site for (or quit)?: "; 29 | 30 | $query = ; 31 | 32 | chomp $query; 33 | 34 | # Exit if empty query 35 | if ( $query =~ /^\s*$/ ) { 36 | 37 | exit; 38 | } 39 | 40 | # Perform the search in the DNA sequence 41 | if ( exists $rebase_hash{$query} ) { 42 | 43 | ( $recognition_site, $regexp ) = split( " ", $rebase_hash{$query} ); 44 | 45 | # Create the restriction map 46 | @locations = match_positions( $regexp, $dna ); 47 | 48 | # Report the restriction map to the user 49 | if (@locations) { 50 | print "Searching for $query $recognition_site $regexp\n"; 51 | print "A restriction site for $query at locations:\n"; 52 | print join( " ", @locations ), "\n"; 53 | } 54 | else { 55 | print "A restriction enzyme $query is not in the DNA:\n"; 56 | } 57 | } 58 | print "\n"; 59 | } until ( $query =~ /quit/ ); 60 | 61 | exit; 62 | 63 | ################################################################################ 64 | # 65 | # Subroutine 66 | # 67 | # Find locations of a match of a regular expression in a string 68 | # 69 | # 70 | # return an array of positions where the regular expression 71 | # appears in the string 72 | # 73 | 74 | sub match_positions { 75 | 76 | my ( $regexp, $sequence ) = @_; 77 | 78 | use strict; 79 | 80 | use BeginPerlBioinfo; # see Chapter 6 about this module 81 | 82 | # 83 | # Declare variables 84 | # 85 | 86 | my @positions = (); 87 | 88 | # 89 | # Determine positions of regular expression matches 90 | # 91 | 92 | while ( $sequence =~ /$regexp/ig ) { 93 | 94 | push( @positions, pos($sequence) - length($&) + 1 ); 95 | } 96 | 97 | return @positions; 98 | } 99 | --------------------------------------------------------------------------------