歡迎您光臨本站 註冊首頁

使用Python文件讀寫,自定義分隔符(custom delimiter)

←手機掃碼閱讀     ml5rwbikls @ 2020-07-06 , reply:0

眾所周知,python文件讀取文件的時候所支持的newlines(即換行符),是指定的。這一點不管是從python的doucuments上還是在python的源碼中(作者是參考了python的io版本,並沒有閱讀C版本),都可以看出來:

  if newline is not None and not isinstance(newline, str):   raise TypeError("illegal newline type: %r" % (type(newline),))  if newline not in (None, "", " ", " ", "  "):   raise ValueError("illegal newline value: %r" % (newline,))

 

好吧,問題來了,如果你恰好是個苦逼的生物狗,正在用python處理所謂的fastq格式的測序結果文件,每次只讀一行往往不是你想要的。Ok, 我們也都知道其實這個問題在Perl裡面十分好解決,無非就是重新定義下文件的分割符($/,The input record separator, newline by default. Set undef to read through the end of file.)

  local $/;   # enable "slurp" mode  local $_ = <FH>; # whole file now here  s/ [ 	]+/ /g;

 

簡單粗暴有效!《Programming Perl》開頭的那些關於什麼是happiness定義看來所言非虛,所以你只要需要將$/定義為fastq格式的分隔符就ok了。

但是,如果是Python呢?(容易鑽牛角尖的孩紙,又或者是不喜歡花括號的孩子…..反正就是強行高端了)。終於要進入正題了,OK,在python中又有兩種方式解決這個問題,看你個人喜好選擇了(當然要是有大神知道四種、五種方法,也不妨指導一下我這個小菜鳥)。

方案一的代碼:

  import _pyio  import io  import functools  class MyTextWrapper(_pyio.TextIOWrapper):   def readrecod(self, sep):     readnl, self._readnl = self._readnl, sep     self._readtranslate = False     self._readuniversal = False     try:       return self.readline()     finally:       self._readnl = readnl  #class MyTextWrapper(_pyio.TextIOWrapper):  # def __init__(self, *args, separator, **kwargs):  #  super().__init__(*args,**kwargs)  #  self._readnl = separator  #  self._readtranslate = False  #  self._readuniversal = False  #  print("{}:	{}".format(self,self._readnl))    f = io.open(&#x27;data&#x27;,mode=&#x27;rt&#x27;)  #f = MyTextWrapper(f.detach(),separator = &#x27;>&#x27;)  #print(f._readnl)  f = MyTextWrapper(f.detach())  records=iter(functools.partial(f.readrecod, &#x27;>&#x27;), &#x27;&#x27;)  for r in records:   print(r.strip(&#x27;>&#x27;))   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/env python    def delimited(file, delimiter = &#x27; &#x27;, bufsize = 4096):   buf = &#x27;&#x27;   while True:    newbuf = file.read(bufsize)    if not newbuf:     yield buf     return    buf += newbuf    lines = buf.split(delimiter)    for line in lines[:-1]:     yield line    buf = lines[-1]    with open(&#x27;data&#x27;, &#x27;rt&#x27;) as f:   lines = delimited(f, &#x27;>&#x27;, bufsize = 1)   for line in lines:    print line,    print &#x27;######&#x27;

 

Ok,這裡用到了所謂的generator函數,優雅程度也還行,至於效率麼,請自行比較和測試吧(畢竟好多生物程序猿是不關心效率的…..)。如此一來,比Perl多敲了好多代碼,唉,懷念Perl的時代啊,簡單粗暴有效,就是幸福的哲學麼。

當然還有童鞋要問,那麼能不能又elegant還efficient(我可是一個高端的生物程序猿,我要強行高端!)答案是有的,請用Cython! 問題又來了,都Cython了,為什麼不直接用C呢?確實,C語言優美又混亂。

補充知識:Python.json.常見兩個錯誤處理(Expecting , delimiter)(Invalid control character at)

ValueError: Invalid control character at: line 1 column 122(char 123)

出現錯誤的原因是字符串中包含了回車符( )或者換行符( )

解決方案:

轉義

json_data = json_data.replace(&#x27; &#x27;, &#x27; &#x27;).replace(&#x27; &#x27;, &#x27;
&#x27;)

使用關鍵字strict

json.loads(json_data, strict=False)

ValueError: Expecting , delimiter: line 13 column 650 (char 4186)

原因:json數據不合法,類似“group_buy_create_description_text”: “1. Select the blue “Buy” button to let other shoppers buy with you.這樣的內容出現在json數據中。

解決方案:

將類似的情形通過正則篩選出來通過下面的方式處理。

正則表達式如下:

json_data = json_data.replace(&#x27;""&#x27;, &#x27;"########"&#x27;)

js_str = &#x27;"[sS]+?":s?"([sS]+?)"}?}?]?,&#x27;

後續使用中發現無法匹配value為空的情況,故先做一下預處理

這個正則可以匹配到大部分的key,value中的value值,但是也有例外,暫時的處理方法是如果匹配結果中包含”{“, “}”, “[“, “]”這樣的字符,說明是匹配失敗結果,跳過處理。其他的使用下邊的方法替換掉可能出問題的字符。

如果大家有更好的正則匹配方式,歡迎隨時批評指正。

  def htmlEscape(input) {      if not input        return input;      input = input.replace("&", "&amp;");      input = input.replace("<", "&lt;");      input = input.replace(">", "&gt;");      input = input.replace(" ", "&nbsp;");      input = input.replace("&#x27;", "&#39;");  //IE暫不支持單引號的實體名稱,而支持單引號的實體編號,故單引號轉義成實體編號,其它字符轉義成實體名稱      input = input.replace(""", "&quot;"); //雙引號也需要轉義,所以加一個斜線對其進行轉義      input = input.replace(" ", "<br/>"); //不能把 的過濾放在前面,因為還要對<和>過濾,這樣就會導致<br/>失效了      return input;    }

 

 

                                                     

   


[ml5rwbikls ] 使用Python文件讀寫,自定義分隔符(custom delimiter)已經有228次圍觀

http://coctec.com/docs/python/shhow-post-241474.html