November 2015 Blog Posts

Sublime Text一个文件内创建多个代码片段(snippets)

MitchellChu 2015-11-30 其他技术

在使用IDE做开发的很多时候,为了减少代码的输入,会创建代码的片段,在需要的时候直接呼出即可。这种方法往往能够提高我们的效率,同时也大大降低我们代码的出错几率!在Sublime Text中,同样提供了创建代码片段的功能(Snippets),但ST默认提供的创建代码片段的方式是一个代码片段一个文件,这种方式对于代码片段的管理有些不便——虽然和Emacs一样提供文件夹的方式来集中管理,不过还是有些不够方便,本文就从创建ST默认的代码片段开始,到一个文件多个snippets的过程做个记录。

ST()创建Snippets

ST的Tools->New Snippet...为创建代码片段,点击后,出现代码片段的模板,如下(ST3):

<snippet>
	<content><![CDATA[
Hello, ${1:this} is a ${2:snippet}.
]]></content>
	<!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
	<!-- <tabTrigger>hello</tabTrigger> -->
	<!-- Optional: Set a scope to limit where the snippet will trigger -->
	<!-- <scope>source.python</scope> -->
</snippet>

这个即是单个snippet的全貌了。

TIPS

  • content :这个即是,注意:
    <![CDATA[ ]]>
     这个是不能删掉的,表示数据内容。如果要开启Tab触发的话(一般都会开启吧),那么:
  • tabTrigger:这个就需要取消注释了,这个里面填写的是触发字符串,当在ST编辑时,和此内容匹配时,即可用Tab直接呼出content内容来替换当前位置tabTrigger的内容
  • scope: 应用的范围,Mitchell Chu创建比较多的snippet是针对python的,所以,这里我一般是source.python,当然,你也可以是其他内容,比如,针对js的可以是source.js

但根据需要对上面三个内容作出了适当修改后,我们就得到了我们需要的一个代码片段了(snippet),比如像下面这样:

<snippet>
	<content><![CDATA[
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright @ ${1:2015} ${2:Mitchell Chu}
# Blog: http://blog.useasp.net/

]]></content>
	<!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
	<tabTrigger>!python</tabTrigger>
	<!-- Optional: Set a scope to limit where the snippet will trigger -->
	<scope>source.python</scope>
</snippet>

确认无误,我们保存到文件即可完成一个代码片段的添加。

注意:

  • 代码片段的文件一定要保存为:.sublime-snippet 的后缀,否则无法识别,路径放在:.\Data\Packages\User
  • 保存后,需要重启ST,才能加载snippet —— 这个不知是否是个人原因,如果你没办法使用,可以尝试重启ST后再试。

 

管理snippet

像上面这样创建snippet,少量还能应付,但数量变多时,问题就来了,要修改某个代码片段将是一个小复杂的工作,更糟糕的是,如果你使用ST做多语言的开发时,每个语言都有自己的,这个时候你将会发现,如果不加管理,要编辑的话,将可能变成一个噩梦!

要管理snippets也不是不可能的,ST中虽然默认没有给我们提供默认方案,但ST提供了管理支持 —— 文件夹!ST会自动的搜索子文件夹的内容,这就为我们管理snippets提供了方便。

我们可以对于单个语言创建一个文件夹,比如:python相关的snippets我们放到Python的文件夹下,这样管理起来也就自然方便多了。

 

多个代码片段在同一个文件

也许,你对上面的管理方式不够满意,同时你也有信心,会好好的小心谨慎的修改每个snippet,这种要求显然是不能通过上面的方案实现的,这个时候我们需要使用的是:——使用补全功能来达到类似多个snippets在同一个文件的效果。

初始的completions的文件也许是这样的:

{
   "scope": "source.python",

   "completions":
   [
      { "trigger": "doc", "contents": "'''\n${1:TODO DOC HERE}\n'''" }
   ]
}

这是一个针对python文件的completions,当在python文件中输入doc之后,我们就可以出现选项提示,如果确认(Ctrl+SpacebarTab,测试发现Enter亦可),则可以完成contents插入到当前位置(替换掉已经的输入)。

TIPS:

  • scope:这个和snippets中的一样
  • completions:这面定义你需要的各种代码片段
  • trigger: 监控的字符串输入,这个提示在ST3中,像doc,你在输入d的时候,他会自动查找d开头的所有trigger。一般放的是关键字。
  • contents:内容模板,要替换trigger中的内容,内容可以使用$1,$2,$3...的方式来作为placeholder[参见Palceholder节]

 

这还只是一个啊,如何实现多个在一个文件内呢?—— 注意,completions,这个里面只要你愿意,你是可以添加无数个trigger的,比如,小菜Mitchell在使用的时候,就添加了:

"completions":
[
  { "trigger": "!head", "contents": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\n#\n# Copyright (c) ${1:2015} ${2:Mitchell Chu}\n" },
  { "trigger": "!doc", "contents": "'''\n${1:TODO doc here.}\n'''" },
  { "trigger": "!pdbdebug", "contents": "import pdb\npdb.set_trace()\n" }
]

这样在编辑的时候插入注释,直接doc一下了,要插入文件头,直接head —— 请无视trigger里面的感叹号(注意:trigger里面的\t有特别用处,不能无视哦)。

这样是不是就将所有的代码片段放到一个文件内了呢,是不是感觉瞬间整洁很多了? 恩,至少Mitchell Chu是这么觉得的。

注意:

  • 文件保存的时候,必须要保存为:.sublime-completions的后缀,同时文件要和snippets一样,放到规定的目录下。
  • 如果有特殊字符,记得使用转义,使用两个反斜杆.

 

关于PlaceHolder

在snippet或者completions中,content(s)里面是可以使用占位符的,占位符以$开头,可以一般有两种方式:

  1. $+数字:这个占位符的数字从1开始,可以一直递增,也可以重复,如:
    this message is come from blog.useasp.net, My Name is $1:
    Current Time: $2
    Wellcome, $3
    —— $1
    
    
     在插入到ST中后,光标会停留在$1的位置(注意,这里有两个地方),当你输入内容的时候,这两个占位符的地方都将同时输入。使用Tab来移动到下一个位置。也许我们想为每个位置提供默认值,这个时候可以使用第二种方式:
  2. ${数字:默认内容}:这个占位符中数字和上种方式一致,如:
    this message is come from blog.useasp.net, My Name is ${1:Mitchell Chu}:
    Current Time: ${2:8 PM}
    Wellcome, ${3:Guest}
    —— ${1:Mitchell Chu}
     这个时候,插入的内容是有默认值的,如果不用改变,直接Tab到下一个位置即可。

 

你有什么好玩的技巧呢? 也请分享一下,共同提高下~:P 

 

 参考:

1. Sublime Text Snippets

2. Sublime Text Completions

Python产生token唯一值的算法性能比较

MitchellChu 2015-11-08 其他技术

在很多场合的时候,我们都需要产生不重复的字符串来标志操作的唯一性,比如:HTTP请求中,我们需要产生SessionID,在数据存储的时候,我们也可能需要生成唯一的字符串来作为数据的ID以便我们进行索引。本文的由来是在使用tornado的时候,需要使用Session,Session需要有唯一的ID值。为了尽可能快速的生成安全可用的Session ID,而对当前的一些比较通用的生成方法进行了比较。为了方便说明,后继的所有说法均以token作为, 唯一字串等的统一表述。

在网络中比较流行的是使用uuid4().hex的方式来生成token,但另外一种声音是,uuid4().hex的安全性不高,需要使用安全性更高的算法来代替,后继出现了使用os.urandom(24),或者自行随机生成字符串的形式(使用的是os.urandom(16)),再到后来,使用OpenSSL和M2Crypto的方式来生成随机数。OpenSSL和M2Crypto需要Python安装pyOpenSSLM2Crypto。M2Crypto由于接触少,因此没有对M2Crypto进行测试。

 

测试环境:

CPU: Intel Xeon E3 3.30Hz 3.70Hz

Memory: 16GB

System: Windows 7 64-bits

# times:测试次数
# func: 要测试的函数名称
# 此方法是入口方法
# 各个算法以函数的形式定义,接受times参数即可——By MitchellChu
def crash_testx(times, func):
	import time
	print('\r\n--------------------------------------------')
	print("test function: %s" % func.func_name)
	print("begin time: %s" % time.strftime('%Y%m%d %X'))
	begin_time = time.time()
	(crashed_times, hash_data_len) = func(times)
	print("end time: %s" % time.strftime('%Y%m%d %X'))
	print("take time:%s" % (time.time() - begin_time))
	print("test times: %d, crashed times:%d, hash data length:%d" % (times, crashed_times, hash_data_len))
	print('--------------------------------------------\r\n')

 

产生方式(generate method)

长度(hash length)

组合范围

耗时(second/10million)

包含包(import packages)

base64.b64encode(os.urandom(24),['_','-']) 32 64^32 65.9289999008 base64, os
base64.b32encode(os.urandom(20)) 32 32^32 86.3580000401 base64, os
sha1(os.urandom(24)).hexdigest() 40 16^40 29.6259999275 os, hashlib
''.join(random.choice(alphabet_digits) for _ in range(32)) 32 62^32 214.484999895 random,string
binascii.b2a_base64(os.urandom(24))[:-1] 32 64^32 22.5640001297 os, binascii
(binascii.b2a_base64(os.urandom(24))[:-1]).translate(translationstr)* 32 64^32 24.5349998474 os, binascii
(binascii.b2a_base64(os.urandom(24))[:-1]).translate(translationstr)* 32 64^32 398.623999834 os, binascii
(binascii.b2a_base64(os.urandom(24))[:-1]).replace('/','_').replace('+','-')* 32 64^32 27.271999836 os, binascii
uuid4().hex 32 16^32 159.762000084 uuid
binascii.b2a_base64(OpenSSL.rand.bytes(24))[:-1] 32 64^32 61.1059999466 binascii,OpenSSL

* 星号表示的几个使用的都是binascii.b2a_base64来生成64位数据,不同的是:第一个translate中的translationstr是全局生成的,而第二个translate中的translationstr是在每次生成时生成,测试的时间来看,每次生成需要耗费大量时间。最后为了比较,使用了两个replace来进行对照。

从测试的结果来看,性能最佳的为binascii.b2a_base64

binascii.b2a_base64(os.urandom(24))[:-1]

 其次性能非常棒的是

sha1(os.urandom(24)).hexdigest()

从生成的覆盖范围来看,SHA1生成的会少于。但base64中有两个特殊字符(这需要注意传入的字节数),因此在有些时候并不适合。

uuid4().hex在测试中看来确实性能不好,仅略优于自定义token生成的方法(random.choice)。

OpenSSL生成的token安全性具体比os.urandom优多少,并无测试,也并不太清楚具体的实现细节,哪位知道,可以说明下。:P

 

结论:

  1. 可以用base64的地方,选择binascii.b2a_base64是不错的选择 —— 根据W3的Session ID的字串中对identifier的定义,Session ID中使用的是base64,但在Cookie的值内使用需要注意“=”这个特殊字符的存在;
  2. 如果要安全字符(字母数字),SHA1也是一个不错的选择,性能也不错;

 

参考:

 

 

关于博主

  一枚成分复杂的网络IT分子,属于互联网行业分类中的杂牌军。