網站首頁 編程語言 正文
背景
一次工作中,我需要完成某個文件的字符串替換。
需求是這樣的:文件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
相關推薦
- 2022-07-03 TypeScript 變量聲明 —— 類型斷言
- 2022-04-22 Golang開發中常見錯誤以及注釋、規范代碼風格
- 2022-12-28 React?Server?Component混合式渲染問題詳解_React
- 2022-04-09 Object 轉Map,Map轉Object方式總結
- 2022-10-12 Matlab實現好看的配對箱線圖的繪制_C 語言
- 2022-06-22 golang?API請求隊列的實現_Golang
- 2024-03-20 spring-boot-maven-plugin報紅的解決辦法
- 2023-07-04 ES聚合查詢+條件搜索的實現
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支