初识perl,只为完成分句脚本的转换。因此本文具有极强的目的性,perl的很多好用功能就不研究了,主要内容围绕分句脚本展开,部分基础知识就不再赘述。
  2.背景简介:仓库是一个将自然语言处理机器翻译系统Moses的分句功能脚本从perl转为python的程序源码。
  3.perl分句脚本地址:https://github.com/moses-smt/mosesdecoder/blob/RELEASE-2.1.1/scripts/ems/support/split-sentences.perl ,在我的仓库相应路径也有该文件,应该是版本不一致,可以参考官方最新版本。
  印象里大多数脚本文件都是顺序执行,方法、变量的命名定义在不同的文件里有不同的规则。早些年的相对通用规则是,如果需要调用方法或者变量,需要再调用前对方法、变量进行定义声明。因此对于脚本文件可以先通读一遍,理出大概结构后,再进行功能研究。脚本通读之后,大致将脚本分为四个部分。1、变量的定义声明;2、参数相关处理;3、脚本的逻辑处理;4.分句实际方法。
  一、变量。perl的变量类型有三类:标量,数组和哈希
  标量变量以$开头,概念很好理解,对标其他语言的数字字符串。标量可以是个完整的网页,但是没有看到相关的例子,知道即可不必过于关注。另外单引号和双引号的使用需要注意。单引号常用于原样输出和多行文本,即在单引号中输出的是变量名而非变量值;单引号下的多行文本可以理解为所见即所得。标量中的多行文本也可以用document语法来输出,在大多数高级语言或常见脚本语言中类似的输出相对少见,不必过分关注。
  标量的运算,常见的是拼接(.)。加减乘除需要两个变量是数字才能正确计算结果,如果是数字和字符串加和,就可以发现字符串被当作0来处理,但并不会报语法错误,这点和python是不同的(python抛出类型异常)。
  数组变量以@开头,常见的定义方式直接以括号和逗号(,)来定义,也可以用qw//来定义(将元素以空格隔开写在斜杠内)。访问元素时以$[]来进行操作。注意数组的长度是数组物理大小,不是数组内的元素个数,因此在使用数组索引的时候,有可能遇到空元素。
my @array=(1,2,3);
$array[50]=4; #此时数组长度为51,但数组中只有4个元素(index:0,1,2,50)。

  数组其他的功能如添加删除元素,切割、替换数组,将字符串转为数组,将数组拼接成字符串,排序,合并,选择等操作不再解释,相关教程很详细。

  哈希变量以%开头,定义的方式有多种,常见以列表来定义(列表中的元素,第一个为key,第二个为value,以此类推)。也可以在列表中以=>的方式自行指定key=>value。对标其他语言中的字典类型便于理解。常用操作有读取、赋值,增删元素,迭代遍历等操作,不再赘述。
  二、参数。参数主要针对脚本的参数@ARGV。
  我们在调用脚本的时候,会把调用的命令行里的参数统统放到@ARGV数组里。
  在文件的开头我们指定了STDIN,STDOUT,STDERR三个标准输入/标准输出/错误信息参数的编码方式。
  三、逻辑处理
  perl既是简洁的也是冗余的,简洁在于很多语法都可以省略,省略到有其他开发经验的perl初学者一脸懵逼;冗余在于很多“理所应当”的常见操作都会有专门的关键词来处理。几乎接触过的所有编程语言的核心逻辑处理只有三类,判断、循环、跳转
  
  跳转,这个操作现在大多数语言的学习中都不推荐,甚至逐渐移除这个操作。
  
  判断,perl中总体有三种。switch case else组合。if elsif else组合。unless elsif else 组合。
  注意,数字 0, 字符串 '0' 、 "" , 空 list() , 和 undef 为 false ,其他值均为 true。 true 前面使用 ! 或 not则返回 false 。
  1.switch case else 组合。switch判断一个变量,根据变量值产生case分支,变量值可以等于某一具体值,可以在一个数组或者哈希中,比较灵活。else分支就是在无法匹配case分支时生效。
  2.if elsif else组合。根据条件,在各判断为真时,进入分支执行方法体。
  3.unless elsif else组合。根据条件,在unless判断为假、其他判断为真时,进入各分支执行方法体。说白了 unless 就是 lf not。
  
  循环,perl中多了一个until循环。其他的循环类型如 for,foreach,while,do while都是和其他语言类似的。循环中的控制语句有next,last,continue,redo,goto这五种。以下均不讨论标签块的使用,使用标签块在某种意义上是跳转,跳转时超纲范围,知道即可。
  1.until和while的用法时一样,只是当untile的判断条件为假时执行循环体,而while则是判断条件为真执行循环体体。
  2.next,将结束本次循环开始下一次循环。对标其他语言(如C#,java)中的continute。
  3.last,结束当前循环,不是结束本次循环。因为有嵌套循环的存在,一定要看清last结束的是哪个循环。对标其他语言(如C#,java)中的break。  
  4.continue,当判断条件成立执行循环体之后,执行continue后的内容。注意,如果循环体内有next,next执行之后continue也会执行。如果循环体内有last,last执行之后不执行continue。
  5.redo,直接将控制转到循环体第一行,redo之后的语句不执行。如果有continue,在redo将控制转到循环体第一行之前不执行continue。与next存在差别,请仔细区分。
 
  四、分句脚本的详解。
  前文以不涉及分句脚本的方式将用到perl基本语法简要介绍了一下。下面针对分句脚本进行学习。
  在while(@ARGV)之前,脚本先后指定了标准输入输出的编码格式,然后定义了常用的变量。如前缀数组,如语言类型等。
while (@ARGV) {
$_ = shift; #是 $_=shift(@ARGV); 的简写,将数组的第一个元素移除并赋值个特殊变量$_。$_是默认输入和模式匹配内容,特殊变量最常用的操作就是省略,这就导致了代码对于初学者不易读。
/^-l$/ && ($language = shift, next); # 也是简写,相对完整的写法如下
/^-q$/ && ($QUIET = 1, next); #循环体内其他代码也是类似的简写。
/^-h$/ && ($HELP = 1, next);
}
/^-l$/ && ($language = shift, next); 相对完整的代码如下:

if ($_m/^-l&/ ){ # 如果$_匹配成功

$language = shift(@ARGV); # 从@ARGV中再取出一个元素赋值给$language
next;                            # 结束本次循环,开始下次循环
}

while(@ARGV){}   是一个标准循环。在调用脚本的时候将参数定义为数组,传递给@ARGV。

if (!(-e $prefixfile)) {}    -e 文件名 用于判断文件是否存在。
my $text = "";
while(<STDIN>) { # 对标准输入进行循环,如果是<>,则是对文件输入进行循环
chop; # 早期版本是 chomp; 完整的代码应该是$_=<STDIN>;chop($_); 对输入内容去除最后一个字符或数组中每个元素的最后一个字符,通常用于去掉换行符。
if (/^<.+>$/ || /^\s*$/) { # 对$_进行正则匹配 ,如果是特殊变量$_,很多地方可以省略。匹配模式m,也可以省略。
#time to process this block, we've hit a blank or <p>
&do_it_for($text,$_); #当输入的内容是空行或者<p>,就开始调用方法处理已输入内容
print "<P>\n" if (/^\s*$/ && $text); ##if we have text followed by <P>
$text = "";
}
else {
#append the text, with a space
$text .= $_. " "; # . 用空格连接字符串
}
}
sub do_it_for {                        #定义方法
my($text,$markup) = @_; # @_变量用来传递变量
print &preprocess($text) if $text; # 如果$text 不为空,则调用preprocess函数。
print "$markup\n" if ($markup =~ /^<.+>$/);
#chop($text);
}
关于preprocess函数,需要深度了解正则表达式,其他的基础语法上文已经基本涵盖。
 
$text =~ s/ +/ /g;    #将多个空格替换为单个,全局模式。 s是正则中的替换模式,=~s/// eg: 变量=~s/正则表达式/替换后内容/ 是将变量按正则替换为指定表达,并赋值给变量。
$text =~ s/([?!]) +([\'\"\(\[\¿\¡\p{IsPi}]*[\p{IsUpper}])/$1\n$2/g;        # $1\n$2 是正则的分组,由于替换后将原文分为两组,对正则的解读就需要注意分组来解析。
 
关于正则的内容,经过这个脚本的学习,再不敢言说自己懂正则表达式了。再赘述两句关于正则的内容,块和分组
块的使用增加了正则对unicode的支持,使用的方法如: \p{Upper} 匹配大写字母,等效于[A-Z] 。早期的perl分句脚本中有对其他语言块的专门匹配,语言块请参考资料1的Unicode块和分类章节。 
分组,应该算是正则表达式的高级内容。以左小括号出现顺序来确定排序。如:((A)(B(C)))
分组0表示表达式自身匹配到的内容。
分组1:((A)(B(C)))
分组2:(A)
分组3:(B(C))
分组4:(C)
分组还涉及到不捕获和断言,有兴趣的自己看吧,相关资料比较多,没用多少不敢乱说。
 
 

perl的学习:将分句脚本split-sentences.perl转为python脚本的更多相关文章

  1. c#调用python脚本实现排序(适用于python脚本中不包含第三方模块的情况)

    引用:https://www.cnblogs.com/zoe-yan/p/10374757.html 利用vs2017c#调用python脚本需要安装IronPython.我是通过vs2017的工具- ...

  2. Python脚本:Linux自动化执行Python脚本

    1.环境及其工具: ubuntu 16.04 python2.7(自带) pip2.7(安装) virtualenv(安装) crontab (自带) 2.pip2.7安装 (1)尝试使用 sudo ...

  3. 查看python脚本的运行pid,让python脚本后台运行

    ps -ef | grep Productor.py | grep -v grep # 先测试好 python3  /usr/local/software/ELK/Productor.py # 没问题 ...

  4. 【原创】控制perl和python脚本执行过程中脚本文件是否关闭的方法

    引子 跟踪perl和python脚本对文件的访问,实际过程中,perl和python解析器在解析完脚本后,直接关闭了 脚本文件,在进程中查询不到是访问文件的脚本文件名称. shell.perl和pyt ...

  5. Python与Hack之window下运行带参数的Python脚本,实现一个简单的端口扫描器

    1.前提是:windows已经配置好Python的环境变量: 2.进入cmd命令行模式: **输入python命令,检测是否环境配置好:显示这样说明配置环境变量没问题 **用cd命令进入Python脚 ...

  6. 如何在命令行里运行python脚本

    python是一款应用非常广泛的脚本程序语言,谷歌公司的网页就是用python编写.python在生物信息.统计.网页制作.计算等多个领域都体现出了强大的功能.python和其他脚本语言如java.R ...

  7. C#调用Python脚本打印pdf文件

     介绍:通过pdf地址先将文件下载到本地,然后调用打印机打印,最后将下载的文件删除. 环境:windows系统.(windows64位) windows系统中安装python3.6.2环境 资料: O ...

  8. Windows运行python脚本文件

    开始学习python就是听说这个语言写脚本文件特别方便,简单使用.学了一段时间,但是直到现在我才直到直到怎么在Windows的cmd上运行脚本文件. 之前一直都是在pycharm上运行,并不实用. 百 ...

  9. spark-submit提交python脚本过程记录

    最近刚学习spark,用spark-submit命令提交一个python脚本,一开始老报错,所以打算好好整理一下用spark-submit命令提交python脚本的过程.先看一下spark-submi ...

  10. 使用sae定时执行Python脚本

    使用sae定时执行Python脚本 使用sae定时执行Python脚本 12,May,2014 | 57 Views 毕设压力略大,必须是桂林游的锅.去之前放松了几天,回来又休闲了几天,加上桂林的一周 ...

随机推荐

  1. CLISP学习(二)

    它是一门函数式语言,你要用函数的思维来思考. 只不过与数学的表达不同的是,数学里的函数是在括号外  f(x) ,而lisp是在括号内,以列表的形式(f x), cos(x) --> (cos x ...

  2. python进阶之路14 之函数内置方法、可迭代对象、异常捕获处理

    重要内置函数 1.map() 映射 l1 = [1, 2, 3, 4, 5] # def func(a): # return a+1 res = map(lambda x:x+1, l1) print ...

  3. 从最简单的线性DP开始

    导读 ^ _ ^ 线性DP可以说是最常见的DP问题. 从本期开始,我们将从最简单的线性DP开始学起. 后面同时更新一些经典的面试题带大家更加深入的学习线性DP 如何计算动态规划的时间复杂度? 状态数 ...

  4. Java反射获取方法参数名 IDEA配置 Maven

    默认情况下无法获得具体的参数名,只能得到arg0, arg1等. 进行如下配置即可通过反射获得具体的参数名. -parameters 如果是Maven项目,还需要在pom.xml文件中增加如下配置 & ...

  5. win32com操作word 第三集:Range精讲(一)

    本课程<win32com操作word API精讲&项目实战>,本公众号以文字分享为主,B站与视频号则发布视频分享,ID均为:一灯编程 本集开始,将会深入Document接口.打开或 ...

  6. 问题记录:VMware vSphere vCenter 7.0 上传文件失败

    问题记录:VMware vSphere vCenter 7.0 上传文件失败 环境说明: VC版本:VMware vSphere vCenter 7.0 ESXi版本:VMware vSphere E ...

  7. 3DText无法被物体遮挡 - 解决

    目录 开篇: 问题复现: 如何解决: 1.创建一个Shader 2.创建一个Material 3.给Material赋值字体 4.给3DText属性赋值 5.查看效果 希望大家:点赞,留言,关注咯~ ...

  8. Linux服务器硬件及RAID配置

    Linux服务器硬件及RAID配置 一.RAID磁盘阵列介绍 独立冗余磁盘阵列(Redundant Array of Independent Disks) 作用: 把多块独立的物理硬盘按不同的方式组合 ...

  9. 一文看懂 Python 中的函数参数

    函数定义中的参数也就是形式参数,规定了在调用函数时如何传递实际参数以及这些参数有无默认值. 实参传递方式 def f(a): print(a) 实参传递方式有两种,位置和关键字.对于上面定义的函数 f ...

  10. 真正“搞”懂HTTPS协议17之TLS握手

    经过前两章的学习,我们知道了通信安全的定义以及TLS对其的实现~有了这些知识作为基础,我们现在可以正式的开始研究HTTPS和TLS协议了.嗯--现在才真正开始. 我记得之前大概聊过,当你在浏览器的地址 ...