问号表达式

更新时间:2023-03-04 13:25:07 阅读: 评论:0

翡翠好坏怎么鉴别-win10怎么设置开机密码

问号表达式
2023年3月4日发(作者:滑板车儿童)

《⾃然语⾔处理技术综述(第三版)》(1)----正则表达式

写在前⾯:

由于⽬前原作者还没有开放第⼀章,我将从第⼆章开始介绍给⼤家。因业务和翻译⽔平有限,⼒求⼤家明⽩,不当之处请⼤家多多包

涵,并不吝赐教。同时,本⽂均为我⼀字⼀字敲写,如有与其他⼈雷同,纯属巧合。

第⼆章正则表达式、⽂本归⼀化和编辑距离

上⾯的对话来⾃⼀个早期的⾃然语⾔处理系统——ELIZA,,它可以模仿罗杰尼亚⼼理治疗者的反应,与⽤户进⾏有限的交谈

(WeieNebAUM,1966)。ELIZA程序的简单程度令⼈吃惊,它使⽤模式匹配来识别“你是X”之类的短语,并将它们转换成合适的输

出,⽐如“什么让你认为我是X?”。这个简单的技术在这个领域成功了,因为ELIZA实际上不需要知道任何东西就可以模仿⼼理医⽣。正

如Weizenbaum所指出的,这是少数⼏个听众对其表现毫⽆察觉的对话类型。ELIZA对⼈类对话的模仿是⾮常成功的:许多与ELIZA互动的

⼈开始相信它真的理解他们和他们的问题。即使把程序的操作原理解释给他们之后(WeieNebAUM,1976),许多⼈还继续相信ELIZA

的能⼒。即使在今天,这种聊天机器⼈也是⼀种有趣的娱乐⽅式。

当然,现代会话系统不仅仅是⼀种转换,他们可以回答问题、预订航班或找餐馆,这些功能依赖于对⽤户意图更为复杂的理解。这些

内容在第29章中我们会将介绍到。尽管如此,基于ELIZA和其他聊天机器⼈的简单的基于模式的⽅法在⾃然语⾔处理中起着⾄关重要的作

⽤。

本章节,我们将从描述⽂本模式的最重要⼯具开始:正则表达式。正则表达式可以⽤来指定我们希望从⽂档中提取的字符串;可以从

上⾯的ELIZA中转换为“您是X”;可以来定义从⽂档中提取价格表的字符串,⽐如$199或$24.99。

然后,我们将转向⼀组称为⽂本归⼀化的任务,其中正则表达式起着重要的作⽤。归⼀化⽂本意味着将它转换成更⽅便、更标准的形

式。例如,分词的任务,我们将要处理的⼤部分语⾔依赖于先从⽂本中分离或标记单词。英语单词通常是⽤空格分隔的,但空格并不总是充

分的。NewYork和rock’n’roll有时被视为⼀个⼤词,尽管它们含有空格。⽽有时我们需要将I’m分为两个词I和am。为了处理

tweets博⽂或⽂本,我们需要标记出:)这样的表情或标记出#nlproc这样的标签。有些语⾔,⽐如汉语,在单词之间没有空格,所以单

词标记法更加困难。

⽂本归⼀化的另⼀部分是词形还原,任务是确定两个词具有相同的词根,但它们的⽂字表⾯是有差异。例如,sang,sung,和sings

这三个词是动词sing的形。sing这个词是这些词的词根,词形还原器将这些词映射为sing。词形还原是处理形态复杂的语⾔必不可少的,

如阿拉伯语。词⼲抽取是指⼀个简单的词形还原版本,主要是从词尾中除去后缀。⽂本规范化还包括句⼦划分:使⽤标点符号如句号或感叹

号,将⽂本分解成单个句⼦。

最后,我们需要⽐较单词和其他字符串相似度的⼯具。我们将引⼊⼀个称为编辑距离的算法,这个算法可以度量两个字符串是如何根

据编辑(插⼊、删除、替换)的数量来改变⼀个字符串到另⼀个字符串的。编辑距离算法的应⽤贯穿整个语⾔处理过程,从拼写校正、语⾳

识别到指代消解都有应⽤。

2.1正则表达式

正则表达式(RE)是计算机科学标准化的成就之⼀,它是⼀种⽤于指定⽂本搜索字符串的语⾔。这种实⽤语⾔在每种计算机语⾔、

⽂字处理器和⽂本处理⼯具中都有使⽤,如UNIX⼯具grep或Emacs。形式上,正则表达式是⽤于表征⼀组字符串的代数表⽰法。它们在进

⾏⽂本检索时特别有⽤。当我们有⼀个搜索模板和⼀个⽂本语料库来进⾏搜索时,正则表达式搜索整个语料库,返回与模板匹配的所有⽂

本。语料库可以是单个⽂档或集合。例如,UNIX命令⾏⼯具grep就是使⽤正则表达式,返回输⼊⽂档中与表达式匹配的每⼀⾏。

如果匹配结果不⽌⼀个,搜索可以设计为返回每⼀⾏或者只返回第⼀个匹配。在下⾯的⽰例中,我们着重介绍正则表达式匹配的每⼀

部分,并仅显⽰第⼀个匹配。我们将⽤两个斜杠来表达正则表达式的起始。但注意,斜杠不是正则表达式的⼀部分。

2.1.1基本正则表达式模板

最简单的正则表达式是⼀系列简单字符。例如,使⽤模板/woodchuck/来查找woodchuck。使⽤表达式/Buttercup/匹配包含⼦字

符串Buttercup的任何字符串,使⽤这个表达式,grep将返回I’mcalledlittleButtercup。搜索字符串可以由单个字符组成(类似/!/)

或⼀系列字符(如/url/)。

图2.1⼀些简单的正则表达式搜索

正则表达式是区分⼤⼩写的;⼩写/s/与⼤写/S/是不同的(/s/匹配⼩写s⽽不是⼤写字母S)。这意味着模板/woodchucks/将不

匹配字符串Woodchucks。我们可以⽤⽅括号[]来解决这个问题。括号内的字符串指定要匹配的字符的分离。例如,图2.2表⽰模

式/[WW]/匹配包含w或W的模式。

图2.2使⽤⽅括号[]表⽰⼀个字符串的分离

虽然这些数字或字母类是表达式中的重要组成部分,但⽤正则表达式/[1234567890]/指定任⼀数字,

[ABCDFIGHYKLMNOPQRSTUVWXYZ]表⽰任⼀⼤写字母,就显得很笨拙。括号可以与短横线(-)⼀起使⽤,来指定⼀个字符范围。模

板/[2-5]/指定字符2,3,4或5中的任何⼀个。模板/[b-g]指定字符b、c、d、e、f或g中的⼀个。图2.3中⽰出了⼀些其他⽰例。

图2.3⽅括号[]与-⼀起指定字符范围

否定操作符:⽅括号中第⼀个符号使⽤插⼊符^,可以⽤来表⽰不包含某单个字符。例如,模式/[^a]/表⽰除了a之外的任何单个字

符(包括特殊字符)都匹配。如果^出现在其他地⽅,它仅表⽰⼀个插⼊符号。图2.4显⽰了⼀些例⼦。

图2.4^表⽰否定以及仅仅表⽰⼀个字符

接下来我们讨论可选操作符,如果想表达查找woodchuck和woodchucks,其中s是可选元素如何做?简单的使⽤中括号是不⾏

的,因为⽬前只有这种形式[sS],但它仅表⽰“s”或“S”,⽆法表达有或者没有s的意思。在这种情况下,引⼊问号操作符/?/,他表

⽰“前⾯的字符出现或不出现”,如图2.5所⽰。

图2.5问号?操作符表⽰前⾯的表达式是可选的

我们可以把问号看作“问号前的字符出现0或⼀次”。也就是说,它是⼀种指定我们想要多少个的⽅法,在正则表达式中是⾮常重要

的。但如何表达更多次出现呢?例如,考虑某些“⽺语”,它由如下的字符串组成:

baa!

baaa!

baaaa!

baaaaa!

...

这种语⾔以⼀个b开头,后⾯⾄少有两个a,结尾是感叹号。这时,我们引⼊星号*操作符来表⽰“⼀些a”,通常叫克林*。克林*表

⽰“星号前⾯的字符或正则表达式出现的零或多次”。/a*/意味着“0或多个a”。它可以匹配a或aaaa,也可以匹配OffMinor,因为字符

串OffMinor有0个a。因此,匹配⼀个或多个a的正则表达式是/aa*/,即⼀个a后⾯跟着0或多个a。*不仅可以重复单个字符还可以重复模

板。所以/[ab]*/意味着“零或更多的a或a”(⽽不是“零或更多的右⽅括号”)。他可以匹配像aaaa或ababab或bbbb的字符串。

对于查找价格等多个数字符的情况,我们可以扩展/[0-9]/为⼀个整数的正则表达式/[0-9][0~9]*/。(⼤家可以想⼀下为什么

不只是/[0-9]*/?)

上⾯这种为数字写两次正则表达式的⽅法很啰嗦。因此有⼀种较短的⽅式来指定某个字符的“⾄少⼀个”。这就是克林+,意思

是“前⼀个字符或表达式出现⼀次或多次”。因此,/[0-9]+/是指定“数字序列”的标准⽅式。此时,我们有两种⽅法来指定⽺语

⾔:/baaa*!/或者/baa+!/。

⼀个⾮常重要的特殊字符是通配符(/./),可以与任何单个字符(除了回车符)匹配的通配符表达式,如图2.6所⽰。

图2.6使⽤通配符.来表⽰任何单⼀字符

通配符经常与星号⼀起使⽤表⽰“任何字符串”。例如,我们想找aardvark出现两次的句⼦。我们可以⽤正则表达

式/aardvark.*aardvark/。

锚点是将正则表达式锚定到字符串中特定位置的特殊字符。最常见的锚点是插⼊符号^和美元符号$。插⼊符号匹配⼀⾏的开头。模

板/^The/⽤于匹配以The开头的⾏。因此,插⼊符号有三种⽤法:1)匹配⼀⾏的开头;2)在正⽅括号内表⽰⼀个否定;3)表⽰插⼊符号

本⾝。⼤家此时可以思考⼀下grep或python在什么情况下能够判断插⼊符起的作⽤?。美元符号$匹配⼀⾏的结尾。因此,模板␣$是⽤于

匹配⾏末是空格的句⼦。/^Thedog.$/匹配只包含Thedog.的⼀⾏。(我们必须使⽤反斜杠,因为我们想要句号⽽不是通配符。)

这⾥还有另外两个锚:b匹配⼀个单词边界,B匹配⼀个⾮边界。因此,/btheb/匹配单词the⽽不是单词other。从技术上讲,

⽤于正则表达式检索的⽬标“单词”定义:任何序列的数字、下划线或字母;这是基于编程语⾔中“单词”的定义。例如,/b99b/将匹

配字符串99,Thereare99bottlesofbeeronthewall(因为99跟随在⼀个空格后⾯)。但下⾯的句⼦,Thereare299bottlesof

beeronthewall这种情况下99不是⼀个词(因为99跟在⼀个数字后⾯)。有⼀些例外,如,这个模板可以匹配$99中的99(因为99紧跟

在美元符号($)后⾯,可是$不是⼀个数字,下划线,或字母)。

2.1.2分离,分组和优先级

假设我们需要搜索关于宠物的⽂字,也许我们对猫狗特别感兴趣。在这种情况下,我们可能要搜索字符串cat或字符串dog。因为我们

不能⽤⽅括号来搜索“cat或dog”(为什么我们不能⽤[catdog]?)我们需要⼀个新的操作符,即分离操作符,也称为管符号。模

板/cat|dog/可以匹配cat或dog。

有时我们需要在更⼤的范围内使⽤这个分离操作符。例如,假设我想为我的表弟戴维搜索宠物鱼的信息。我怎么能指定guppy和

guppies?显然我们不能简单地说/guppy|ies/,因为这将只匹配字符串guppy和ies。这是因为guppy这种字符串的优先级要⽐分离操作符

的优先级⾼。为了使分离操作符应⽤在这种特定的场景,我们需要使⽤括号操作符(和)。⽤圆括号将|或*操作符括起来,让他们看上去像

⼀个独⽴的字符。因此,模板/gupp(y|ies)/可以实现我们想要分离后缀y和ies的意图。

上⾯提到了,圆括号操作符可以⽤在*操作符上。和|不同的是,*操作符只能作⽤与⼀个独⽴的字符上,⽽不是⼀个字符串上。假设我

们希望匹配字符串的重复实例,例如我们有⼀个包括多栏⽬标题(Colunmn1,Column2,Column3)的⼀⾏。如果我们使⽤表达

式/Column␣[0-9]+␣*/将匹配不到所有栏⽬标题;相反,它仅能匹配到⼀个栏⽬标题,这个标题后⾯跟着任意数量的空格;这是因为*操作

符只作⽤于它前⾯的␣,⽽不是整个序列。我们可以⽤括号写表达式/(Column␣[0-9]+␣*)*/来匹配单词Column,其后跟着⼀个数字和任

意个␣,整个模板重复任意次数。

⼀个操作符可以优先于另⼀个操作符,有时我们还会使⽤括号来凸显我们的意思,这就形成了正则表达式的运算符优先级层次。下表

给出了RE运算符从最⾼优先级到最低优先级的顺序。

因此,由于*操作符具有⽐序列⾼的优先级,/the*/匹配theeee,⽽不是匹配thethe。由于序列⽐分离具有更⾼的优先

级,/the|any/匹配the或者any,但不匹配theny。

模板的应⽤还有另⼀个暗含规则。例如表达式/[a-z]*/在与⽂本onceuponatime匹配的时候。因为/[a-z]*/匹配零个或多个字

母,这个表达式可以匹配任何东西,或者o、on、onc或once。在这种情况下,正则表达式总是匹配最⼤的字符串;我们称这是模板的贪婪

性,覆盖尽可能多的字符串。

然⽽,有⼀些⽅法来执⾏“⾮贪婪”匹配,这就⽤到了限定符?。例如*?表⽰*操作符匹配尽量少的⽂本。+?表⽰+操作符匹配尽可

能少的⽂本。

2.1.3⼀个简单的例⼦

假设我们想写⼀个RE来查找英⽂⽂章中the的例⼦。⼀个简单的模板可能是:

/the/

有⼀个问题是,这种模板会漏掉以⼤写T开始的字符串(⽐如The)。我们将模板进⾏以下改进:

/[tT]he/

但是我们仍然会错误地检索到包含这个the这三个字母的词(例如,other或theology)。因此,我们需要指定两边都有单词边界:

/b[tT]heb/

有时,我们可能想在⼀些上下⽂中找到后⾯跟着下划线或数字的the(the_或the25)。由于/b/不会把下划线和数字当作单词边

界,这时我们不想使⽤/b/。我们需要指定,the的两侧没有字母:

/[ˆa-zA-Z][tT]he[ˆa-zA-Z]/

但是这个模式有⼀个问题:当the位于⼀⾏的开始时,就匹配不到了。这是因为我们为了避免包含the的词被搜索到⽽引⼊了^操作

符,^操作符意味着the前⾯必须有⼀个单独的(虽然⾮字母)字符。为了解决这个问题,我们可以通过指定要么是⾏的开始,要么是⾮字母

的字符开始。在末尾也是同样的处理⽅式来避免这⼀点:

/(ˆ|[ˆa-zA-Z])[tT]he([ˆa-zA-Z]|$)/

我们刚刚经历的过程是基于修复两种错误:1)假阳性,我们错误地匹配到了不想要的结果,如other或there。2)假阴性,我们没

有匹配到想要的字符串,如The。在实现语⾳和语⾔处理系统中,经常需要解决这两类错误。因此,减少应⽤程序的整体错误率,应在以下

两⽅⾯努⼒:

提⾼精确度(尽量减少假阳性)

增加召回(最⼩化假阴性)

2.1.4⼀个更复杂的例⼦

这⼀节,我们尝试⼀个更加典型的例⼦,以彰显RE的能⼒。假设我们想构建⼀个应⽤程序来帮助⽤户在⽹络上购买⼀台计算机。⽤

户可能希望“任何超过6GHz和500GB的磁盘空间⼩于1000美元的机器”。要做到这种检索,我们⾸先需要能够寻找像6GHz或500

GB或$999.99的表达式。在本节,我们将为这个任务设计⼀些简单的正则表达式。

⾸先,让我们完成价格的正则表达式。下⾯是⼀个美元符号的规则表达式,后⾯是⼀个数字串:

/$[0-9]+/

注意,$字符在这⾥不是前⾯讨论的⾏结束的功能。正则表达式分析器实际上是⾜够聪明的,知道这⾥的$并不意味着结束。(这⾥

留⼀个作业,请思考正则表达式分析器如何从上下⽂中计算出$的功能。)

现在我们在整数美元后⾯添加⼀个⼩数点和两个数字:

/$[0-9]+.[0-9][0-9]/

这种模式只允许$199.99,但不匹配“$199.”。我们需要变为美分可选的,并且确保我们处于单词边界:

/b$[0-9]+(.[0-9][0-9])?b/

接下来,看⼀下电脑选型时处理器速度的规格如何检索?这⾥有⼀个模板:

/b[0-9]+␣*(GHz|[Gg]igahertz)b/

请注意,我们使⽤/␣*/意味着“零或更多的␣”,是因为这⾥可能出现多个空格。还需要⽀持可选的⼩数(如5.5GB);注意在s后

使⽤了?,以表达s是可选的:

/b[0-9]+(.[0-9]+)?␣*(GB|[Gg]igabytes?)b/

2.1.5更多操作符

图2.7显⽰了常⽤范围的别名,主要⽤于保存类型。除了*和+之外,我们还可以使⽤显式数字作为计数器,将它们括在⼤括号中。正

则表达式/{3}/意味着“前3个字符或表达式要确切出现3次”。那么,/a.{24}z/将匹配⼀个字母a,后⾯有24个点,再后⾯是字母

z(但不是a后⾯跟23个或25个点,然后后⾯是Z)。

图2.7常⽤字符集别名

⼤括号也可以指定⼀个数字区间。例如/{n,m}/指定从前⼀个字符或表达式的n到m出现;/{n,}/意味着前⾯的表达式⾄少出现n

次。可计数的RE总结在图2.8中。

图2.8⽤于计数的正则表达式运算符。

最后,某些字符通过使⽤反斜杠转义后表达特殊含义,⽐如n表⽰另起⼀⾏,t表⽰tab。另外,特殊字符在表达字符原本含义时需

要反斜杠()进⾏转义。例如,*[在表达这些符号本⾝含义时,需要使⽤/./,/*/,/[/,/。(参见图2.9)。

图2.9需要反斜杠的字符

2.1.6正则表达式替换、捕获组和ELIZA

正则表达式的⼀个重要⽤途是替换。例如,在Python和Unix命令(如vim或d)中通过使⽤s/regexp1/pattern/的正则表达式,

来完成⼀个字符串替换另⼀个字符串的功能,例如

s/colour/color/

在实际应⽤中,我们还经常⽤到,将匹配到的字符串变形后⽤于替换。这⾥有⼀个任务,假如我们想将⽂本中所有的数字前后加上尖

括号<>,如将the35boxes改为the<35>boxes。我们想⽤⼀种⽅法来引⽤我们找到的整数,这样我们就可以很容易地添加括号。要做到

这⼀点,我们使⽤圆括号()将第⼀个模板括起来,并在第⼆个模式中使⽤数字运算符1来回溯。这就是它的样⼦:

s/([0-9]+)/<1>/

括号和数字运算符还可以指定某个字符串或表达式必须在⽂本中出现两次。例如,假设我们要检索“theXertheywere,theXer

theywillbe”这种句⼦,约定两个X代表形同的字符串。我们可以这样做:⽤括号运算符将第⼀个X括起来,然后⽤数字运算符1替换第⼆

个X,如下:

/the(.*)ertheywere,the1ertheywillbe/

在这⾥,1将被替换为第⼀个匹配项匹配的任何字符串。使⽤这个模板可以匹配Thebiggertheywere,thebiggertheywillbe,

但匹配不到Thebiggertheywere,thefastertheywillbe。

使⽤圆括号将模式存储在内存中称为捕获组。每次使⽤捕获组(即圆括号包围模板)时,捕获组中的模板匹配到的结果将存储在⼀个

数字编号寄存器中,通过“数字”提取出来。如果有两个捕获组,那么2代表第⼆个捕获组匹配到的内容。因此/the(.*)erthey(.*),the

1erwe2/将匹配到Thefastertheyran,thefasterweran,但不能匹配Thefastertheyran,thefasterweate。同样,第三捕获

组存储在3,第四个是4,等等。

因此,括号在正则表达式中具有双重功能;它们⽤于分组或优先级,即指定操作符的顺序,另⼀个作⽤是,使⽤寄存器捕获某些东

西。有时我们可能希望使⽤圆括号⽤于进⾏分组,但不想使⽤捕获组的模式。在这种情况下,我们使⽤⾮捕获组,形式是在左圆括号后⾯加

上?:即(?:模板)。例如

/(?:some|afew)(people|cats)likesome1/

将匹配到somecatslikesomepeople,但匹配不到somepeoplelikesomeafew。

替换和捕获组在实现简单的聊天机器⼈(如ELIZA)中⾮常有⽤。回忆ELIZA模拟罗杰斯⼼理学家进⾏的以下对话:

ELIZA是通过⼀系列或级联的正则表达式替换来⼯作的,每个正则表达式替换和改变输⼊⾏的某些部分。⾸先是将my替换为

YOUR,将I’m替换为YOUARE。然后替换输⼊中匹配到的内容。下⾯是⼀些例⼦:

由于多个替换都可以应⽤于给定的输⼊,那么替换被赋予⼀个秩并按顺序应⽤。更多关于创建模板的题⽬请查看练习2.3。我们将在

第29章中详细说明ELIZA体系结构的细节。

2.1.7预测断⾔

最后,我们介绍⼀下预测断⾔:在⽂本中只检查是否匹配,但不移动匹配游标。

预测断⾔使⽤了(?语法,类似的语法我们在⾮捕获组的定义中看到过。操作符(?=pattern),表⽰如果模板能匹配上则该断⾔返

回true,但为零宽度,即匹配指针不前进。操作符(?!pattern)只有在不匹配时返回true,但同样是零宽度,不前进光标。在⼀些复杂的模

板中,要排除⼀个特殊的情况时,通常使⽤否定的断⾔。例如,假设我们查找⼀个开头单词不是“Volcano”的句⼦。我们可以⽤否定的

预测断⾔来做到这⼀点:

/(ˆ?!Volcano)[A-Za-z]+/

本文发布于:2023-03-04 13:25:07,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/zhishi/a/167790750710518.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:问号表达式.doc

本文 PDF 下载地址:问号表达式.pdf

下一篇:返回列表
标签:问号表达式
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 实用文体写作网旗下知识大全大全栏目是一个全百科类宝库! 优秀范文|法律文书|专利查询|