首页 > 编程语言 >你不知道的 Python RawString 和 open文件的newline换行符,遇坑折腾半天终于搞定,总结此文!

你不知道的 Python RawString 和 open文件的newline换行符,遇坑折腾半天终于搞定,总结此文!

时间:2022-10-17 12:32:46浏览次数:58  
标签:文件 RawString 遇坑 Python newline 写入 字符串 换行符

背景

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

需求是这样的:文件A有个占位符,需要利用Python3,把占位符替换成文件B的内容。文件都不大,可以一次性读到内存处理。

我想,这不是简单的​​open​​​ ​​read​​​ ​​replace​​​ ​​write​​就搞定了嘛?

结果,还真有点麻烦!

思路

  1. 全量读取文件A,保存到变量templace
  2. 全量读取文件B,保存到变量text
  3. 利用python的​​re.sub​​实现正则替换,保存到新变量result
  4. 把变量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

遇到的问题

文件B内有换行符,也有字符串​​\n​​​,按上文的方式处理后,所有的字符串​​\n​​都变成了换行符!

举个例子,template是​​我是:{}​​​(其中​​{}​​就是占位符),text是下面的文本:

哈哈
哈哈\n哈哈

替换后,如下图所示:

你不知道的 Python RawString 和 open文件的newline换行符,遇坑折腾半天终于搞定,总结此文!_字符串

可以看到,当我打印​​re.sub​​​结果时,所有的​​\n​​​都变成了换行符,字符串​​\n​​消失了!

这的确令人烦躁,本来五分钟可以搞定,结果要花多余的时间处理这个问题。如果你学会了本文,以后都不用再去费脑筋了~

思考过程

一开始遇到这个问题,是在写入文件后发现的,所以并没定位的这么准确,当时跟换行符相关的,我怀疑了以下方面:

  1. 字符串定义没有使用 Raw String(例如​​r'xxx'​​这种方式)。
  2. 正则替换出了问题。
  3. 写入文件时,​​newline​​参数导致。

如果我们能把这3个问题全都弄清楚,以后定位就非常快了!

Raw String

Python中,如果字符串常量的定义前加了个​​r​​,就表示 Raw String 原始字符串。

Raw String 特点在于,字符串常量里的\将不具有转义作用,它仅仅代表它自己。

例如,你定义个普通字符串​​"\n"​​,这个字符串长度其实是1,它只包含了1个换行符,对应的 ASCII 是10。

如果你定义了原始字符串​​"\n"​​​,这个字符串长度就是2,它包含了字符​​\​​​和字符​​n​​。

如果字符串没转义字符,那么 Raw String 跟普通 String 完全一致

转义字符有这些:

你不知道的 Python RawString 和 open文件的newline换行符,遇坑折腾半天终于搞定,总结此文!_后端_02

也就是说​​r'\haha'​​​跟​​'\haha'​​​是完全一致的,因为​​\h​​​不是转义字符,所以这种情况下,没必要加​​r​​。

你不知道的 Python RawString 和 open文件的newline换行符,遇坑折腾半天终于搞定,总结此文!_掘金·日新计划_03

误区:注意引号问题

有一个令人疑惑的点:理论上讲,​​r'\'​​​应该就是​​'\\'​​​,但是当你使用​​r'\'​​时,Python会报错。

这是因为Python在编译时,读取字符串时,如果字符串以单引号开头,遇到​​\'​​​后,不论你是不是Raw String,都会继续认为是字符串,不会把​​'​​当作结束符。估计是一个历史遗留问题。我们只能接受现实。但是其实编译后,​​\​​​和​​'​​又变成了2个字符。

如何证明呢?你给字符后面加个空格,发现它们是相等的:​​r'\ '​​​和​​'\\ '​​​。但是单独的字符​​r'\'​​就报错了。

你不知道的 Python RawString 和 open文件的newline换行符,遇坑折腾半天终于搞定,总结此文!_换行符_04

但是这种情况只有字符串末尾是奇数个​​\​​​时(例如​​r'\'​​​或​​r"\"​​​)才会发生,如果字符串最后一个字符不是​​\​​​,或者字符串最后是连续偶数个​​\​​​,是没问题的,例如​​r"\\"​​可以被合法定义。

你不知道的 Python RawString 和 open文件的newline换行符,遇坑折腾半天终于搞定,总结此文!_后端_05

启发

定义字符串时,如果你是这么定义:​​"哈哈\n哈哈"​​,那么这个字符串长度是5,包含了1个换行符。

如果你是这么定义:​​r"哈哈\n哈哈"​​​,那么这个字符串长度是6,不包含换行符,包含字符​​\​​​和​​n​​。

同样,当你写入文件时,如果是​​f.write('\n')​​​,就表明写入了换行符,但如果是​​f.write(r'\n')​​​,就表明写入了字符串​​"\n"​​。

在正则表达式中,我们通常用 Raw String,但我们依然使用\n表达换行,是因为正则语法中,会把2个连续的字符​\​​n​当作换行符,这是正则表达式库做的转义,而非定义字符串时Python做的转义。

正则替换的问题

这是导致本文问题的根本原因。使用​​re.sub​​​时,所有的字符串​​r"\n"​​都被当作了换行符。

怎么办呢?

只要我们替换前,把原始文件对应的字符串的​​r"\n"​​​都改为​​r"\\n"​​​,手动多加了一次转义符,那么​​re.sub​​​时,就不会把​​r"\n"​​​当作一个整体改成换行符了,反而会把​​r"\\"​​​当作一个整体,替换为字符​​\​​​。这样​​r"\n"​​字符串就保留下来了!当然,其它转义字符,也统统保留下来了。这就是正确的解法了。

open 文件的 newline 参数

with open(filename, 'r', newline=None) as

这个主要是因为不同操作系统的换行符不同,所以有了这个参数。Windows 是 CRLF 即 ​​\r\n​​​,Unix 是 LF 即​​\n​​​,旧版 Macintosh 是 CR 即​​\r​​。

你不知道的 Python RawString 和 open文件的newline换行符,遇坑折腾半天终于搞定,总结此文!_后端_06

通常情况下,我们不需要加这个参数,Python 会自动为我们做这些事情:

  • 读取文件时,自动把文本中的各种换行符统一转换为​​"\n"​​。
  • 写入文件时,根据当前的操作系统,自动把​​"\n"​​​转换为对应的换行符,通过​​os.linesep​​可以查看当前操作系统换行符。

当然,你也可以主动设置 newline 参数:

  • 读取文件时,如果 newline 是空字符串​​''​​,则Python不会做任何自动转换,读到什么就是什么。
  • 读取文件时,如果 newline 是非空字符串,则Python会把换行符转化为这个非空字符串,例如你可以指定为​​'\r'​​​或​​'\r\n'​​或其它。
  • 写入文件时,如果 newline 是空字符串​​''​​,则Python不会做任何自动转换,现在换行符是什么,就写入什么。
  • 写入文件时,如果 newline 是非空字符串,则Python会把​​\n​​​转化为这个非空字符串,例如你可以指定为​​'\r'​​​或​​'\r\n'​​或其它。

注意,​​newline​​​ 参数只对文本文件有效,如果是二进制读写,​​newline​​ 是无用的。

其实,大部分时候我们无需关注这个 ​​newline​​ 参数。

写在最后

我是HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,联系我,交个朋友),转发本文前需获得作者HullQin​授权。我独立开发了《联机桌游合集》​,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋、象棋等游戏,不收费无广告。还独立开发了《合成大西瓜重制版》​。还开发了《Dice Crush》​参加Game Jam 2022。喜欢可以关注我噢~我有空了会分享做游戏的相关技术,会在这2个专栏里分享:《教你做小游戏》、《极致用户体验》。


标签:文件,RawString,遇坑,Python,newline,写入,字符串,换行符
From: https://blog.51cto.com/hullqin/5762213

相关文章

  • python题目:斐波那契数列【杭州多测师】【杭州多测师_王sir】
    分析以下数字的规律,112358132134用Python语言编程实现输出#斐波那契数列l=[]foriinrange(10):ifi==0ori==1:l.append(1)#初始......
  • HelloPython
    #helloworldprint("helloworld")#参数a=100print(a)#条件ifa==98:print("a==98")elifa==88:print("a==88")else:print("a==100")#循环forbb=......
  • Python与Java交互
    介绍Python与Java两种语言互有优势,本文介绍如何把两种语言结合起来。Python调用Java​......
  • Python 之configparser模块
    一、示例'''添加add_section(section)向实例添加一个sectionset(section,option,value)如果给定的部分存在,将给定的选项设置为指定的值optionxform(option......
  • python安装与python、pip的环境变量配置
    进入官网在你常用的搜索引擎中输入python官网然后进入。可直接点击本链接python官网进入;也可在浏览器地址栏输入www.python.org回车进入官网。下载将鼠标放到菜......
  • 本地线上运行python代码
    http://localhost:39093/1、learning.py文件的代码#!/usr/bin/envpython3#-*-coding:utf-8-*-r'''learning.pyAPython3tutorialfromhttp://www.liaox......
  • [oeasy]python0007-调试程序_debug
    ​ 调试程序......
  • 盘点一个Python自动化办公的实战案例
    大家好,我是皮皮。一、前言前几天在Python钻石交流群【Hxy任我肥】问了一个Python自动化办公的问题,提问截图如下:想要的效果是下图这样的:准确来说,这个都不算是问题了,而......
  • python系列13:python中Path常用功能
     1.基本功能 建议使用pathlib模块来处理文件和文件夹,可以跨平台。pathlib提供path对象来操作,包括目录和文件。In[1]:frompathlibimportPathIn[2]:p=Path()In......
  • python学习第三周总结
    文件操作文件的读写模式文件的操作模式文件相关操作文件内光标移动文件内容修改函数前戏函数的语法结构函数的定义和调用函数的分类函数......