写在前面:

学习和应用NLP有几年了,在工程应用上也小有成果,除了开发了智能客服、智能营销、智能回访、保险智能机器人系统外,正在做一个开放平台,希望不久能为更多企业、个人所使用。在这个过程中积累了很多算法改进、应用架构、工程实施以及产品优化方面的经验,希望能尽可能的分享给大家。这个专栏里,我将翻译《Speech and Language Processing(第三版)》(目前还是草案)。希望能给大家带来最新的内容,为大家提供一个系统学习NLP的基础内容。英文原文在这里http://web.stanford.edu/~jurafsky/slp3/,如有喜欢请大家自行下载。

由于目前原作者还没有开放第一章,我将从第二章开始介绍给大家。因业务和翻译水平有限,力求大家明白,不当之处请大家多多包涵,并不吝赐教。同时,本文均为我一字一字敲写,如有与其他人雷同,纯属巧合。

第二章 正则表达式、文本归一化和编辑距离

上面的对话来自一个早期的自然语言处理系统——ELIZA,,它可以模仿罗杰尼亚心理治疗者的反应,与用户进行有限的交谈(WeieNebAUM,1966)。ELIZA程序的简单程度令人吃惊,它使用模式匹配来识别“你是X”之类的短语,并将它们转换成合适的输出,比如“什么让你认为我是X?”。这个简单的技术在这个领域成功了,因为ELIZA实际上不需要知道任何东西就可以模仿心理医生。正如Weizenbaum所指出的,这是少数几个听众对其表现毫无察觉的对话类型。ELIZA对人类对话的模仿是非常成功的:许多与ELIZA互动的人开始相信它真的理解他们和他们的问题。即使把程序的操作原理解释给他们之后(WeieNebAUM,1976),许多人还继续相信ELIZA的能力。即使在今天,这种聊天机器人也是一种有趣的娱乐方式。

当然,现代会话系统不仅仅是一种转换,他们可以回答问题、预订航班或找餐馆,这些功能依赖于对用户意图更为复杂的理解。这些内容在第29章中我们会将介绍到。尽管如此,基于ELIZA和其他聊天机器人的简单的基于模式的方法在自然语言处理中起着至关重要的作用。

本章节,我们将从描述文本模式的最重要工具开始:正则表达式。正则表达式可以用来指定我们希望从文档中提取的字符串;可以从上面的ELIZA中转换为“您是X”;可以来定义从文档中提取价格表的字符串,比如$199或$24.99。

然后,我们将转向一组称为文本归一化的任务,其中正则表达式起着重要的作用。归一化文本意味着将它转换成更方便、更标准的形式。例如,分词的任务,我们将要处理的大部分语言依赖于先从文本中分离或标记单词。英语单词通常是用空格分隔的,但空格并不总是充分的。New Yorkrock ’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’m called little Buttercup。搜索字符串可以由单个字符组成(类似/!/)或一系列字符(如/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 ^表示否定以及仅仅表示一个字符

接下来我们讨论可选操作符,如果想表达查找woodchuckwoodchucks,其中s是可选元素如何做?简单的使用中括号是不行的,因为目前只有这种形式[sS],但它仅表示“s”或“S”,无法表达有或者没有s的意思。在这种情况下,引入问号操作符/?/,他表示“前面的字符出现或不出现”,如图2.5所示。

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

我们可以把问号看作“问号前的字符出现0或一次”。也就是说,它是一种指定我们想要多少个的方法,在正则表达式中是非常重要的。但如何表达更多次出现呢?例如,考虑某些“羊语”,它由如下的字符串组成:

baa!

baaa!

baaaa!

baaaaa!

...

这种语言以一个b开头,后面至少有两个a,结尾是感叹号。这时,我们引入星号*操作符来表示“一些a”,通常叫克林*。克林*表示“星号前面的字符或正则表达式出现的零或多次”。/a*/意味着“0或多个a”。它可以匹配a或aaaa,也可以匹配Off Minor,因为字符串Off Minor有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在什么情况下能够判断插入符起的作用?。美元符号$匹配一行的结尾。因此,模板␣$是用于匹配行末是空格的句子。/^The dog\.$/匹配只包含The dog.的一行。(我们必须使用反斜杠,因为我们想要句号而不是通配符。)

这里还有另外两个锚:\b匹配一个单词边界,\B匹配一个非边界。因此,/\bthe\b/匹配单词the而不是单词other。从技术上讲,用于正则表达式检索的目标“单词”定义:任何序列的数字、下划线或字母;这是基于编程语言中“单词”的定义。例如,/\b99 \b/将匹配字符串99,There are 99 bottles of beer on the wall(因为99跟随在一个空格后面)。但下面的句子,There are 299 bottles of beer on the wall这种情况下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的意图。

上面提到了,圆括号操作符可以用在*操作符上。和|不同的是,*操作符只能作用与一个独立的字符上,而不是一个字符串上。假设我们希望匹配字符串的重复实例,例如我们有一个包括多栏目标题(Colunmn 1,Column 2,Column 3)的一行。如果我们使用表达式/Column␣[0-9]+␣*/将匹配不到所有栏目标题;相反,它仅能匹配到一个栏目标题,这个标题后面跟着任意数量的空格;这是因为*操作符只作用于它前面的␣,而不是整个序列。我们可以用括号写表达式/(Column␣[0-9]+␣*)*/ 来匹配单词Column,其后跟着一个数字和任意个␣,整个模板重复任意次数。

一个操作符可以优先于另一个操作符,有时我们还会使用括号来凸显我们的意思,这就形成了正则表达式的运算符优先级层次。下表给出了RE运算符从最高优先级到最低优先级的顺序。

因此,由于*操作符具有比序列高的优先级,/the*/匹配theeee,而不是匹配thethe。由于序列比分离具有更高的优先级,/the|any/匹配the或者any,但不匹配theny。

模板的应用还有另一个暗含规则。例如表达式/ [a-z]*/在与文本once upon a time匹配的时候。因为/[a-z] */匹配零个或多个字母,这个表达式可以匹配任何东西,或者o、on、onc或once。在这种情况下,正则表达式总是匹配最大的字符串;我们称这是模板的贪婪性,覆盖尽可能多的字符串。

然而,有一些方法来执行“非贪婪”匹配,这就用到了限定符?。例如*?表示*操作符匹配尽量少的文本。+?表示+操作符匹配尽可能少的文本。

2.1.3 一个简单的例子

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

/the/

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

/[tT]he/

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

/\b[tT]he\b/

有时,我们可能想在一些上下文中找到后面跟着下划线或数字的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的能力。假设我们想构建一个应用程序来帮助用户在网络上购买一台计算机。用户可能希望“任何超过6 GHz和500 GB的磁盘空间小于1000美元的机器”。要做到这种检索,我们首先需要能够寻找像6 GHz或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.5 GB);注意在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或sed)中通过使用s/regexp1/pattern/的正则表达式,来完成一个字符串替换另一个字符串的功能,例如

s/colour/color/

在实际应用中,我们还经常用到,将匹配到的字符串变形后用于替换。这里有一个任务,假如我们想将文本中所有的数字前后加上尖括号<>,如将the 35 boxes改为the <35> boxes。我们想用一种方法来引用我们找到的整数,这样我们就可以很容易地添加括号。要做到这一点,我们使用圆括号()将第一个模板括起来,并在第二个模式中使用数字运算符1来回溯。这就是它的样子:

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

括号和数字运算符还可以指定某个字符串或表达式必须在文本中出现两次。例如,假设我们要检索“the Xer they were, the Xer they will be ”这种句子,约定两个X代表形同的字符串。我们可以这样做:用括号运算符将第一个X括起来,然后用数字运算符1替换第二个X,如下:

/the (.*)er they were, the \1er they will be/

在这里,\1将被替换为第一个匹配项匹配的任何字符串。使用这个模板可以匹配The bigger they were, the bigger they will be ,但匹配不到The bigger they were, the faster they will be

使用圆括号将模式存储在内存中称为捕获组。每次使用捕获组(即圆括号包围模板)时,捕获组中的模板匹配到的结果将存储在一个数字编号寄存器中,通过“\数字”提取出来。如果有两个捕获组,那么\2代表第二个捕获组匹配到的内容。因此 /the (.*)er they (.*), the \1er we \2/ 将匹配到The faster they ran, the faster we ran,但不能匹配 The faster they ran, the faster we ate。同样,第三捕获组存储在\3,第四个是\4,等等。

因此,括号在正则表达式中具有双重功能;它们用于分组或优先级,即指定操作符的顺序,另一个作用是,使用寄存器捕获某些东西。有时我们可能希望使用圆括号用于进行分组,但不想使用捕获组的模式。在这种情况下,我们使用非捕获组,形式是在左圆括号后面加上?:即(?:模板)。例如

/(?:some|a few) (people|cats) like some \1/

将匹配到some cats like some people ,但匹配不到 some people like some a few

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

ELIZA是通过一系列或级联的正则表达式替换来工作的,每个正则表达式替换和改变输入行的某些部分。首先是将my替换为YOUR,将I’m替换为YOU ARE。然后替换输入中匹配到的内容。下面是一些例子:

由于多个替换都可以应用于给定的输入,那么替换被赋予一个秩并按顺序应用。更多关于创建模板的题目请查看练习2.3。我们将在第29章中详细说明ELIZA体系结构的细节。

2.1.7 预测断言

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

预测断言使用了(?语法,类似的语法我们在非捕获组的定义中看到过。操作符(?= pattern) ,表示如果模板能匹配上则该断言返回true,但为零宽度,即匹配指针不前进。操作符(?! pattern) 只有在不匹配时返回true,但同样是零宽度,不前进光标。在一些复杂的模板中,要排除一个特殊的情况时,通常使用否定的断言。例如,假设我们查找一个开头单词不是“Volcano ”的句子。我们可以用否定的预测断言来做到这一点:

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

《自然语言处理技术综述(第三版)》(1)----正则表达式相关推荐

  1. 服务器技术综述(三)

    服务器技术综述(三)

  2. 读《数据挖掘技术(第三版)》-应用于市场营销,销售与客户关系管理 有感

    读<数据挖掘技术(第三版)>-应用于市场营销,销售与客户关系管理 有感 这本书不是纯讲数据挖掘理论的书,从本书的副标题你大概也能猜得到.对于像我这样数据挖掘领域的门外汉,读起这本书也没有多 ...

  3. 《自然语言处理技术综述(第三版)》(2)----分词和归一化

    写在前面: 学习和应用NLP有几年了,在工程应用上也小有成果,除了开发了智能客服.智能营销.智能回访.保险智能机器人系统外,正在做一个开放平台,希望不久能为更多企业.个人所使用.在这个过程中积累了很多 ...

  4. MFC与Matlab编程总结 (以《Matlab与C/C++混合编程技术(第三版)》-刘维 第五章 生成DLL为例)

    近期要完成一个任务,把人脸超分辨率的算法集成在一个系统中,嵌入人脸库及字典集等.老板的要求是有比较好的界面,目前也只能是VS那一套了,前一段时间完成的项目是用的MFC,这次也就是用MFC来完成吧.但是 ...

  5. 数字电子技术基础第三版杨志忠_阎石数字电子技术基础第6版笔记和课后习题详解...

    阎石<数字电子技术基础>(第6版)笔记和课后习题(含考研真题)详解 第1章 数制和码制 1.1 复习笔记 本章作为<数字电子技术基础>的开篇章节,是数字电路学习的基础.本章介绍 ...

  6. 正则表达式 数字和小数点_《自然语言处理综论》第三版笔记(二)之正则表达式,文本标准化和编辑距离...

    概要 早期有一种叫ELIZA的自然语言处理系统能够与用户进行有限的对话交流.它的原理是通过模式匹配来识别词组,譬如"YOU are X",然后将其转换为合适的回答,如"W ...

  7. 数据挖掘:概念与技术(第三版)之第十章的学习记录

    本章主要讲解聚类的基本概念和方法 对聚类的浅要分析 聚类是什么意思,很好理解,这里不说了. 需要注意的是一下这几点 1.在相同的数据集上,不同的聚类方法可能产生不同的聚类 . 2.聚类可以作为其他算法 ...

  8. 数据挖掘:概念与技术(第三版)之第一章的学习记录

    写在前面的话 第一章为引论,主要对技术和概念进行概述.但是在我读来,书中对一些概念的阐述对于初学者来说相当不友好,语言组织逻辑相当差,陌生词汇繁多且不做解释.我不知道是自己水平有限理解不了还是翻译得不 ...

  9. 《微机原理与接口技术(第三版)》的专有名词缩写你还在死记硬背???【更新至第二章 ARM微处理器

    这些名称都是英文单词的缩写,理解记忆方为上策. 有些缩写的全称百度不到,是我用零散的相同首字母的单词拼凑出来的,仅供参考,如有纰漏,请读者指正. 第一章 微型计算机系统 中文名称 英文缩写 英文全称 ...

  10. 【杂谈】篇篇精华,有三AI不得不看的技术综述(超过100篇核心干货)

    文/编辑 | 言有三 有三AI很少写零散的报导,因为我们的文章通常都是提炼与总结,一般遇到一个新方向,找技术综述读一读是最合适的开始,大家也可以拓展一下自己的知识边界,今天总结一下有三AI迄今为止发过 ...

最新文章

  1. 【软件】chrome设置默认字体
  2. python requests text content_python requests的content和text方法的区别
  3. jwt:介绍以及创建token
  4. eclipse(或者myeclipse)常用配置方法
  5. 将亚型多态性与通用多态性相关联的危险
  6. .net core下简单构建高可用服务集群
  7. 【李宏毅2020 ML/DL】P23 Transformer | Self-attention, Multi-head Self-attention
  8. 华为海思K3平台总体特性
  9. v-model中修饰符lazy,number, trim的作用
  10. android anr 分析方法,Android ANR分析
  11. 搜索 阿虚同学_凉宫春日阿虚台词“在虚构的故事当中寻求真实感的人脑袋一定有问题”动画是出自那一集?...
  12. python小写变为大写_在python中改为大写和小写
  13. Google与百度、搜狗合作,共同推进移动网络发展
  14. c++/c/java数据结构--队列
  15. iOS开发之AVPlayer的精彩使用---网易新闻视频播放界面的另类实现
  16. 开源项目搭建私有物联网智能家居接入天猫精灵控制
  17. centos 7和redhat 7的区别及如何安装
  18. 用CSS实现段落前面缩进两个字
  19. adb 判断imei,如何在Android 5.0上使用adb命令获取MEID和IMEI信息?
  20. [OC学习笔记]分类和关联对象源码解析

热门文章

  1. python提取二值栅格上边界和中线
  2. LSD源代码编译运行
  3. 【转ITAA上justdoit的一篇帖子】 验证OSPF中对外部路由路由的选择规则【留档】
  4. ROS2的create_publisher参数详解
  5. 宣纸一笔,思重于行——聊一聊思考的价值
  6. 【stm32单片机基础】按键状态机实现长按和短按
  7. Failed to start reboot.target: 连接超时
  8. win10做好备份如何恢复系统
  9. mysql 赋权_《MySQL数据库》MySQL用户赋权
  10. python微信抢票脚本_春节到了 教你使用python来抢票回家