2020-07
15

改进

By xrspook @ 10:06:49 归类于: 烂日记

我觉得哪一天自己不看一下脚本,尤其是在工作日的时候,就觉得日子好像缺了点什么。脚本可以是VS Code里的那些,也可以是Excel VBA,同样也可以是各种的网页源代码,又或者是XML文件。反正就是一些不是给人看的东西,又或者说,不是给人直接看的东西。那些东西经过软件的处理以后,结果是给人看的,但是我看那些东西的时候,却是给机器看的。我还没有神经病到要看二进制代码的地步。

一个没有完美倾向的码农,绝对不是一个好码农。所以当我看到,单位的那个所谓智能系统出来东西每一页都有错的时候,我怎么可能不吐槽。他们测试过了吗?他们真的测试过了吗?他们不只是没有测试过,而且做那个表的人根本没用心,连抄都可以抄错。因为我自己是一个码农,所以我知道那些步骤到底应该是怎样的。我不知道专业的码农日子是怎么过的,反正只要我开始任务。任何时候我脑子里可能都在想,有可能是吃饭的时候,也有可能是跑步的时候,经常发生在我洗澡的时候。

写出来的东西的确能实现一些功能,但是那个东西真的能兼容所有情况吗?如果有一些突发的呢?突发的时候,我们可以手动使用B计划,也就是非智能秒杀计划,但是能不能在秒杀计划里加一些判断分分支适应特殊情况呢?这完全是可以做到的,但是一开始的时候,那并不是核心功能所在,所以没有被考虑进去。到达一定程度以后,我就要把那个功能泛化出来。不仅仅做到一些核心的东西,连一些正常的例外也得考虑进去。之所以这么说,是因为昨天走回宿舍的路上,在洗澡之前,我又想起前天写的两个脚本我还可以加一些条件判断进去,使之适应一些后续增加的例外事件。虽然说那些是例外事件,但是在某些情况下,有可能变成常态。之前我不知道该如何处理,但昨天,写了两个数据透视表的脚本以后,我明白到数据透视表我可以固定用某个表名。如果之前已经存在那样的表名,第一步需要把那个表删掉,然后开始后面的操作。又或者,我并不需要删掉那个东西,我只需要改变数据的引用范围。在我的知识范围内,直接删掉比调整引用范围简单。但实际上调整应用范围也必定是一个可控的东西,所以大概接下来我要了解一下怎么在VBA里改变数据透视表的应用范围。另外一个脚本更简单一些,直接是判断某个单元格那时是不是某个固定的东西,是的话就无需进行插入操作,直接开始排序,不是的话就要先进行插入,然后排序。

如果之前我没有学过python,没有努力地写过各种脚本,大概我会觉得泛化有点麻烦,但是当我经历过那些东西以后,我觉得这一切都理所当然了,我甚至想写一个自定义函数把主流程丢到里面去,那么,核心部分的判断就会非常明了,理论上VBA也肯定能做到。之所能具备了这种思路,我必须得感谢Think Python这本书。这种思路是我大学时学习程序语言的时候所不知道的。虽然那时我通过了计算机二级C语言的考试,但那考试对我来说只是一张纸。是后续我接触到、我自学回来的东西,成就了现在的我。

变得更好的路永无尽头。

2020-07
14

脚本相关

By xrspook @ 9:09:56 归类于: 烂日记

昨天GitHub不知道发生什么状况,下午我发现服务器上不去,晚上貌似又好了。但问题是,下午我push上去的东西,代码页面已经修正过来了,但是网页显示还是老版本,至于为什么,我实在没搞懂。无论,我把仓库检查多少遍,线上跟线下都是一致的,为什么展示页面却不行呢?实在让我很迷惑,如果仍然是这种状况,估计我得把整个仓库里的内容全部删掉,然后重来。这样做肯定是最彻底的,但我真的需要如此变态吗?好像有人说过,如果修改了某些东西,那个会导致网页崩溃的话,GitHub Pages就会一直保留在最后那个靠谱的版本,我觉得新生成的网页没什么问题,因为我在单机上也测试过了,所以接下来可能我要把本地仓库里面的东西全部删掉,然后重新生成网站,再去校验。昨天我试图用一下git bash,但我发现自己根本不知道那个五颜六色的东西要干嘛。尤其是到达某个叫我注释的页面,我完全不知道该如何处理那个东西,不知道该用键盘还是鼠标,不知道应该在哪里操作。那个界面没有任何提示,真的让人非常抓狂。Dos界面很多东西都是默认的快捷键,但显然那个五颜六色的版面的快捷键我一窍不通。而他们默认的处理方式是你懂的。用CMD处理git不是老手做法,但我觉得CMD反而让我心安理得一点,因为CMD要输入的东西永远在最后,不会五颜六色蹦出来一个界面,或许能用鼠标,但实际上又好像实现不了某个功能。VS Code貌似原生是支持GitHub的功能,但我好像找不到登录界面。我明明已经把某个仓库的本地文件夹加入到VS Code的工作区,但是软件还是没感知出来。

下午的GitHub一直显示服务器500错误。没办法搞那个,所以我就研究Excel VBA去了,去实现一个我一直以来都很想做,但是却一直没有动手的东西。最终我写出来了两个脚本,一个用来整理数据,另外一个用来一键生成数据透视表。这两个东西,基本不需要再理清思路,首先用录制宏走一遍,然后参考一下里面的代码。录制的宏里面,总有很多废话,很多无厘头的各种操作。如果那个代码完全是写的,而不是录制的,就没有这么多多余的东西。录制的宏里面默认会带入非常多的默认设置,但实际上,那是不需要写出来的。录制的宏里面也有非常多确定某个选区的命令,但实际上,那也是没必要的。在Excel的可视化界面,鼠标点在某个单元格,录制的宏里面就会确定一个选区。实际上很多时候,鼠标点在哪个单元格其实都是无所谓的,那是很随意的,但是其实我们可以确定某些不随意的单元格。把定位写死就不用经常切换选区,选区选来选去,选了以后又没取消,我不确定会不会整出什么幺蛾子。数据整理的脚本我写的内容还多一点。数据透视表的一键生成跟我录制出来的那个东西差别不大,因为的确那些语句都得表达出来。耗费我最长时间的是数据透视表新表格的建立。我一直以为是数据选区我的表达有问题,但实际上原来是我新增数据表的某些语句写错了。VBE与VS Code比起来,我觉得最不人性化的就是,明明那都是明摆的语法,是你拼写错误了,运行的时候,居然不提醒你。如果能像VS Code那样,固定搭配写对了,显示某个颜色,如果你乱写一个东西就不是那个颜色,语法错误就给你下滑波浪线,debug的时候,我就不需要浪费那么多时间。昨天我的状态也不太行,因为一些理所当然的单词我几乎每次都会拼写错误。看来看去找不到原因,最后发现单词写错了。大概如果我要玩Excel VBA,我必须得找一个靠谱的VS Code插件。

在经历过好几个星期才能解决一个脚本问题以后,一天解决了两个,让人有莫名的成就感。

2020-06
18

BlogBus 2 WordPress – by xrspook

By xrspook @ 19:50:07 归类于: 扮IT

为什么要学习python?因为我见识过python有多牛逼,简单一个脚本文件,轻量级的东西实现强大的功能。因为要做XML文件的格式转换,所以我觉得我要学好python。Think Python 2看到第14章,我就转向去研究10年多以前网友写的BlogBus转WordPress的python脚本。之所以要研究,因为当时的WordPress格式和现在不一样,用以前的脚本转换出来的东西已经没办法直接导入到现在的WordPress里了。再去找写代码的那些人,有些网站还在,但有些已经消失了。我不能等待别人拯救我,我只能自己拯救自己。

我需要转换格式的是“回到过去——Betty迷的独白”和“Mi Internacional Cielo”,这两个旧BlogBus站点和我的主站“我的天”不一样,虽然里面有不少我原创的东西,但我从四面八方搜集回来的内容也不少。当时的BlogBus默认编辑界面是富文本,我看上去觉得格式没问题大概就可以了,但实际上格式是有问题的。从五湖四海搜集回来的文字里面怎么可能不夹杂各种格式,那些东西在富文本编辑下可能看不出来,但在源代码界面一团糟。如果当年我复制粘贴的时候有先去记事本过渡一下就不会有那么多的问题。所以除了要转换BlogBus和WordPress的标签以外我还要筛选删除那些坏事的源代码。

经过接近一周的努力,我终于整出来了。运行下面的python3脚本,如果能顺利完成,自动生成出新的XML文件,用官方途径导入WordPress 5.4.2是完全没有问题的,但我只测试了我自己的两个blog,是不是兼容其它我不知道。因为转换blog我是有自己的想法的,所以脚本中有一些个性化的东西,比如我把blog的标题变成了分类,把原来的分类变成了标签。脚本中有大量的反转义替换,主要是为了人去看CDATA的时候不太头晕迷糊,因为我那两个旧blog里有大量的西班牙语字符,不同的编码下,BlogBus的导出文件里有些被转义了有些没有。那些转义了的放到WordPress里不知道WordPress会不会转回来,我试过标题被BlogBus转义之后WordPress不会转回来,看得我云里雾里。因为转义很头痛,所以除了少数几个内容,有可能被转义的文字都被我用CDATA包裹了起来。

脚本不是我一个人的功劳,我只是在当年网友脚本的基础上做了调整,使之适配python3和WordPress 5.4.2。

我的脚本:xbus2wp.py (PS:下面脚本330行的《/p》是什么鬼怪!WordPress的脚本插件在搞什么!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
'''
***使用说明***
终端界面输入xbus2wp.py bus.xml xrspook。其中:
xbus2wp.py为脚本名字,bus.xml为BlogBus导出文件,xrspook为博主名字,3个参数以空格分开
若运行无误,输出的文件名为[原文件名_xbus2wp.xml]
脚本基于python3,适配WordPress 5.4.2(2020-06-18)
'''
 
import re, sys, getopt, datetime
from xml.dom import minidom
from time import time
 
def convert(inputFileName, owner, order='asc'):
    """"""
    try:
        xmldoc = minidom.parse(inputFileName)
    except Exception as e:
        print ('Fail.')
        print (e)
        print ('Please repair or delete invalid token like "& < >" there.')
        sys.exit(1)
 
    bus = xmldoc.documentElement
    logs = bus.getElementsByTagName('Log')
 
    dom = minidom.Document()
    rss = dom.createElement('rss') # rss是root,根元素
    dom.appendChild(rss)      
    rss.setAttribute('version', '2.0')
    rss.setAttribute('xmlns:content', 'http://purl.org/rss/1.0/modules/content/')
    rss.setAttribute('xmlns:wfw', 'http://wellformedweb.org/CommentAPI/')
    rss.setAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/')
    rss.setAttribute('xmlns:wp', 'http://wordpress.org/export/1.0/')
    channel = dom.createElement('channel')
    rss.appendChild(channel)
    wxr_version = dom.createElement('wp:wxr_version') # 加入wxr戳,无戳无法进行WordPress导入
    channel.appendChild(wxr_version)
    wxr_version_node = dom.createTextNode('1.1')
    wxr_version.appendChild(wxr_version_node)
 
    busname = bus.getElementsByTagName('BlogName')[0] # 提取原BlogBus名字
    busname_text = getElementData(busname).replace(' ', '_')
 
    # create a list to contain items instead of appending them to
    # channel directly in order to sort them of lately according to order.
    if order == 'desc':
        item_list = []
    else:
        item_list = None
 
    for log in logs:
        title = log.getElementsByTagName('Title')[0]
        title_text = getElementData(title)
        content = log.getElementsByTagName('Content')[0]
        content_text = getElementData(content)
        logdate = log.getElementsByTagName('LogDate')[0]
        pubdate = getElementData(logdate)
        writer = log.getElementsByTagName('Writer')[0]
        creator = owner # BlogBus的writer根本没包含元素!
        category = getElementData(log.getElementsByTagName('Sort')[0])
        tagi = log.getElementsByTagName('Tags')[0]
        tags = getElementData(tagi).split(' ')
        new_tags = unique_tag(category, tags) # 新的wp标签里包含了原BlogBus里的分类与标签
        comments = log.getElementsByTagName('Comment')
 
        #-----
        item = dom.createElement('item')
 
        # handle title
        title_element = createElement(dom, 'title', title_text, 'cdata')
        item.appendChild(title_element)
 
        # handle type
        type_element = createElement(dom, 'wp:post_type', 'post', 'cdata')
        item.appendChild(type_element)
 
        # handle pubdate
        pubdate_element = createElement(dom, 'pubDate', convertPubDate(pubdate))
        item.appendChild(pubdate_element)
 
        # handle creator
        creator_element = createElement(dom, 'dc:creator', creator, 'cdata')
        item.appendChild(creator_element)
 
        # handle categories with domain
        category_element = createElement(dom, 'category', busname_text, 'cdata') # 把BlogBus标题设置为分类,因为我要合并多个旧blog
        category_element.setAttribute('domain','category')
        category_element.setAttribute('nicename', busname_text)
        item.appendChild(category_element)
 
        # handle tags
        for tag in new_tags:
            tag = tag.replace('&ntilde;', 'n')
            tag = tag.replace('summary_of_BLF', 'summary_of_BLF(from_rincondebetty)')
            tag = tag.replace('summary_of_EcoModa', 'summary_of_EcoModa(from_rincondebetty)')
            category_element = createElement(dom, 'category', tag, 'cdata')
            category_element.setAttribute('domain','post_tag')
            category_element.setAttribute('nicename', tag)
            item.appendChild(category_element)
 
        # handle content
        content_element = createElement(dom, "content:encoded", content_text, 'cdata')        
        item.appendChild(content_element)
 
        # handle post_date
        post_date_element = createElement(dom, "wp:post_date", pubdate)
        item.appendChild(post_date_element)
 
        # handle status
        status_element = createElement(dom, "wp:status", 'publish')
        item.appendChild(status_element)
 
        # handle comments
        if comments:
            commentElements = createComments(dom, comments)
            for commentElement in commentElements:
                item.appendChild(commentElement)
 
        if item_list != None:
            item_list.append(item)
        else:
            channel.appendChild(item)
 
    if item_list:
        item_list.reverse()
        for m in item_list:
            channel.appendChild(m)
 
    global filename # 输出设置
    output = filename + '_xbus2wp.xml'
    f = open(output ,'wb+')
    import codecs
    writer = codecs.lookup('utf-8')[3](f)
    dom.writexml(writer, '', ' ' * 4, '\n', encoding='utf-8')
    writer.close()
 
def unique_tag(category,tags): # 只保留唯一的标签
    category = category.replace(' ', '_')
    l = category.split() + tags
    new_l = []
    for item in l:
        if item not in new_l and item != '(from_rincondebetty)':
            new_l.append(item.replace(' ', '_')) # 替换空格为下划线
    return new_l
 
def getElementData(element): # 获取节点数据
    """"""
    data = ''
    for node in element.childNodes:
        if node.nodeType in (node.TEXT_NODE, node.CDATA_SECTION_NODE):
            data += node.data
    return data
 
def createComments(dom, comments):
    """"""
    l = []
    count = 0
    for comment in comments:
        count += 1 # 每篇文章的评论序号,没有序号,评论只能导入每篇最后一条
        email = comment.getElementsByTagName('Email')[0]
        homepage = comment.getElementsByTagName('HomePage')[0]
        name = comment.getElementsByTagName('NiceName')[0]
        content = comment.getElementsByTagName('CommentText')[0]
        date = comment.getElementsByTagName('CreateTime')[0]
        comment_element = createCommentElement(count, dom, email, homepage, name, content, date)
        l.append(comment_element)
    return l
 
def createCommentElement(count, dom, email, homepage, name, content, date):
    """"""
    comment_author = getElementData(name)
    comment_author_email = getElementData(email)
    comment_author_url = getElementData(homepage)
    comment_date = getElementData(date)
    comment_content = getElementData(content)
 
    comment_id_element = createElement(dom, 'wp:comment_id', str(count))
    comment_author_element = createElement(dom, 'wp:comment_author', comment_author)
    comment_author_email_element = createElement(dom, 'wp:comment_author_email', comment_author_email)
    comment_author_url_element = createElement(dom, 'wp:comment_author_url', comment_author_url)
    comment_date_element = createElement(dom, 'wp:comment_date', comment_date)
    comment_date_gmt_element = createElement(dom, 'wp:comment_date_gmt', comment_date)
    comment_content_element = createElement(dom, 'wp:comment_content', comment_content, 'cdata')
    comment_approved_element = createElement(dom, 'wp:comment_approved', '1')
 
    # make the comment element
    comment_element = dom.createElement('wp:comment')
    comment_element.appendChild(comment_id_element)
    comment_element.appendChild(comment_author_element)
 
    # validate email and url
    validEmail = validateEmail(comment_author_email)
    if (validEmail):
        comment_element.appendChild(comment_author_email_element)
 
    validUrl = validateUrl(comment_author_url)
    if (validUrl):
        comment_element.appendChild(comment_author_url_element)    
 
    comment_element.appendChild(comment_date_element)
    comment_element.appendChild(comment_date_gmt_element)
    comment_element.appendChild(comment_content_element)
    comment_element.appendChild(comment_approved_element)
 
    return comment_element
 
def createElement(dom, elementName, elementValue, type='text'): #建立节点标签和节点
    """"""
    global owner
    tag = dom.createElement(elementName)
    if elementValue.find(']]>') > -1:
        type = 'text'
    if type == 'text':
        text = dom.createTextNode(elementValue)
    elif type == 'cdata':
        elementValue = elementValue.replace('&amp;', '&')
        elementValue = elementValue.replace('&lt;', '<')
        elementValue = elementValue.replace('&gt;', '>')
        elementValue = elementValue.replace('&apos;', '\'')
        elementValue = elementValue.replace('&quot;', '"')
 
        # 大量替换与我的旧blog有各种编码的西班牙语字符有关
        elementValue = elementValue.replace('&copy;', '') # 版权标志
        elementValue = elementValue.replace('&nbsp;', '') # 空格
        elementValue = elementValue.replace('&ldquo;', '“') # 左双引号
        elementValue = elementValue.replace('&rdquo;', '”') # 右双引号
        elementValue = elementValue.replace('&lsquo;', '‘') # 左单引号
        elementValue = elementValue.replace('&rsquo;', '’') # 右单引号
        elementValue = elementValue.replace('&acute;', '´') # 单引号
        elementValue = elementValue.replace('&hellip;', '...') # 省略号
        elementValue = elementValue.replace('&mdash;', '—') # 破折号
        elementValue = elementValue.replace('&middot;', '·') # 分隔号
        elementValue = elementValue.replace('&deg;', '°') # 单位度
        elementValue = elementValue.replace('&iexcl;', '¡') # 西班牙语反叹号
        elementValue = elementValue.replace('&iquest;', '¿') # 西班牙语反问号
        elementValue = elementValue.replace('&ntilde;', 'ñ') # 西班牙语n
        elementValue = elementValue.replace('&Ntilde;', 'Ñ') # 西班牙语N
        elementValue = elementValue.replace('&aacute;', 'á') # 西班牙语a
        elementValue = elementValue.replace('&eacute;', 'é') # 西班牙语e
        elementValue = elementValue.replace('&iacute;', 'í') # 西班牙语i
        elementValue = elementValue.replace('&oacute;', 'ó') # 西班牙语o
        elementValue = elementValue.replace('&uacute;', 'ú') # 西班牙语u
        elementValue = elementValue.replace('&Aacute;', 'Á') # 西班牙语A
        elementValue = elementValue.replace('&Eacute;', 'É') # 西班牙语E
        elementValue = elementValue.replace('&Iacute;', 'Í') # 西班牙语I
        elementValue = elementValue.replace('&Oacute;', 'Ó') # 西班牙语O
        elementValue = elementValue.replace('&Uacute;', 'Ú') # 西班牙语U
        elementValue = elementValue.replace('&Atilde;', 'Ã') # 西班牙语A~
        elementValue = elementValue.replace('&ordf;', 'ª') # 西班牙语上标a
        elementValue = elementValue.replace('&ordm;', 'º') # 西班牙语上标o
 
        elementValue = elementValue.replace('<!--msnavigation-->', '')
        elementValue = elementValue.replace('博主', owner)
        elementValue = elementValue.replace('<i>', '')
        elementValue = elementValue.replace('</i>', '')
        elementValue = elementValue.replace('<br /><br />', '<br />')
 
        elementValue = re.sub(r"(?:<\?xml.*?>)", "", elementValue)
        elementValue = re.sub(r"(?:<[TDSFHI].*?>)", "", elementValue)
        elementValue = re.sub(r"(?:<\/[TDSFHI].*?>)", "", elementValue)
        elementValue = re.sub(r"(?:<P.*?>)", "<p>", elementValue)
        elementValue = re.sub(r"(?:<(table|tbody|tr|td|div|span|img|script|font|hr|object|param).*?>)", "", elementValue)
        elementValue = re.sub(r"(?:<\/(table|tbody|tr|td|div|span|img|script|font|object).*?>)", "", elementValue)
        elementValue = re.sub(r"\n", "", elementValue) # 把替换造成的空行删除
 
        text = dom.createCDATASection(elementValue)
    tag.appendChild(text)
    return tag
 
def convertPubDate(date, timediff='+0000'):
    """
    convert 2003-08-22 16:01:56
    to Thu, 23 Aug 2007 05:47:54 +0000
    """
    year, mon, day = int(date[:4]), int(date[5:7]), int(date[8:10])
    time = date[11:]
    aday = datetime.datetime(year, mon, day)
    d = {'1':'Mon', '2':'Tus', '3':'Wen', '4':'Thur', '5':'Fri', '6':'Sat', '7':'Sun'}
    m = {'1':'Jan', '2':'Feb', '3':'Mar', '4':'Apr', '5':'May', '6':'Jun',
         '7':'Jul', '8':'Aug', '9':'Sep', '10':'Oct', '11':'Nov', '12':'Dec'}
    weekday = d[str(aday.isoweekday())]
    month = m[str(mon)]
    pubdate = "%s, %d %s %s %s %s" % (weekday, day, month, year, time, timediff)
    return pubdate
 
def validateEmail(email):
    '''
    '''
    pattern = r'^[0-9a-z][_.0-9a-z-]{0,31}@([0-9a-z][0-9a-z-]{0,30}[0-9a-z]\.){1,4}[a-z]{2,4}$'
    p = re.compile(pattern)
    m = p.match(email)
    if m:
        return True
    else:
        return False
 
def validateUrl(url):
    '''
    '''
    pattern = r'^[a-zA-z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$'
    p = re.compile(pattern)
    m = p.match(url)
    if m:
        return True
    else:
        return False
 
def main(argv=None):    
    global filename
    global owner
 
    if argv is None:
        argv = sys.argv
    # parse command line options
 
    args = sys.argv[1:]
    order='asc'
    if (len(args) == 2):
        print ('Converting...'),
        sys.stdout.flush()
        start = time()
        filename = args[0].replace('.xml', '')
        owner = args[1] # BlogBus没把博主名字输出,只能手动
        convert(args[0], args[1], order)
        end = time()
        print ('Done. Elapse %g seconds.' % (end - start))
 
if __name__ == "__main__":
    sys.exit(main())
</p>
2020-06
5

随机单词扎堆成文

By xrspook @ 14:47:54 归类于: 扮IT

从某本书里随机找单词拼出句子段落。重点是把握好前缀和后缀,前缀要捆绑查找,后缀要关联对应。

Exercise 8: Markov analysis: Write a program to read a text from a file and perform Markov analysis. The result should be a dictionary that maps from prefixes to a collection of possible suffixes. The collection might be a list, tuple, or dictionary; it is up to you to make an appropriate choice. You can test your program with prefix length two, but you should write the program in a way that makes it easy to try other lengths. Add a function to the previous program to generate random text based on the Markov analysis. Here is an example from Emma with prefix length 2: He was very clever, be it sweetness or be angry, ashamed or only amused, at such a stroke. She had never thought of Hannah till you were never meant for me?” “I cannot make speeches, Emma:” he soon cut it all himself. For this example, I left the punctuation attached to the words. The result is almost syntactically correct, but not quite. Semantically, it almost makes sense, but not quite. What happens if you increase the prefix length? Does the random text make more sense? Once your program is working, you might want to try a mash-up: if you combine text from two or more books, the random text you generate will blend the vocabulary and phrases from the sources in interesting ways. Credit: This case study is based on an example from Kernighan and Pike, The Practice of Programming, Addison-Wesley, 1999. You should attempt this exercise before you go on; then you can download my solution from http://thinkpython2.com/code/markov.py. You will also need http://thinkpython2.com/code/emma.txt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import string
import random
from collections import defaultdict
def set_book(fin1,num):
    d = defaultdict(list) # 默认键值为列表
    l = []
    header = ()
    for line in fin1:
        line = line.replace('-', ' ')
        for word in line.rstrip().split(): # 空格换行为分割,单词存入列表
            l.append(word)
    for i in range(len(l)-num): # 以列表序号逐一推进方式建立字典
        header = (l[i-1],) # 元组header为前缀,做键
        for j in range(i,i+num-1):
            header += (l[j],)
            j += 1
        if l[i+num-1] not in d[header]:
            d[header].append(l[i+num-1]) # 列表后缀做键值
    return d
def next(start, book):
    return random.choice(book[start])
fin1 = open('emma.txt', encoding='utf-8')
prefix_num = 3 # 前缀个数
suffix_num = 100 # 后缀个数
book = set_book(fin1,prefix_num)
start = random.choice(list(book.keys())) # 随机前缀开头
final =  start
for i in range(suffix_num): # 截取最后几个单词为前缀找后缀
    final += (next(final[len(final)-prefix_num:], book),) 
for word in final:
    print(word, end=' ')
# reigns alone. A very proper compliment! and then follows the application, 
# which I think, my dear, you said you had a great deal happier if she had no 
# intellectual superiority to make atonement to herself, or frighten those 
# who might hate her into outward respect. She had never seen her look so well, 
# so lovely, so engaging. There was consciousness, animation, and warmth; 
# there was every appearance of its being all in proof of how much he was 
# in love with, how to be able to return! I shall try what I can do. 
# Harriet's features are very delicate, which makes a likeness
2020-05
2

改变字典规则不香吗?

By xrspook @ 20:55:44 归类于: 扮IT

改变字典的键值规则就可以把从一本书里挑随机单词这件事轻松搞定,我真搞不懂参考答案为啥要那么折腾。在Think Python 2的第十三章里,字典的默认规则是单词是键,词频是键值。既然这道题要唯一的索引找随机单词,我把键值变成唯一序号不就完事大吉了?再来一个zip把字典的键值和键互换,random.choice()直接就到达随机单词了。我只改了生成字典的规则,耗时0.12秒,参考答案折腾了不只一点点,耗时0.42秒。之所以参考答案不修改字典规则,是因为他们要灌输python拼装模块的特性,拼装很方便,但事实证明效率不一定最高。

This algorithm works, but it is not very efficient; each time you choose a random word, it rebuilds the list, which is as big as the original book. An obvious improvement is to build the list once and then make multiple selections, but the list is still big.

An alternative is: Use keys to get a list of the words in the book. Build a list that contains the cumulative sum of the word frequencies (see Exercise 2). The last item in this list is the total number of words in the book, n. Choose a random number from 1 to n. Use a bisection search (See Exercise 10) to find the index where the random number would be inserted in the cumulative sum. Use the index to find the corresponding word in the word list.

Exercise 7: Write a program that uses this algorithm to choose a random word from the book. Solution: http://thinkpython2.com/code/analyze_book3.py.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import string
import random
from time import time
def set_book(fin1):
    useless = string.punctuation + string.whitespace + '“' + '”' # 标点符号、换行符全部咔嚓掉
    d = {}
    i = 1
    for line in fin1:
        line = line.replace('-', ' ') # 有-的单词全部一分为二,这样真的好吗?
        for word in line.split():
            word = word.strip(useless)
            word = word.lower()
            if word not in d:
                d[word] = i # 录入字典的时候键值就是序号
                i += 1
            # d[word] = d.get(word, 0) + 1 # 反正我不算词频,这个没必要了
    return d
fin1 = open('emma.txt', encoding='utf-8')
start = time()
book1 = set_book(fin1)
book2 = dict(zip(book1.values(), book1.keys())) # 键和键值互换,序号成了唯一索引号
print('100 random words in book')
for i in range(100):
    if i > 1 and i%8 == 0:
        print()
    print(random.choice(book2), end=' ') # 索引号找词,想多快有多快
print()
end = time()
print(end - start)
# 100 random words in book
# solicit laughing preserve inebriety elton's unimpeded effusions unselfish
# intimate connect native judges charities travel informs colours
# enigmas bragge case greensward cox's particularly unexampled promise
# prone greensward dignity maps fourth christmas creature maximum
# graver mildest pleasant corrected increased named partridge marks
# following kept gloom conjecturing parlour inheriting say consulting
# magnified abundant produces sons malt add unenforceability beautifully
# richly striking confuse greatness asleep steps humility upon
# already paper delight liberties confide appendages undecided male
# prophecies esteem unadorned likelihood shopping deeply unbiased horrors
# man's dumplings business chapter shakespeare sees counsels attentive
# silenced ventured singular double mean waltzes requisite checks
# unattended qualified blessed surmises
# 0.12100672721862793
© 2004 - 2024 我的天 | Theme by xrspook | Power by WordPress