首頁 > 軟體

Python RawString與open檔案的newline換行符遇坑解決

2022-10-16 14:01:35

背景

一次工作中,我需要完成某個檔案的字串替換。

需求是這樣的:檔案A有個預留位置,需要利用Python3,把預留位置替換成檔案B的內容。檔案都不大,可以一次性讀到記憶體處理。

我想,這不是簡單的open read replace write就搞定了嘛?

結果,還真有點麻煩!

思路

  • 全量讀取檔案A,儲存到變數templace
  • 全量讀取檔案B,儲存到變數text
  • 利用python的re.sub實現正則替換,儲存到新變數result
  • 把變數result內容寫入檔案A
with open('A', encoding='utf8') as f:
  template = f.read()
with open('B', encoding='utf8') as f:
  text = f.read()
result = re.sub(r'佔位識別符號', text, template, 1)
with open('A', 'w', encoding='utf8') as f:
  f.write(result)

遇到的問題

檔案B內有換行符,也有字串n,按上文的方式處理後,所有的字串n都變成了換行符!

舉個例子,template是我是:{}(其中{}就是預留位置),text是下面的文字:

哈哈
哈哈n哈哈

替換後,如下圖所示:

可以看到,當我列印re.sub結果時,所有的n都變成了換行符,字串n消失了!

這的確令人煩躁,本來五分鐘可以搞定,結果要花多餘的時間處理這個問題。如果你學會了本文,以後都不用再去費腦筋了~

思考過程

一開始遇到這個問題,是在寫入檔案後發現的,所以並沒定位的這麼準確,當時跟換行符相關的,我懷疑了以下方面:

  • 字串定義沒有使用 Raw String(例如r'xxx'這種方式)。
  • 正則替換出了問題。
  • 寫入檔案時,newline引數導致。

如果我們能把這3個問題全都弄清楚,以後定位就非常快了!

Raw String

Python中,如果字串常數的定義前加了個r,就表示 Raw String 原始字串。

Raw String 特點在於,字串常數裡的將不具有跳脫作用,它僅僅代表它自己。

例如,你定義個普通字串"n",這個字串長度其實是1,它只包含了1個換行符,對應的 ASCII 是10。

如果你定義了原始字串"n",這個字串長度就是2,它包含了字元和字元n

如果字串沒跳脫字元,那麼 Raw String 跟普通 String 完全一致

跳脫字元有這些:

也就是說r'haha''haha'是完全一致的,因為h不是跳脫字元,所以這種情況下,沒必要加r

誤區:注意單個字元的引號問題

有一個令人疑惑的點:理論上講,r''應該就是'\',但是當你使用r''時,Python會報錯。

這是因為Python在編譯時,讀取字串時,如果字串以單引號開頭,遇到'後,不論你是不是Raw String,都會繼續認為是字串,不會把'當作結束符。估計是一個歷史遺留問題。我們只能接受現實。

如何證明呢?你給字元后面加個空格,發現它們是相等的:r' ''\ '。但是單獨的字元r''就報錯了。

但是這種情況只有r''r""才會發生,如果字串長度為2,是沒問題的,例如r"\"可以被合法定義。

啟發

定義字串時,如果你是這麼定義:"哈哈n哈哈",那麼這個字串長度是5,包含了1個換行符。

如果你是這麼定義:r"哈哈n哈哈",那麼這個字串長度是6,不包含換行符,包含字元n

同樣,當你寫入檔案時,如果是f.write('n'),就表明寫入了換行符,但如果是f.write(r'n'),就表明寫入了字串"n"

正則替換的問題

這是導致本文問題的根本原因。使用re.sub時,所有的字串r"n"都被當作了換行符。

怎麼辦呢?

只要我們替換前,把原始檔案對應的字串的r"n"都改為r"\n",手動多加了一次跳脫符,那麼re.sub時,就不會把r"n"當作一個整體改成換行符了,反而會把r"\"當作一個整體,替換為字元。這樣r"n"字串就保留下來了!當然,其它跳脫字元,也統統保留下來了。這就是正確的解法了。

open 檔案的 newline 引數

with open(filename, 'r', newline=None) as f:
  f.read()

這個主要是因為不同作業系統的換行符不同,所以有了這個引數。Windows 是 CRLF 即 rn,Unix 是 LF 即n,舊版 Macintosh 是 CR 即r

通常情況下,我們不需要加這個引數,Python 會自動為我們做這些事情:

  • 讀取檔案時,自動把文字中的各種換行符統一轉換為"n"
  • 寫入檔案時,根據當前的作業系統,自動把"n"轉換為對應的換行符,通過os.linesep可以檢視當前作業系統換行符。

當然,你也可以主動設定 newline 引數:

  • 讀取檔案時,如果 newline 是空字串'',則Python不會做任何自動轉換,讀到什麼就是什麼。
  • 讀取檔案時,如果 newline 是非空字串,則Python會把換行符轉化為這個非空字串,例如你可以指定為'r''rn'或其它。
  • 寫入檔案時,如果 newline 是空字串'',則Python不會做任何自動轉換,現在換行符是什麼,就寫入什麼。
  • 寫入檔案時,如果 newline 是非空字串,則Python會把n轉化為這個非空字串,例如你可以指定為'r''rn'或其它。

注意,newline 引數只對文字檔案有效,如果是二進位制讀寫,newline 是無用的。

其實,大部分時候我們無需關注這個 newline 引數。

以上就是Python RawString與open檔案的newline換行符遇坑解決的詳細內容,更多關於Python RawString open檔案 newline換行符的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com