日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Python?RawString與open文件的newline換行符遇坑解決_python

作者:HullQin ? 更新時間: 2022-11-25 編程語言

背景

一次工作中,我需要完成某個文件的字符串替換。

需求是這樣的:文件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 即 \r\n,Unix 是 LF 即\n,舊版 Macintosh 是 CR 即\r

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

  • 讀取文件時,自動把文本中的各種換行符統一轉換為"\n"
  • 寫入文件時,根據當前的操作系統,自動把"\n"轉換為對應的換行符,通過os.linesep可以查看當前操作系統換行符。

當然,你也可以主動設置 newline 參數:

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

注意,newline 參數只對文本文件有效,如果是二進制讀寫,newline 是無用的。

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

原文鏈接:https://juejin.cn/post/7154026867333267492

欄目分類
最近更新