1. 我们怎样才能编写程序访问本地和网络上的文件,从而获得无限的语言材料?
2. 我们如何把文档分割成单独的词和标点符号,这样我们就可以开始像前面章节中在文本语料上做的那样的分析?

3. 我们怎样编程程序产生格式化的输出,并把结果保存在一个文件中?

from __future__ import division
import nltk, re, pprint

3.1 从网络和硬盘访问文本

电子书

from urllib.request import urlopen
url =  "http://www.gutenberg.org/files/2554/2554-0.txt"
raw = urlopen(url).read().decode('utf-8')
print(type(raw))
print(len(raw))
print(raw[:75])#对于语言处理,我们要将字符串分解为词和标点 符号,正如我们在第 1 章中所看到的。
#这一步被称为分词,它产生我们所熟悉的结构,一个 词汇和标点符号的链表。
tokens = nltk.word_tokenize(raw)
print(type(tokens))
print(len(tokens))
print(tokens[:10])# #从这个链表创建一个 NLTK 文本
text = nltk.Text(tokens)
print(type(text))
print(text[1020:1060])
print(text.collocations())

处理的 HTML

url = "http://news.bbc.co.uk/2/hi/health/2284783.stm"
html = urlopen(url).read().decode("utf-8")
print(html[:60])#使用BeautifulSoup来从HTML中提取文本,然后我们可以对原始文本进行分词
from bs4 import BeautifulSoup as bs
raw = bs(html,"lxml").get_text()
tokens = nltk.word_tokenize(raw)
print(tokens[:5])

处理搜索引擎的结果

网络可以被看作未经标注的巨大的语料库。网络搜索引擎提供了一个有效的手段,搜索 大量文本作为有关的语言学的例子。
搜索引擎的主要优势是规模,网络搜索引擎的第二 个优势是非常容易使用

显著的缺点
首先,允许的搜索方式的范围受到严格限制。 不同于本地驱动器中的语料库,你可以编写程序来搜索任意复杂的模式,搜索引擎一般只允 许你搜索单个词或词串,有时也允许使用通配符。
其次,搜索引擎给出的结果不一致,并且 在不同的时间或在不同的地理区域会给出非常不同的结果。当内容在多个站点重复时,搜索 结果会增加。
最后,搜索引擎返回的结果中的标记可能会不可预料的改变,基于模式的方法 定位特定的内容将无法使用

处理 RSS 订阅

import feedparser
llog = feedparser.parse("http://languagelog.ldc.upenn.edu/nll/?feed=atom")
print(llog['feed']['title'])
print(len(llog.entries))
post = llog.entries[2]
print(post.title)
content = post.content[0].value
print(content[:70])print(nltk.word_tokenize(bs(content, 'lxml').get_text())[:5])

读取本地文件

#为了读取本地文件,我们需要使用 Python 内置的 open()函数,然后是 read()方法。
f = open("document.txt")
raw = f.read()
print(raw)import os
os.listdir('.')f = open("document.txt", 'r')
for line in f:print(line.strip())#使用 strip()方法删除输入行结尾的换行符b#NLTK中的语料库文件也可以使用这些方法来访问。
#我们只需使用 nltk.data.find()来获取语料库项目的文件名。然后就可以使用我们刚才讲的方式打开和阅读它。
path = nltk.data.find('corpora/gutenberg/melville-moby_dick.txt')
raw = open(path, 'r').read()
print(raw)

从 PDF、MS Word及其他二进制格式中提取文本

捕获用户输入

s = input("请输入:" )
print(s)

NLP 的流程

处理流程:打开一个URL,读里面HTML格式的内容,去除标记,并选择字符的切片,然后分词,是否转换为 nltk.Text对象是可选择的。
我们也可以将所有词汇小写并提取 词汇表
使用 type(x)我们可以找出任一 Python 对象 x 的类型

3.2 字符串:最底层的文本处理

字符串的基本操作

circus = 'Monty Python\'s Flying Circus'
print(circus)
#如果一个字符串 中包含一个单引号,我们必须在单引号前加反斜杠让 Python 知道这是字符串中的单引号
circus = 'Monty Python's Flying Circus'
print(circus)#一个包含 两个字符串的序列被连接为一个字符串。
#我们需要使用反斜杠或者括号,这样解释器就 知道第一行的表达式不完整。
couplet = "Shall I compare thee to a Summer's day?"\"Thou are more lovely and more temperate:"
print(couplet)#首先,让我们来看看+ 操作,被称为连接
print('very' + 'very' + 'very')
#对字符串用乘法
print('very' * 3)
#我们已经看到加法和乘法运算不仅仅适用于数字也适用于字符串。但是,请注意,我们 不能对字符串用减法或除法:
print('very' - 'y')

输出字符串

monty = "Monty Python"
print(monty)
grail = 'Holy Grail'
print(monty + grail)
print(monty, grail)
print(monty, "and the", grail)

访问单个字符

#字符串也是索引从零开始。
#当我们索引一个字符 串时,我们得到它的一个字符(或字母)。
#一个单独的字符并没有什么特别,它只是一个长度为1的字符串。
monty = "Monty Python"
print(monty[0])
print(monty[-1])
print(monty[-5])#我们可以写一个 for 循环,遍历字符串中的字符。
sent = "colorless green ideas sleep furiously"
for char in sent:print(char, end=" ")#我们也可以计数单个字符。通过将所有字符小写来忽略大小写的区分,并过滤掉非字母字符。
print()
from nltk.corpus import gutenberg
raw = gutenberg.raw('melville-moby_dick.txt')
fdist = nltk.FreqDist(ch.lower() for ch in raw if ch.isalpha())
print(fdist.most_common(5))
print([word for (word, freq) in fdist.most_common()])
fdist.plot()

访问子字符串

#使用 in 操作符测试一个字符串是否包含一个特定的子字符串
phrase = 'And now for something completely different'
if 'thing' in phrase:print('found "thing"')monty = "Monty Python"
#也可以使用 find()找到一个子字符串在字符串内的位置
monty.find("Python")

更多的字符串操作

s.find(t) 字符串 s 中包含 t 的第一个索引(没找到返回-1)
s.rfind(t) 字符串 s 中包含 t 的最后一个索引(没找到返回-1)
s.index(t) 与 s.find(t)功能类似,但没找到时引起 ValueError
s.rindex(t) 与 s.rfind(t)功能类似,但没找到时引起 ValueError
s.join(text) 连接字符串 s 与 text 中的词汇
s.split(t) 在所有找到 t 的位置将 s 分割成链表(默认为空白符)
s.splitlines() 将 s 按行分割成字符串链表
s.lower() 将字符串 s 小写
s.upper() 将字符串 s 大写
s.titlecase() 将字符串 s 首字母大写
s.strip() 返回一个没有首尾空白字符的 s 的拷贝

s.replace(t, u) 用u替换 s 中的 t

链表与字符串的差异

#字符串和链表都是一种序列。我们可以通过索引抽取它们中的一部分,可以给它们切片,可以使用连接将它们合并在一起。
#但是,字符串和链表之间不能连接。
qurey = "Who knows?"
beatles = ['John', 'Paul', 'George', 'Ringo']
print(qurey[2])
print(beatles[2])
print(qurey + " I don't")
print(beatles + ["brian"])
#字符串是不可变的:一旦你创建了一个字符串,就不能改变它。然而,链表是可变的,其内容可以随时修改
#作为一个结论,链表支持修改原始值的操作,而不是产生一 个新的值。

3.3 使用 Unicode 进行文字处理

什么是 Unicode?

Unicode 支持超过一百万种字符。每个字符分配一个编号,称为编码点。在 Python 中, 编码点写作\uXXXX 的形式,其中 XXXX 是四位十六进制形式数。
文件中的文本都是有特定编码的,所以我们需要一些机制来将文本翻译成 Unicode—— 翻译成 Unicode 叫做解码。
要将 Unicode 写入一个文件或终端,我们首先需要将 U nicode 转化为合适的编码——这种将 Unicode 转化为其它编码的过程叫做编码

从文件中提取已编码文本

path = nltk.data.find('corpora/unicode_samples/polish-lat2.txt')
import codecs
f = codecs.open(path, encoding="latin2")
for line in f:line = line.strip()print(line.encode("unicode_escape"))#使用 ord()查找一个字符的整数序数
print(ord('a'))#97 的十六进制四位数表示是 0061,所以我们可以使用相应的转义序列定义一个 Unicode 字符串常量:
a = u'\u0061'
print(a)

在 Python 中使用本地编码

3.4 使用正则表达式检测词组搭配

正则表达式给我们一个更加强大和灵 活的方法描述我们感兴趣的字符模式。

import re
wordlist = [w for w in nltk.corpus.words.words('en') if w.islower()]

使用基本的元字符

#让我们使用正则表达式«ed$»查找以 ed 结尾的词汇。
#函数 re.search(p, s)检查字符 串 s 中是否有模式 p。
#我们需要指定感兴趣的字符,然后使用美元符号,它是正则表达式中 有特殊用途的符号,用来匹配单词的末尾:
print([w for w in wordlist if re.search('ed$', w)][:5])#  ^表示匹配字符串的开始,$表示匹配字符串的结尾
print([w for w in wordlist if re.search('^..j..t..$', w)][:5])
#不用^和$这两个符号
print([w for w in wordlist if re.search('..j..t..', w)][:5])#符号“?”表示前面的字符是可选的
#因此«^e-?mail $»将匹配 email和 e-mail
list = ['email', 'e-mail', 'wang']
print([w for w in list if re.search('^e-?mail', w)])
#我们可以使用 sum(1 for w in text if re.search('^e-? mail$', w))
#计数一个文本 中这个词(任一拼写形式)出现的总次数。
print(sum(1 for w in list if re.search('^e-?mail$', w)))

范围与闭包

#T9 系统用于在手机上输入文本,两个或两个以上的词汇以相同的击键顺序输入,这叫做输入法联想提示
#hole 和 golf 都是通过输入序列 4653。
#还有哪些其它 词汇由相同的序列产生?这里我们使用正则表达式«^[ghi][mno][jlk][def]$»
print([w for w in wordlist if re.search('^[ghi][mno][jlk][def]$', w)])#将匹配只使用中间 行的 4、5、6 键的词汇
print([w for w in wordlist if re.search('^[ghijklmno]+$', w)][:5])#"+"
print([w for w in wordlist if re.search('^[g-o]+$', w)][:5])#«^[a-fj-o]+$»将匹配使用右上角 2、3、5、6 键 的词汇。
print([w for w in wordlist if re.search('^[a-fj-o]+$', w)][:5])#进一步探索“+”
#它可以适用于单个字母或括号内的字母集“+”表示的是“前面的项目的一个或多个实例,”它可以是单独的字母如 m,
#可以是一个集合如[fed],可以是一个范围如[d-f] 。
chat_words = sorted(set(w for w in nltk.corpus.nps_chat.words()))
print([w for w in chat_words if re.search('^m+i+n+e+$', w)])
print([w for w in chat_words if re.search('^[ha]+$', w)][:5])#用“*”替换“+”
#“前面的项目的零个或多个实例。"正则表达式«^m*i*n*e*$»将匹配所有我们用«^m+i+n+e+$»找到的,
#同时包括其中一些字母不出现的词汇,例如:me、min 和 mmmmm。
print([w for w in chat_words if re.search('^m*i*n*e*$', w)][:5])
#请注意“+”和“*”符号有时被称为的 Kleene 闭包,或者干脆闭包#运算符“^”当它出现在方括号内的第一个字符位置时有另外的功能。
#例如:«[^aeiouAEIOU]»匹配除元音字母之外的所有字母。
print([w for w in chat_words if re.search('^[^aeiouAEIOU]+$', w)][:5])
#这些例子演 示如何使用一些新的符号:\,{},()和|。
wsj = sorted(set(nltk.corpus.treebank.words()))
#反斜杠表示其后面的字母不再有特殊的含义而是按照字面的表示匹配 词中特定的字符。因此,虽然“.”有特殊含义,但“\.”值匹配一个句号
print([w for w in wsj if re.search('^[0-9]+\.[0-9]+$', w)][-5:])
print([w for w in wsj if re.search('^[A-Z]+\$$', w)])
print([w for w in wsj if re.search('^[0-9]{4}$', w)][:5])   # {n} 重复 n 次,n 为非负整数
print([w for w in wsj if re.search('^[0-9]+-[a-z]{3,5}$', w)][:5])
print([w for w in wsj if re.search('^[a-z]{5,}-[a-z]{2,3}-[a-z]{,6}$', w)])   # {n,}至少重复 n 次
print([w for w in wsj if re.search('(ed|ing)$', w)][:5])     # ed|ing|s匹配指定的一个字符串(析取)

· 通配符,匹配所有字符
^abc 匹配以 abc 开始的字符串
abc$ 匹配以 abc 结尾的字符串
[abc] 匹配字符集合中的一个
[A-Z0-9] 匹配字符一个范围
* 前面的项目零个或多个,如 a*, [a-z]* (也叫 Kleene 闭包)
+ 前面的项目 1 个或多个,如 a+, [a-z]+
? 前面的项目零个或 1 个(即:可选)如:a?, [a-z]?
{n} 重复 n 次,n 为非负整数
{n,} 至少重复 n 次
{,n} 重复不多于 n 次
{m,n} 至少重复 m 次不多于 n 次
a(b|c)+ 括号表示操作符的范围

3.5 正则表达式的有益应用

除了检查一个正则表达式是否匹配一个单词外,我们还可以使用正则表达式从词汇中提取的特征或以特殊的方式来修改词。

提取字符块

#通过re.findall() (“find all”即找到所有)方法找出所有(无重叠的)匹配指定正则表 达式的。
#让我们找出一个词中的元音,再计数它们
word = 'supercalifragilisticexpialidocious'
print(re.findall(r'[aeiou]', word))
print(len(re.findall(r'[aeiou]', word)))#让我们来看看一些文本中的两个或两个以上的元音序列,并确定它们的相对频率
wsj = sorted(set(nltk.corpus.treebank.words()))
fd = nltk.FreqDist(vs for word in wsjfor vs in re.findall(r'[aeiou]{2,}', word))
print(fd.items())
for word, freq in fd.items():print(word, freq)break#将字符串'2009-12-31'转换为一 个整数链表[2009, 12, 31]:
print([int(n) for n in re.findall(r'[0-9]+', '2009-12-31')])

在字符块上做更多事情

#英文文本是高度冗余的,忽略掉词内部的元音仍然可以很容易的阅读,有些时候这很明显
#例如:declaration变成 dclrtn,inalienable变成 inlnble,保留所有词首或词尾的元音序列。
#正则表达式匹配词首元音序列,词尾元音序列和所有的辅音;其它的被忽略。
#这三个阶段从左到右处理,如果词匹配了三个部分之一,正则表达式后面的部分将被忽略
#使用 re.findall()提取所有匹配的词中的字符,然后使用''.join()将它们连接在一 起
regexp = r'^[AEIOUaeiou]+|[AEIOUaeiou]+$|[^AEIOUaeiou]'
def compress(word):pieces = re.findall(regexp, word)return "".join(pieces)english_udhr = nltk.corpus.udhr.words("English-Latin1")
print(nltk.tokenwrap(compress(w) for w in english_udhr[:75]))#将正则表达式与条件频率分布结合起来
rotokas_words = nltk.corpus.toolbox.words("rotokas.dic")
cvs = [cv for w in rotokas_words for cv in re.findall(r'[ptksvr][aeiou]', w)]
cfd = nltk.ConditionalFreqDist(cvs)
cfd.tabulate()

查找词干

#使用网络搜索引擎时,我们通常不介意(甚至没有注意到)文档中的词汇与我们的搜 索条件的后缀形式是否相同
#对于一些语言处理任务,我们想忽略词语结尾,只是处理词干。
#抽出一个词的词干的方 法有很多种。这里的是一种简单直观的方法,直接去掉任何看起来像一个后缀的字符:
def stem(word):for suffix in ['ing', 'ly', 'ed', 'ious', 'ive', 'es', 's', 'ment']:if word.endswith(suffix):return word[:-len(suffix)]word = "interesting"
print(stem(word))#虽然我们最终将使用 NLTK 中内置的词干,看看我们如何能够使用正则表达式处理这个任务是有趣的。
#我们的第一步是建立一个所有后缀的连接。我们需要把它放在括号内以限 制这个连接的范围。
print(re.findall(r'^.*(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processing'))
#尽管正则表达式匹配整个单词,re.findall()只是给我们后缀。这是因为括号有第二个功能:选择要提取的子字符串。
#如果我们要使用括号来指定连接的范围,但不想选 择要输出的字符串,必须添加“?:”,它是许多神秘奥妙的正则表达式之一
print(re.findall(r'^.*(?:ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processing'))
#然而,实际上,我们会想将词分成词干和后缀。
#所以,我们应该只是用括号括起正则表达式的这两个部分:
print(re.findall(r'^(.*)(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processing'))#让我们来看看另外的词“processes”
print(re.findall(r'^(.*)(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processes'))
#正则表达式错误地找到了后缀“-s ”,而不是后缀“-es”。这表明另一个微妙之处:“*”操作符是“贪婪的”,
#所以表达式的“.*”部分试图尽可能多的匹配输入的字符串。如果我 们使用“非贪婪”版本的“*”操作符,写成“*?”,我们就得到我们想要的
print(re.findall(r'^(.*?)(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processes'))
#我们甚至可以通过使第二个括号中的内容变成可选,来得到空后缀
print(re.findall(r'^(.*?)(ing|ly|ed|ious|ies|ive|es|s|ment)?$', 'language'))
print(re.findall(r'^(.*?)(ing|ly|ed|ious|ies|ive|es|s|ment)?$', 'language')[0])def stem(word):regexp = r'^(.*?)(ing|ly|ed|ious|ies|es|s|ment)?$'stem, suffix = re.findall(regexp, word)[0]return stem
raw = """DENNIS: Listen, strange women lying in ponds distributing swordsis no basis for a system of government. Supreme executive power derives froma mandate from the masses, not from some farcical aquatic ceremony."""
tokens = nltk.word_tokenize(raw)
print([stem(t) for t in tokens][:5])

搜索已分词文本

#尖括号用于标记标识符 的边界,尖括号之间的所有空白都被忽略
#我们使用<.*>,它将匹配所有单个标识符,将它括在括号里,
#于是只匹配词(例如:monied)而不匹配短语(例如:a monied man)。
from nltk.corpus import gutenberg, nps_chat
moby = nltk.Text(gutenberg.words('melville-moby_dick.txt'))
print(moby.findall(r'<a>(<.*>)<man>'))#第二个例子找出以词“br o”结尾的三个词组成的短语�。
chat = nltk.Text(nps_chat.words())
print(chat.findall(r'<.*><.*><bro>'))#最后一个例子找出以字母“l”开始的三个或更多词组成的 序列
print(chat.findall(r'<l.*>{3,}'))# \w 表示单词字符
#在大型文本语料库中搜索“x and other ys”形式 的表达式能让我们发现上位词
from nltk.corpus import brown
hobbies_learned = nltk.Text(brown.words(categories=['hobbies', 'learned']))
print(hobbies_learned.findall(r'<\w*><and><other><\w*s>'))#查找模式“as x as y”的实例以发现实体及其属性信息
from nltk.corpus import brown
hobbies_learned = nltk.Text(brown.words(categories=['hobbies', 'learned']))
print(hobbies_learned.findall(r'<as><\w*><as><\w*>'))

3.6 规范化文本

#首先,我们需要定义我们将在本节中使用的数据:
raw = """DENNIS: Listen, strange women lying in ponds distributing swords is no basis for a system of government. Supreme executive power derives from a mandate from the masses, not from some farcical aquatic ceremony."""
tokens = nltk.word_tokenize(raw)
print(tokens)

词干提取器

#Porter 词干提取器正确处理了词 lying(将它映射为 lie),而 Lancaster 词干提取 器并没有处理好。
porter = nltk.PorterStemmer()
lancaster = nltk.LancasterStemmer()
print([porter.stem(t) for t in tokens][:5])
print([lancaster.stem(t) for t in tokens][:5])

词形归并

#WordNet词形归并器删除词缀产生的词都是在它的字典中的词。这个额外的检查过程使 词形归并器比刚才提到的词干提取器要慢。
#请注意,它并没有处理“lying”,但它将“women”转换为“woman”。
wnl = nltk.WordNetLemmatizer()
print([wnl.lemmatize(t) for t in tokens][:5])
#如果你想编译一些文本的词汇,或者想要一个有效词条(或中心词)列表,WordNet词形归并器是一个不错的选择。

3.7 用正则表达式为文本分词

分词是将字符串切割成可识别的构成一块语言数据的语言单元。

分词的简单方法

raw = """'When I'M a Duchess,' she said to herself, (not in a very hopeful tonethough), 'I won't have any pepper in my kitchen AT ALL. Soup does verywell without--Maybe it's always pepper that makes people hot-tempered,'..."""
#使用 raw.split()在空格符处分割原始文本。使用正则表达式能做同样的事情,匹配字符串中的所有空格符是不够的,
#因为这将导致分词结果包含“\n”换行符;我们需 要匹配任何数量的空格符、制表符或换行符
print(re.split(r' ', raw)[:20])
print(re.split(r'[ \t\n]+', raw)[:20])
#正则表达式«[ \t\n]+»匹配一个或多个空格、制表符(\t)或换行符(\n)。其他空白字符,如回车和换页符,确实应该包含的太多。
#于是,我们将使用一个 re 库内置的缩写“\ s”,它表示匹配所有空白字符。前面的例子中第二条语句可以改写为re.split(r'\s+', raw)。
print(re.split(r'\s+', raw)[:20])# 要点:记住在正则表达式前加字母“r”,它告诉 Python 解释器按照字面表示
#对待字符串而不去处理正则表达式中包含的反斜杠字符。
#\W 任何非字母数字字符(相当于[^a-zA-Z0-9_])
print(re.split(r'\W', raw)[:5])
print(re.split(r'\w', raw)[:5])print(re.findall(r'\w+|\S\w*', raw)[:5])

\b 词边界(零宽度)
\d 任一十进制数字(相当于[0-9])
\D 任何非数字字符(等价于[^ 0-9])
\s 任何空白字符(相当于[ \t\n\r\f\v])

\S 任何非空白字符(相当于[^ \t\n\r\f\v])

\w 任何字母数字字符(相当于[a-zA -Z0-9_])

\W 任何非字母数字字符(相当于[^a-zA-Z0-9_])

\t 制表符
\n 换行符

NLTK 的正则表达式分词器

函数 nltk.regexp_tokenize()与 re.findall()类似(我们一直在使用它进行分词)。
然 而,nltk.regexp_tokenize()分词效率更高,且不需要特殊处理括号。

分词的进一步问题

分词是一个比你可能预期的要更为艰巨的任务。没有单一的解决方案能在所有领 域都行之有效,
我们必须根据应用领域的需要决定哪些是标识符。
分词的最后一个问题是缩写的存在

3.8 分割

断句

#在词级水平处理文本通常假定能够将文本划分成单个句子。正如我们已经看到,一些语 料库已经提供在句子级别的访问。
#在下面的例子中,我们计算布朗语料库中每个句子的平均 词数:
print(len(nltk.corpus.brown.words()) / len(nltk.corpus.brown.sents()))

分词

#将连续的语音流分割成单个的词汇
#例3-2. 从分词表示字符串seg1和seg2中重建文本分词。
#seg1和seg2表示假设的一些儿童讲话的初始和最终分词。函数 segment()可以使用它们重现分词的文本。
text = "doyouseethekittyseethedoggydoyoulikethekittylikethedoggy"
seg1 = "0000000000000001000000000010000000000000000100000000000"
seg2 = "0100100100100001001001000010100100010010000100010010000"
def segment(text, segs):words = []last = 0for i in range(len(segs)):if segs[i] == '1':words.append(text[last:i+1])last = i + 1words.append(text[last:])return words
print(segment(text, seg1))
print(segment(text, seg2))#现在分词的任务变成了一个搜索问题:找到将文本字符串正确分割成词汇的字位串
#我们可以定义一个目标函数,一个打分函数,我们将基于词典的大小和从词典中重构源文本所需的信息量尽力优化它的值。
#例3-3. 计算存储词典和重构源文本的成本。
def evaluate(text, segs):words = segment(text, segs)text_size = len(words)lexicon_size = len(''.join((set(words))))return (text_size + lexicon_size)
text = "doyouseethekittyseethedoggydoyoulikethekittylikethedoggy"
seg1 = "0000000000000001000000000010000000000000000100000000000"
seg2 = "0100100100100001001001000010100100010010000100010010000"
seg3 = "0000100100000011001000000110000100010000001100010000001"
print(segment(text, seg1))
print(segment(text, seg2))
print(segment(text, seg3))
print(evaluate(text, seg1))
print(evaluate(text, seg2))
print(evaluate(text, seg3))

3.9 格式化:从链表到字符串

从链表到字符串

#我们用于文本处理的最简单的一种结构化对象是词链表。
#当我们希望把这些输出到显示器或文件时,必须把这些词的链表转换成字符串。
#在 Python 做这些,我们使用的 join()方 法,并指定作为“胶水”使用的字符串:
silly = ['We', 'called', 'him', 'Tortoise', 'because', 'he', 'taught', 'us', '.']
print(' '.join(silly))
print(','.join(silly))
#join()方法只适用于一个字符串的链表— —我们一直把它叫做一个文本——在 Python 中享有某些特权的一个复杂的类型。

字符串与格式

#格式化输出通常包含变量和预先指定的字符串的一个组合
fdist = nltk.FreqDist(['dog', 'cat', 'dog', 'cat', 'dog', 'snake', 'dog', 'cat'])
for word in fdist:print(word,'->', fdist[word],';')#除了不必要的空格符问题,输出包含变量和常量交替出现的表达式是难以阅读和维护的。
#一个更好的解决办法是使用字符串格式化表达式。
for word in fdist:print('%s->%d;'%(word, fdist[word]))
#特殊符号%s 和%d 是字符串和整数(十进制数)的占位符。
#我们可以将这些嵌入在一个字符串中,然后使用%操作符把它们组合起来。#我们还可以间接的提供占位符的值。下面是使用 for 循环的一个例子
template = 'Lee wants a %s right now'
menu = ['sandwich', 'spam fritter', 'pancake']
for snack in menu:print(template % snack)

排列

#指定宽度,如%6s,产生一个宽度为 6 的字符串
print('%6s'%'dog')#包括一个减号使它左对齐
print('%-6s'%'dog')#事先不知道要显示的值应该有多宽时, 可以在格式化字符串中用*替换宽度值,然后指定一个变量。
width = 6
print('%-*s'%(width, 'dog'))#其他控制字符用于十进制整数和浮点数。
#因为百分号%在格式化字符串中有特殊解释,我们要在它前面加另一个%才能输出它。
count, total = 3205, 9375
print("accuracy for %d words:%2.4f%%"%(total, 100 * count / total))

将结果写入文件

#打开可写文件 output.txt ,将程序的输出保存到文件。
output_file = open('output.txt', 'w')
words = set(nltk.corpus.genesis.words('english-kjv.txt'))
for word in sorted(words):output_file.write(word + "\n")print(len(words))
print(str(len(words)))output_file.write(str(len(words)) + "\n")
output_file.close()
#你应该避免文件名包含空格字符,例如:output file.txt
#避免使用除了大小 写区别外其他都相同的文件名,例如:Output.txt 与 output.TXT。

文本换行

#可以在 Python 的 textwrap 模块的帮助下采取换行
saying = ['After', 'all', 'is', 'said', 'and', 'done', ',', 'more', 'is', 'said', 'than', 'done', '.']
from textwrap import fill
format = '%s(%d),'
pierces = [format % (word, len(word)) for word in saying]
output = ' '.join(pierces)
wrapped = fill(output)
print(wrapped)

3.10 小结

在本书中,我们将文本作为一个词链表。“原始文本”是一个潜在的长字符串,其中包 含文字和用于设置格式的空白字符,也是我们通常存储和可视化文本的原料。

在 Python 中指定一个字符串使用单引号或双引号:'Monty Python',"Monty Python"。

字符串中的字符是使用索引来访问的,索引从零计数:'Monty Python'[0]的值是 M。 求字符串的长度可以使用 len()。

子字符串使用切片符号来访问: 'Monty Python'[1:5]的值是 onty。如果省略起始 索引,子字符串从字符串的开始处开始;如果省略结尾索引,切片会一直到字符串的结 尾处结束。

字符串可以被分割成链表:'Monty Python'.split()得到['Monty', 'Python']。链表 可以连接成字符串:'/'.join(['Monty', 'Python'])得到'Monty/Python'。

我们可以使用 text = open(f).read()从一个文件 f 读取文本。可以使用 text = urlpen(u).read()从一个 URL u 读取文本。我们可以使用 for line in open(f)遍历一个文本文件的每一行。

在网上找到的文本可能包含不需要的内容(如页眉、页脚和标记),在我们做任何语言处理之前需要去除它们。

分词是将文本分割成基本单位或标记,例如词和标点符号等。基于空格符的分词对于许多应用程序都是不够的,因为它会捆绑标点符号和词。NLTK 提供了一个现成的分词器nltk.word_tokenize()。

词形归并是一个过程,将一个词的各种形式(如:appeared,appears)映射到这个词标准的或引用的形式,也称为词位或词元(如:appear)。

正则表达式是用来指定模式的一种强大而灵活的方法。只要导入了 re 模块,我们就可以使用 re.findall()来找到一个字符串中匹配一个模式的所有子字符串。

如果一个正则表达式字符串包含一个反斜杠,你应该使用原始字符串与一个 r 前缀:r'regexp',告诉 Python 不要预处理这个字符串。

当某些字符前使用了反斜杠时,例如:\n,处理时会有特殊的含义(换行符);然而,当反斜杠用于正则表达式通配符和操作符时,如:\.,\|,\$,这些字符失去其特殊的含义,只按字面表示匹配。

一个字符串格式化表达式 template % arg_tuple 包含一个格式字符串 template,它由如%-6s 和%0.2d 这样的转换标识符符组成。

《用Python进行自然语言处理》第3章 加工原料文本相关推荐

  1. 《Python自然语言处理(第二版)-Steven Bird等》学习笔记:第03章 加工原料文本

    第03章 加工原料文本 3.1 从网络和硬盘访问文本 电子书 处理的HTML 处理搜索引擎的结果 处理RSS 订阅 读取本地文件 从PDF.MS Word 及其他二进制格式中提取文本 捕获用户输入 N ...

  2. 一起来学自然语言处理----加工原料文本

    加工原料文本 从网络和硬盘访问文本 1.电子书 2.处理的HTML 3.读取本地文件 4.NLP的流程 字符串:字符串的基本操作 使用Unicode进行文字处理 1. 从文件中提取已编码文本 使用正则 ...

  3. python自然语言处理答案_《用Python进行自然语言处理》 第一章练习题答案

    尝试使用Python解释器作为一个计算器,输入表达式,如12/(4+1). >>> 12 / (4 + 1) 2.4 26 个字母可以组成 26 的 10 次方或者 26**10个 ...

  4. Python自然语言处理 | 加工原料文本

    本章的目的是要回答下列问题: 我们怎样才能编写程序访问本地和网络上的文件,从而获得无限的语言材料? 我们如何把文档分割成单独的词和标点符号,这样我们就可以开始像前面章节中在文本语料上做的那样的分析? ...

  5. python cook读书笔记第2章字符串和文本

    使用多个界定符分割字符串 line = 'asdf fjdk; afed, fjek,asdf, foo' import re # line = re.split(r'[;,\s]\s*',line) ...

  6. 用Python进行自然语言处理 读书笔记 第一章

    用Python进行自然语言处理(第一章) 搜索文本 text1.concordance("monstrous")#搜索文章中的词语text3.concordance("l ...

  7. 《用Python进行自然语言处理》第 5 章 分类和标注词汇

    1. 什么是词汇分类,在自然语言处理中它们是如何使用? 2. 一个好的存储词汇和它们的分类的 Python 数据结构是什么? 3. 我们如何自动标注文本中词汇的词类? 将词汇按它们的词性(parts- ...

  8. 用python进行自然语言处理

    近来,在看一本用python进行自然语言处理的书,里面的例子比较多,博主在此将其整理如下,一是方便自己查看,二是帮助广大学友共同学习,对于里面的问题大家都可以随时讨论.PS:书名为python自然语言 ...

  9. Python基础与大数据应用章末小结(一)

    目录 第二章 Python编程基础 第三章 函数 第四章 面向对象编程基础 第五章 模块 第六章 Python文件和数据库 第二章 Python编程基础 1.Python常用的数据类型有数值.字符串. ...

最新文章

  1. 隧道接口工具airtun-ng
  2. BZOJ 2788[Poi2012]Festival
  3. SQLite Version3.3.6源代码文件结构
  4. 中方:开展科技合作应秉持开放、合作、包容心态
  5. 常用网站URL规划分析
  6. python安装要什么配置_Python的安装和详细配置
  7. 白话经典算法系列之——希尔排序的实现
  8. Spark Streaming中流式计算的困境与解决之道
  9. mysql ---- DDL(了解)
  10. 【链表】牛客网:链表删除
  11. ZYNQ7020 Soc最小系统创建及测试
  12. VMRC 控制台的连接已断开
  13. 解决win7安装梦幻桌面后不能使用,成灰色的问题
  14. 《卓有成效的管理者》读书笔记(二)——卓有成效是可以学会的
  15. 自动化测试平台(十三):接口自动化框架与平台对比及应用场景分析及设计思路分享
  16. 用js代码简单的介绍自己
  17. Ardupilot -- APM源码笔记四(重制)~ 线程机制
  18. Mybatis源码基础解析
  19. Latex url波浪号~问题
  20. 网络模拟器软件分享——Cisco Packet Tracer、华为eNSP、H3C Cloud Lab

热门文章

  1. “反过来”学数学:从图形到符号的思考法
  2. 一盘棋都没下过,AI只听人类评论比赛,就学会了国际象棋,还战胜了DeepChess...
  3. 推荐给Android开发者的抢手书单
  4. 深入揭示Web 2.0核心技术——混搭
  5. ​两大顶级AI算法一起开源!Nature、Science齐发Alphafold2相关重磅,双厨狂喜~
  6. 汪星人出门也靠脸?狗脸识别技术可识别化妆后的汪星人,准确率99%
  7. 想快速入门NLP?我们测评了15门最火课程,帮你找到最适合的
  8. 独家 | 教你实现数据集多维可视化(附代码)
  9. 的确好用!Python数据科学速查表中文版强势来袭!
  10. php log在哪里看,PHP Log时时查看小工具