如果字符串是换行符,如何删除字符串的最后一个字符?
"abc\n" --> "abc"
open()
,您可能不需要显式删除它。
尝试方法 rstrip()
(参见文档 Python 2 和 Python 3)
>>> 'test string\n'.rstrip()
'test string'
默认情况下,Python 的 rstrip()
方法会去除 所有 种尾随空格,而不是像 Perl 对 chomp
所做的那样只去除一个换行符。
>>> 'test string \n \r\n\n\r \n\n'.rstrip()
'test string'
仅去除换行符:
>>> 'test string \n \r\n\n\r \n\n'.rstrip('\n')
'test string \n \r\n\n\r '
除了 rstrip()
,还有方法 strip()
和 lstrip()
。以下是他们三个的例子:
>>> s = " \n\r\n \n abc def \n\r\n \n "
>>> s.strip()
'abc def'
>>> s.lstrip()
'abc def \n\r\n \n '
>>> s.rstrip()
' \n\r\n \n abc def'
我会说在没有尾随换行符的情况下获取行的“pythonic”方法是 splitlines()。
>>> text = "line 1\nline 2\r\nline 3\nline 4"
>>> text.splitlines()
['line 1', 'line 2', 'line 3', 'line 4']
splitlines()
。如果我给它一个多line 字符串,我不希望它只剥离最后一行,因为我确实告诉它在换行符处将我的多行字符串拆分为多个字符串; ) 使用它从单行字符串中去除行尾实际上只是一个有用的极端情况。
去除行尾 (EOL) 字符的规范方法是使用字符串 rstrip() 方法删除任何尾随 \r 或 \n。以下是 Mac、Windows 和 Unix EOL 字符的示例。
>>> 'Mac EOL\r'.rstrip('\r\n')
'Mac EOL'
>>> 'Windows EOL\r\n'.rstrip('\r\n')
'Windows EOL'
>>> 'Unix EOL\n'.rstrip('\r\n')
'Unix EOL'
使用 '\r\n' 作为 rstrip 的参数意味着它会去掉 '\r' 或 '\n' 的任何尾随组合。这就是为什么它在上述所有三种情况下都有效。
这种细微差别在极少数情况下很重要。例如,我曾经必须处理一个包含 HL7 消息的文本文件。 HL7 标准要求尾随 '\r' 作为其 EOL 字符。我使用此消息的 Windows 机器附加了它自己的 '\r\n' EOL 字符。因此,每一行的结尾看起来像 '\r\r\n'。使用 rstrip('\r\n') 会删除整个 '\r\r\n' 这不是我想要的。在这种情况下,我只是简单地切掉了最后两个字符。
请注意,与 Perl 的 chomp
函数不同,这将删除字符串末尾的所有指定字符,而不仅仅是一个:
>>> "Hello\n\n\n".rstrip("\n")
"Hello"
os.linesep
,其中包含当前操作系统的 EOL 序列。
\n
和 \r
请注意, rstrip 的行为与 Perl 的 chomp() 不完全相同,因为它不修改字符串。也就是说,在 Perl 中:
$x="a\n";
chomp $x
导致 $x
为 "a"
。
但在 Python 中:
x="a\n"
x.rstrip()
将意味着 x
的值是 still "a\n"
。即使 x=x.rstrip()
也不总是给出相同的结果,因为它会从字符串末尾删除所有空格,而最多不只是一个换行符。
我可能会使用这样的东西:
import os
s = s.rstrip(os.linesep)
我认为 rstrip("\n")
的问题在于您可能希望确保行分隔符是可移植的。 (有传言说一些过时的系统使用 "\r\n"
)。另一个问题是 rstrip
将去除重复的空格。希望 os.linesep
将包含正确的字符。以上对我有用。
rstrip('\r\n')
相同,并且 rstrip()
将删除参数中的任何字符。
您可以使用 line = line.rstrip('\n')
。这将从字符串末尾删除所有换行符,而不仅仅是一个。
s = s.rstrip()
将删除字符串 s
末尾的所有换行符。需要赋值,因为 rstrip
返回一个新字符串而不是修改原始字符串。
"line 1\nline 2\r\n...".replace('\n', '').replace('\r', '')
>>> 'line 1line 2...'
或者你总是可以用正则表达式变得更怪异
.replace('\n|\r', '')
?
import re
re.sub('\n|\r', '', '\nx\n\r\n')
==> 'x'
。
这将完全复制 perl 的 chomp (减去数组上的行为)用于 "\n" 行终止符:
def chomp(x):
if x.endswith("\r\n"): return x[:-2]
if x.endswith("\n") or x.endswith("\r"): return x[:-1]
return x
(注意:它不会修改字符串 'in place';它不会去除多余的尾随空格;考虑到 \r\n)
你可以使用条带:
line = line.strip()
演示:
>>> "\n\n hello world \n\n".strip()
'hello world'
在很多层面上,rstrip 与 chomp 不同。阅读 http://perldoc.perl.org/functions/chomp.html,发现 chomp 确实非常复杂。
但是,我的主要观点是 chomp 最多删除 1 行结尾,而 rstrip 将尽可能多地删除。
在这里,您可以看到 rstrip 删除了所有换行符:
>>> 'foo\n\n'.rstrip(os.linesep)
'foo'
使用 re.sub 可以更接近典型的 Perl chomp 用法,如下所示:
>>> re.sub(os.linesep + r'\Z','','foo\n\n')
'foo\n'
小心 "foo".rstrip(os.linesep)
:这只会为您的 Python 正在执行的平台选择换行符。想象一下,你正在 Linux 下修改 Windows 文件的行,例如:
$ python
Python 2.7.1 (r271:86832, Mar 18 2011, 09:09:48)
[GCC 4.5.0 20100604 [gcc-4_5-branch revision 160292]] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os, sys
>>> sys.platform
'linux2'
>>> "foo\r\n".rstrip(os.linesep)
'foo\r'
>>>
正如 Mike 上面所说,改用 "foo".rstrip("\r\n")
。
chomp
不同。
example in Python's documentation 只使用 line.strip()
。
Perl 的 chomp
函数从字符串末尾删除一个换行序列,前提是它确实存在。
下面是我计划在 Python 中执行此操作的方法,如果 process
在概念上是我需要的函数,以便对该文件中的每一行执行一些有用的操作:
import os
sep_pos = -len(os.linesep)
with open("file.txt") as f:
for line in f:
if line[sep_pos:] == os.linesep:
line = line[:sep_pos]
process(line)
import re
r_unwanted = re.compile("[\n\t\r]")
r_unwanted.sub("", your_text)
如果您的问题是清理多行str对象(oldstr)中的所有换行符,您可以根据分隔符'\n'将其拆分为一个列表,然后将此列表加入一个新的str(newstr)中。
newstr = "".join(oldstr.split('\n'))
我发现能够通过 in 迭代器获取 chomped 行很方便,这与从文件对象获取 unchomped 行的方式平行。您可以使用以下代码执行此操作:
def chomped_lines(it):
return map(operator.methodcaller('rstrip', '\r\n'), it)
示例用法:
with open("file.txt") as infile:
for line in chomped_lines(infile):
process(line)
operator.methodcaller
和 map
(Py2 上的 itertools.imap
),您可以将这项工作推送到 C 层,避免 Python 级别的生成器代码(因此运行速度更快,尽管 I/O 开销可能会被掩盖小收益):for line in map(operator.methodcaller('rstrip', '\r\n'), infile):
。它仍然可以被分解为 def chomped_lines(it): return map(operator.methodcaller('rstrip', '\r\n'), it)
。
我正在从我之前在另一个答案的评论中发布的一个基于正则表达式的答案中冒泡。我认为使用 re
是比 str.rstrip
更清晰、更明确的解决方案。
>>> import re
如果要删除一个或多个尾随换行符:
>>> re.sub(r'[\n\r]+$', '', '\nx\r\n')
'\nx'
如果您想在任何地方删除换行符(不仅仅是尾随):
>>> re.sub(r'[\n\r]+', '', '\nx\r\n')
'x'
如果您只想删除 1-2 个尾随换行符(即 \r
、\n
、\r\n
、\n\r
、\r\r
、\n\n
)
>>> re.sub(r'[\n\r]{1,2}$', '', '\nx\r\n\r\n')
'\nx\r'
>>> re.sub(r'[\n\r]{1,2}$', '', '\nx\r\n\r')
'\nx\r'
>>> re.sub(r'[\n\r]{1,2}$', '', '\nx\r\n')
'\nx'
我有一种感觉,大多数人在这里真正想要的是删除 一个 出现的尾随换行符,\r\n
或 \n
仅此而已。
>>> re.sub(r'(?:\r\n|\n)$', '', '\nx\n\n', count=1)
'\nx\n'
>>> re.sub(r'(?:\r\n|\n)$', '', '\nx\r\n\r\n', count=1)
'\nx\r\n'
>>> re.sub(r'(?:\r\n|\n)$', '', '\nx\r\n', count=1)
'\nx'
>>> re.sub(r'(?:\r\n|\n)$', '', '\nx\n', count=1)
'\nx'
(?:
是创建一个非捕获组。)
(顺便说一句,这 不是 '...'.rstrip('\n', '').rstrip('\r', '')
所做的事情,这对于其他偶然发现此线程的人来说可能不清楚。str.rstrip
尽可能多地去除尾随字符,所以像 {3 这样的字符串} 将导致 foo
的误报,而您可能希望在剥离单个尾随换行后保留其他换行符。)
r'\r?\n$'
跳过非捕获组,即使是您的最终方法。可能更有效,因为正则表达式引擎更难优化交替。另请注意,如果您要多次执行此操作,则预先将表达式 re.compile
一次,然后使用 sub
方法会明显更快(特别是如果您与其他 re
使用混合)编译的正则表达式对象;模块函数是 Python 级别的,首先检查已编译正则表达式的缓存(如果缺少则创建/缓存),然后调用匹配方法;跳过该查找会有所帮助。
\n
,因此您可能希望使用 \Z
而不是 $
(或仅匹配 \r?$
,因为 $
可以在换行符之前隐式匹配在字符串的末尾)。
特殊情况的解决方案:
如果换行符是最后一个字符(就像大多数文件输入的情况一样),那么对于集合中的任何元素,您可以按如下方式进行索引:
foobar= foobar[:-1]
切出你的换行符。
看起来 perl 的 chomp 没有完美的模拟。特别是,rstrip 无法处理像 \r\n
这样的多字符换行符分隔符。但是,splitlines 会执行 as pointed out here。按照 my answer 处理不同的问题,您可以组合 join 和 splitlines 来删除/替换字符串 s
中的所有换行符:
''.join(s.splitlines())
以下内容删除了一个尾随换行符(我相信 chomp 会这样)。将 True
作为 keepends
参数传递给分割线保留分隔符。然后,再次调用 splitlines 以删除最后“行”上的分隔符:
def chomp(s):
if len(s):
lines = s.splitlines(True)
last = lines.pop()
return ''.join(lines + last.splitlines())
else:
return ''
s = '''Hello World \t\n\r\tHi There'''
# import the module string
import string
# use the method translate to convert
s.translate({ord(c): None for c in string.whitespace}
>>'HelloWorldHiThere'
使用正则表达式
s = ''' Hello World
\t\n\r\tHi '''
print(re.sub(r"\s+", "", s), sep='') # \s matches all white spaces
>HelloWorldHi
替换\n,\t,\r
s.replace('\n', '').replace('\t','').replace('\r','')
>' Hello World Hi '
使用正则表达式
s = '''Hello World \t\n\r\tHi There'''
regex = re.compile(r'[\n\r\t]')
regex.sub("", s)
>'Hello World Hi There'
加入
s = '''Hello World \t\n\r\tHi There'''
' '.join(s.split())
>'Hello World Hi There'
>>> ' spacious '.rstrip()
' spacious'
>>> "AABAA".rstrip("A")
'AAB'
>>> "ABBA".rstrip("AB") # both AB and BA are stripped
''
>>> "ABCABBA".rstrip("AB")
'ABC'
"\r\n"
例如:' spacious \n\r\n\r \n\n'.rstrip()
产生 ' spacious'
只需使用:
line = line.rstrip("\n")
或者
line = line.strip("\n")
你不需要任何这些复杂的东西
我们通常会遇到三种类型的行尾:\n
、\r
和 \r\n
。 re.sub
中的一个相当简单的正则表达式,即 r"\r?\n?$"
,能够捕获所有这些。
(我们必须抓住他们,对吗?)
import re
re.sub(r"\r?\n?$", "", the_text, 1)
对于最后一个参数,我们将替换的出现次数限制为一个,在某种程度上模仿 chomp。例子:
import re
text_1 = "hellothere\n\n\n"
text_2 = "hellothere\n\n\r"
text_3 = "hellothere\n\n\r\n"
a = re.sub(r"\r?\n?$", "", text_1, 1)
b = re.sub(r"\r?\n?$", "", text_2, 1)
c = re.sub(r"\r?\n?$", "", text_3, 1)
... 其中 a == b == c
是 True
。
rstrip("\r\n")
包罗万象。试试 print(text_2.rstrip('\r\n'))
。
str.rstrip()
解决了问题。这取决于您有哪些需求。此解决方案专门针对需要删除最后一个 "\n"
、"\r"
或 "\r\n"
而不是全部(如果字符串中有多个 "\n"
)的情况。 re.sub(r"\r?\n?$", "", text_1, 1)
返回 "hellothere\n\n"
,text_1.rstrip("\r\n")
返回 "hellothere"
,这是一个不同的字符串。
str.strip()
是一个包罗万象的问题,有时就是问题所在。
如果您关心速度(假设您有一个冗长的字符串列表)并且您知道换行符的性质,那么字符串切片实际上比 rstrip 更快。一个小测试来说明这一点:
import time
loops = 50000000
def method1(loops=loops):
test_string = 'num\n'
t0 = time.time()
for num in xrange(loops):
out_sting = test_string[:-1]
t1 = time.time()
print('Method 1: ' + str(t1 - t0))
def method2(loops=loops):
test_string = 'num\n'
t0 = time.time()
for num in xrange(loops):
out_sting = test_string.rstrip()
t1 = time.time()
print('Method 2: ' + str(t1 - t0))
method1()
method2()
输出:
Method 1: 3.92700004578
Method 2: 6.73000001907
method1
中,您只是截断最后一个字符,无论如何,在 method2
中,.rstrip()
首先检查字符串的末尾是否包含不需要的字符并将它们截断,只有在找到一些的情况下。请对 method1
中的字符进行一些检查并测试 agin!
这适用于 Windows 和 linux(如果您只寻找 re 解决方案,re sub 有点贵)
import re
if re.search("(\\r|)\\n$", line):
line = re.sub("(\\r|)\\n$", "", line)
re.sub
的地方使用 re.search
?
包罗万象:
line = line.rstrip('\r|\n')
rstrip
不采用正则表达式。 "hi|||\n\n".rstrip("\r|\n")
返回 "hi"
\n
换行。 (在 OS X 之前,MacOS 确实使用\r
作为行分隔符,但在 10 年前就结束了。).strip()
不会改变字符串(可能与不可变字符串有关)。如果不在命令行中,您将需要"string = string.strip()"