使用Python文件读写,自定义分隔符(custom delimiter)
众所周知,python文件读取文件的时候所支持的newlines(即换行符),是指定的。这一点不管是从python的doucuments上还是在python的源码中(作者是参考了python的io版本,并没有阅读C版本),都可以看出来:
ifnewlineisnotNoneandnotisinstance(newline,str): raiseTypeError("illegalnewlinetype:%r"%(type(newline),)) ifnewlinenotin(None,"","\n","\r","\r\n"): raiseValueError("illegalnewlinevalue:%r"%(newline,))
好吧,问题来了,如果你恰好是个苦逼的生物狗,正在用python处理所谓的fastq格式的测序结果文件,每次只读一行往往不是你想要的。Ok,我们也都知道其实这个问题在Perl里面十分好解决,无非就是重新定义下文件的分割符($/,Theinputrecordseparator,newlinebydefault.Setundeftoreadthroughtheendoffile.)
local$/;#enable"slurp"mode local$_=;#wholefilenowhere s/\n[\t]+//g;
简单粗暴有效!《ProgrammingPerl》开头的那些关于什么是happiness定义看来所言非虚,所以你只要需要将$/定义为fastq格式的分隔符就ok了。
但是,如果是Python呢?(容易钻牛角尖的孩纸,又或者是不喜欢花括号的孩子…..反正就是强行高端了)。终于要进入正题了,OK,在python中又有两种方式解决这个问题,看你个人喜好选择了(当然要是有大神知道四种、五种方法,也不妨指导一下我这个小菜鸟)。
方案一的代码:
import_pyio importio importfunctools classMyTextWrapper(_pyio.TextIOWrapper): defreadrecod(self,sep): readnl,self._readnl=self._readnl,sep self._readtranslate=False self._readuniversal=False try: returnself.readline() finally: self._readnl=readnl #classMyTextWrapper(_pyio.TextIOWrapper): #def__init__(self,*args,separator,**kwargs): #super().__init__(*args,**kwargs) #self._readnl=separator #self._readtranslate=False #self._readuniversal=False #print("{}:\t{}".format(self,self._readnl)) f=io.open('data',mode='rt') #f=MyTextWrapper(f.detach(),separator='>') #print(f._readnl) f=MyTextWrapper(f.detach()) records=iter(functools.partial(f.readrecod,'>'),'') forrinrecords: print(r.strip('>')) print("###")
Ok,这是Python3.x中的方法(亲测),那么在Python2.x中需要改动的地方,目测好像是(没有亲测)
super(MyTextWrapper,self).__init__(*args,**kwargs)
这个方法看上去还是比较elegant,但是efficient吗?答案恐怕并不,毕竟放弃了C模块的速度优势,但是OOP写起来还是比较舒服的。对了值得指出的Python的I/O是一个layer一个layer的累加起来的。从这里我们就能看出来。当然里面的继承关系还是值得研究一下的,从最开始的IOBase一直到最后的TextIOWrapper,这里面的故事,还是要看一看的。
方案二的代码:
#!/usr/bin/envpython defdelimited(file,delimiter='\n',bufsize=4096): buf='' whileTrue: newbuf=file.read(bufsize) ifnotnewbuf: yieldbuf return buf+=newbuf lines=buf.split(delimiter) forlineinlines[:-1]: yieldline buf=lines[-1] withopen('data','rt')asf: lines=delimited(f,'>',bufsize=1) forlineinlines: printline, print'######'
Ok,这里用到了所谓的generator函数,优雅程度也还行,至于效率么,请自行比较和测试吧(毕竟好多生物程序猿是不关心效率的…..)。如此一来,比Perl多敲了好多代码,唉,怀念Perl的时代啊,简单粗暴有效,就是幸福的哲学么。
当然还有童鞋要问,那么能不能又elegant还efficient(我可是一个高端的生物程序猿,我要强行高端!)答案是有的,请用Cython!问题又来了,都Cython了,为什么不直接用C呢?确实,C语言优美又混乱。
补充知识:Python.json.常见两个错误处理(Expecting,delimiter)(Invalidcontrolcharacterat)
ValueError:Invalidcontrolcharacterat:line1column122(char123)
出现错误的原因是字符串中包含了回车符(\r)或者换行符(\n)
解决方案:
转义
json_data=json_data.replace('\r','\\r').replace('\n','\\n')
使用关键字strict
json.loads(json_data,strict=False)
ValueError:Expecting,delimiter:line13column650(char4186)
原因:json数据不合法,类似“group_buy_create_description_text”:“1.Selecttheblue“Buy”buttontoletothershoppersbuywithyou.这样的内容出现在json数据中。
解决方案:
将类似的情形通过正则筛选出来通过下面的方式处理。
正则表达式如下:
json_data=json_data.replace('""','"########"')
js_str='"[\s\S]+?":\s?"([\s\S]+?)"\}?\}?\]?,'
后续使用中发现无法匹配value为空的情况,故先做一下预处理
这个正则可以匹配到大部分的key,value中的value值,但是也有例外,暂时的处理方法是如果匹配结果中包含”{“,“}”,“[“,“]”这样的字符,说明是匹配失败结果,跳过处理。其他的使用下边的方法替换掉可能出问题的字符。
如果大家有更好的正则匹配方式,欢迎随时批评指正。
defhtmlEscape(input){ ifnotinput returninput; input=input.replace("&","&"); input=input.replace("<","<"); input=input.replace(">",">"); input=input.replace(""," "); input=input.replace("'","'");//IE暂不支持单引号的实体名称,而支持单引号的实体编号,故单引号转义成实体编号,其它字符转义成实体名称 input=input.replace("\"",""");//双引号也需要转义,所以加一个斜线对其进行转义 input=input.replace("\n","
");//不能把\n的过滤放在前面,因为还要对<和>过滤,这样就会导致
失效了 returninput; }
以上这篇使用Python文件读写,自定义分隔符(customdelimiter)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。