python學習:python文件中空格和換行符的捕獲和文本文件的轉存


0. 背景

之前公司的項目中,需要在嵌入式系統中實現一個http的網頁端內容,由於項目歷史遺留問題,公司是采用的將html文件轉成c語言頭文件的方式,每次修改頁面端都需要從新編譯一下程序,非常的繁瑣。

雖然繁瑣,但是因為歷史遺留問題,歷史遺留項目都采用這種方式做后面的升級維護。

入鄉隨俗嘛,用python寫了一個html和h文件互轉的小程序,程序編寫的過程和原理很簡單,以后有時間再另外發帖。(TODO)在此不做深入討論。

程序也很好用,但是最近將公司自己寫的程序使用gitblit本地倉庫的形式進行版本管理后,發現一個致命的問題。就是每次轉換成的h文件和公司歷史遺留的文件進行git diff 時候,滿屏都是不一樣的地方。這咋利於版本控制和驗證呢?

1. 問題分析

究竟是哪里不同呢?后來發現原來我寫的轉換腳本,和公司慣用的html to c腳本有着嚴重不同的地方在於:

公司舊版本程序是:

我轉換的程序是:

git diff 比對文件的時候是會比對空格的,而且是引號的位置不同,所以就是大段的內容是不一樣的。

這怎么辦呢?

這時候正則匹配就派上用場了。

2. 尋找方法

上述問題其實總結起來就是:“引號位置放錯了”。那么怎么知道應該在哪里放置引號呢?博主想到的笨辦法就是在把每行的內容單獨拎出來,然后分成三個部分,空格+內容+空格的方式,然后在組合成 空格+引號 +內容+引號+空格的方式。然后實際上就是提取出來了內容兩邊的東西。

talk is cheap , show codes.

假設我們有一個 test.html 文件:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Document</title>
 6 </head>
 7 <body>
 8     <h1>Hello World</h1>
 9 </body>
10 </html>

我們讀取它的時候,要注意,每行實際在末尾有一個換行符\n

現在我們編寫一個 r.py 腳本

1 import re
2 with open('test.html') as f:
3     lines = f.readlines() # 獲取行列表信息
4     print(lines) # 打印行信息

我們在ipython中執行是這樣的:

1 In [31]: %run r.py
2 ['<!DOCTYPE html>\n', '<html lang="en">\n', '<head>\n', '\t<meta charset="UTF-8"
3 >\n', '\t<title>Document</title>\n', '</head>\n', '<body>\n', '\t<h1>Hello Wor
4 ld</h1>\n', '</body>\n', '</html>']

2,3,4 表示的是每行的信息,和我們上面的 test.html 文件是一致的。

將上面的列表整理一下:

 1 # 整理列表
 2 [
 3 '<!DOCTYPE html>\n',
 4 '<html lang="en">\n',
 5 '<head>\n', 
 6 '\t<meta charset="UTF-8">\n',
 7 '\t<title>Document</title>\n',
 8 '</head>\n', '<body>\n',
 9 '\t<h1>Hello World</h1>\n', 
10 '</body>\n', '</html>'
11 ]

可以看出,我們就是逐行打印了文件內容而已:

拿第6行舉例,我們需要匹配到\t 和 \n 並在合適的地方加上引號,程序就over了。

查閱正則內容(菜鳥教程Python正則表達式章節),可知道 \s 可以匹配任意空白字符。

於是,我們用行6字符串測試一下我們的處理代碼對不對:

In [54]: s = re.search(r'^(\s*)(.*)(\s*)$','\t"<title>Document</title>"\n')

In [55]: s.group()
Out[55]: '\t"<title>Document</title>"\n'

In [56]: s.group(0)
Out[56]: '\t"<title>Document</title>"\n'

In [57]: s.group(1)
Out[57]: '\t'

In [58]: s.group(2)
Out[58]: '"<title>Document</title>"'

In [59]: s.group(3)
Out[59]: '\n'

測試和之前的想法是一致的。括弧括起來的內容被捕獲出來。

3. 解決問題

由此,上述問題基本已經找到解決的頭緒,那么定下代碼編寫的流程:

  1. 讀取讀文件
  2. 行列表信息行處理
  3. 讀取寫文件
  4. 寫入處理后的行列表信息

於是編寫代碼:

1 import re # 引入正則庫
2 with open('test.html') as f: # 讀取讀文件
3     lines = f.readlines() # 讀取行信息
4     r = r'^(\s*)(.*)(\s*)$' # 正則
5     lines = [re.search(r,l).group(1) +'"'+ re.search(r,l).group(2)+'\\n"'+re.search(r,l).group(3) for l in lines] # 處理行信息
6     with open('test.h','w+') as f2: # 讀取寫文件
7         f2.writelines(lines) # 寫入行信息

其中第4行就是我們處理行信息的過程,這里用了一個列表推導式

所謂列表推導式,就是一種for循環的簡寫形式,可以從一個列表,經過一定的變換,快速生成一個列表。例如:

In[1]   :  a = [1,2,3,4]
In[2]   :  print(a)
Out[1]  :  [1,2,3,4]

In[3]   :  print([i for i in a])
Out[2]  :  [1,2,3,4]

In[4]   :  print([i*2+1 for i in a])
Out[3]  :  [3,5,7,9]

也就是,前面第4行的程序實際上就是將lines的數據單個處理,在捕獲內容中加入一些我們需要的字符,比如是雙引號,然后組成了新的列表。寫入到文件中。

問題解決。

4. 總結

這個測試腳本的重點就在於正則的捕獲,正則捕獲在文本文件、字符串處理中使用廣泛,需要不斷積累和總結,方能領悟其中的妙用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM