如何从列表元素中移除 \n?

97 投票
15 回答
420455 浏览
提问于 2025-04-16 04:55

我正在尝试让Python从一个.txt文件中读取一行,并把这一行的元素放到一个列表里。文件里的元素是用制表符分开的,所以我用了split("\t")来分隔这些元素。因为这个.txt文件里有很多元素,所以我把每一行找到的数据保存到了一个单独的列表里。

我现在遇到的问题是,列表显示成这样:

['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3\n']

我该怎么做才能把列表最后一个元素中的\n去掉,让它变成'7.3'呢?

15 个回答

11

听起来你想要的功能类似于 Perl 里的 chomp() 函数。

在 Python 中实现这个功能非常简单:

def chomp(s):
    return s[:-1] if s.endswith('\n') else s

... 前提是你使用的是 Python 2.6 或更高版本。如果不是的话,可以用稍微复杂一点的方法:

def chomp(s):
    if s.endwith('\n'):
        return s[:-1]
    else:
        return s

如果你想要去掉字符串末尾的所有换行符(在某些奇怪的情况下,可能会有多个换行符):

def chomps(s):
    return s.rstrip('\n')

显然,正常情况下,Python 文件对象的 readline()readlines() 方法不会返回这样的字符串。

我见过有人盲目地从文件 readline() 和类似函数的结果中去掉最后一个字符(用 s[:-1] 切片)。这其实是个坏主意,因为如果文件的最后一行不是以换行符结束,这样做会导致错误。

一开始,你可能会觉得随意去掉读取行的最后字符是安全的。如果你用普通的文本编辑器创建测试文件,大多数编辑器会在最后一行的末尾默默添加一个换行符。要创建一个有效的测试文件,可以用类似下面的代码:

f = open('sometest.txt', 'w')
f.write('some text')
f.close()

... 然后如果你重新打开这个文件,使用 readline()readlines() 方法读取,你会发现文本是没有末尾换行符的。

很多年来,文本文件以非换行符结尾的问题一直困扰着许多 UNIX 工具和脚本语言。这是一个愚蠢的边缘案例错误,时不时会出现在代码中,虽然不常见,但足以让人烦恼。我们可以争论说,没有最终换行符的“文本”文件是“损坏的”或不标准的;这在某些编程规范中可能是合理的。

然而,在编码时忽视这些边缘情况是很容易的,而这种无知会在依赖你代码的人身上造成问题。正如我妻子所说:在编程时……要注意安全!

73

从Python3开始

在Python3中,map不再返回一个list,而是返回一个mapObject,所以结果看起来会像这样:

>>> map(lambda x:x.strip(),l)
<map object at 0x7f00b1839fd0>

你可以在Python 3.0的新特性中了解更多信息。

map()filter()返回的是迭代器。如果你真的需要一个list,可以用list(map(...))来快速解决。

那么现在有哪些方法可以解决这个问题呢?


案例1 - 用lambdamap调用

map返回一个迭代器list是一个可以把迭代器转换成列表的函数。因此你需要在map外面加一个list的调用。这样答案就变成了:

>>> l = ['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3\n']
>>> list(map(lambda x:x.strip(),l))
['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3']

很好,我们得到了输出。现在我们来检查这段代码执行所需的时间。

$ python3 -m timeit "l = ['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3\n'];list(map(lambda x:x.strip(),l))"
100000 loops, best of 3: 2.22 usec per loop

2.22微秒。这还不错。但有没有更高效的方法呢?


案例2 - 不用lambdamap调用

在Python社区中,很多人对lambda并不太喜欢(包括Guido)。此外,它会大大降低程序的速度。因此我们尽量避免使用它。这里可以使用顶层函数str.strip来帮助我们。

可以不使用lambda,用str.strip重写map,如下:

>>> list(map(str.strip,l))
['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3']

现在来看看时间。

$ python3 -m timeit "l = ['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3\n'];list(map(str.strip,l))"
1000000 loops, best of 3: 1.38 usec per loop

太棒了。你可以看到这两种方法之间的效率差异。它快了近60%。因此,不使用lambda的方法在这里是更好的选择。


案例3 - 遵循指南,常规方法

来自Python 3.0的新特性的另一个重要点是建议我们尽量避免使用map

特别棘手的是为了函数的副作用而调用map();正确的做法是使用常规的for循环(因为创建一个列表只是浪费)。

所以我们可以通过使用常规的for循环来解决这个问题。

最简单的解决方法(暴力法)是:

>>> l = ['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3\n']
>>> final_list = []
>>> for i in l:
...     final_list.append(i.strip())
... 
>>> final_list
['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3']

时间设置

def f():
    l = ['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3\n']
    final_list = []
    for i in l:
         final_list.append(i.strip())
import timeit
print(min(timeit.repeat("f()","from __main__ import f")))

结果是。

1.5322505849981098

如你所见,暴力法在这里稍微慢一点。但对于普通程序员来说,它比map的写法更易读。


案例4 - 列表推导式

这里也可以使用列表推导式,和Python2中的用法一样。

>>> [i.strip() for i in l]
['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3']

现在来看时间:

$ python3 -m timeit "l = ['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3\n'];[i.strip() for i in l]"
1000000 loops, best of 3: 1.28 usec per loop

如你所见,列表推导式比map(即使不使用lambda)更有效。因此,在Python3中,使用列表推导式而不是map是一个好规则。


案例5 - 就地修改和空间效率(时间-空间权衡

最后一种方法是在列表内部进行就地修改。这将节省很多内存空间。可以使用enumerate来实现。

>>> l = ['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3\n']
>>> for i,s in enumerate(l):
...     l[i] = s.strip()
... 
>>> l
['Name1', '7.3', '6.9', '6.6', '6.6', '6.1', '6.4', '7.3']

时间结果是1.4806894720022683。不过这种方法在空间上是有效的。


结论

以下是一个时间比较列表(Python 3.4.3和Python 3.5.0)

----------------------------------------------------
|Case| method          | Py3.4 |Place| Py3.5 |Place|
|----|-----------------|-------|-----|-------|-----|
| 1  | map with lambda | 2.22u | 5   | 2.85u | 5   |
| 2  | map w/o lambda  | 1.38u | 2   | 2.00u | 2   |
| 3  | brute-force     | 1.53u | 4   | 2.22u | 4   |
| 4  | list comp       | 1.28u | 1   | 1.25u | 1   |
| 5  | in-place        | 1.48u | 3   | 2.14u | 3   |
----------------------------------------------------

最后要注意,列表推导式是最好的方法,而使用lambdamap是最差的。但再次强调——仅在PYTHON3中

168

如果你只想去掉最后一个元素中的 \n,可以用这个:

t[-1] = t[-1].strip()

如果你想去掉所有元素中的 \n,可以用这个:

t = map(lambda s: s.strip(), t)

你也可以考虑在分割行之前先去掉 \n

line = line.strip()
# split line...

撰写回答