【问题标题】:How do I remove a trailing newline?如何删除尾随换行符?
【发布时间】:2010-09-21 11:03:20
【问题描述】:

Perl 的 chomp 函数的 Python 等效项是什么,如果字符串是换行符,它会删除字符串的最后一个字符?

【问题讨论】:

  • 超集:任何字符串,而不仅仅是换行符:stackoverflow.com/questions/1038824/…
  • A+ 的答案是,如果这是由于忘记 open() 一个文件,该文件具有适合您平台的 'newline=...' 参数(通用换行支持),您可能不需要显式删除它。

标签: python newline trailing


【解决方案1】:

试试rstrip()的方法(参见文档Python 2Python 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'

【讨论】:

  • 我不是 Python 人,所以我没有答案,但 Perl 的 chomp() 实际上从末尾删除了输入记录分隔符。这是 Unixy 事物的换行符,但可能不同(例如 Windows)并且它是可变的。有没有办法从字符串的末尾只删除一次该值?
  • brian d foy:Python 没有像 awk 和 Perl 那样的输入记录分隔符。
  • @csde_rats,这不是真的:OS X 像 Unix 一样使用\n 换行。 (在 OS X 之前,MacOS 确实使用\r 作为行分隔符,但在 10 年前就结束了。)
  • @briandfoy Python 内置了对通用换行符的支持(仅在读取时,而不是在写入时)。您以“U”或“rU”模式打开文件,然后无论是 Windows、Linux、Mac 等,当文本到达您的 python 代码时,任何样式的换行符都已替换为“\n”。见:python.org/dev/peps/pep-0278
  • 我将继续说明这一点,因为我是菜鸟,我花了一段时间想知道为什么它不起作用。 .strip() 不会改变字符串(可能与不可变字符串有关)。如果不在命令行中,您将需要 "string = string.strip()"
【解决方案2】:

我会说“pythonic”的方式来获取没有尾随换行符的行是 splitlines()。

>>> text = "line 1\nline 2\r\nline 3\nline 4"
>>> text.splitlines()
['line 1', 'line 2', 'line 3', 'line 4']

【讨论】:

【解决方案3】:

去除行尾 (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"

【讨论】:

  • 请注意,现代 Mac OS X 应用程序使用 \n。只有最初为 Mac OS 编写的旧 Carbon 应用程序使用 \r.
  • 感谢您的澄清。当然,rstrip('\r\n') 在这种情况下仍然有效。
  • 还有os.linesep,其中包含当前操作系统的EOL序列。
  • 这是最好的答案:它去除换行符,并在最常见的平台上正确执行。
  • 加 +1 用于使用 \n\r
【解决方案4】:

请注意,rstrip 的行为与 Perl 的 chomp() 不完全相同,因为它不会修改字符串。也就是说,在 Perl 中:

$x="a\n";

chomp $x

导致$x 成为"a"

但在 Python 中:

x="a\n"

x.rstrip()

将意味着x 的值是仍然 "a\n"。即使x=x.rstrip() 也不总是给出相同的结果,因为它会从字符串的末尾删除所有空格,而最多不只是一个换行符。

【讨论】:

  • 另外,strip() 删除重复的字符,而chomp/chomp 只删除一个换行符
【解决方案5】:

我可能会使用这样的东西:

import os
s = s.rstrip(os.linesep)

我认为rstrip("\n") 的问题在于您可能希望确保行分隔符是可移植的。 (有传言说一些过时的系统使用"\r\n")。另一个问题是rstrip 会去掉重复的空格。希望os.linesep 将包含正确的字符。以上对我有用。

【讨论】:

  • 但是,如果您尝试在 Web 应用程序中清理用户提交的内容,这将不起作用。用户内容可以来自任何来源并包含任何换行符。
  • 好点,但您可能正在现代操作系统上处理“外来”文件(来自过时的系统)。
  • 还要记住,如果您以文本模式读取文件,这在 Windows 系统上也不起作用,因为尾随字符将始终转换为 '\n'。跨度>
  • @MadPhysicist 你是对的,它确实转换了它,但它仍然有效,因为它与 rstrip('\r\n') 相同,rstrip() 将删除参数中的任何字符。
【解决方案6】:

您可以使用line = line.rstrip('\n')。这将删除字符串末尾的所有换行符,而不仅仅是一个。

【讨论】:

    【解决方案7】:
    s = s.rstrip()
    

    将删除字符串s 末尾的所有换行符。需要赋值是因为rstrip 返回一个新字符串而不是修改原始字符串。

    【讨论】:

      【解决方案8】:

      这将完全复制 perl 对 "\n" 行终止符的 chomp(减去数组行为):

      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)

      【讨论】:

        【解决方案9】:
        "line 1\nline 2\r\n...".replace('\n', '').replace('\r', '')
        >>> 'line 1line 2...'
        

        或者你总是可以用正则表达式变得更怪

        【讨论】:

        • 这对我尝试快速将带有行尾的文本文件转换为一行文本非常有用。我是新手,所以不知道是否有更好的方法来做到这一点,但它有效,谢谢! (Strip 似乎只能从末端工作,而不是在内部)
        • 为什么不只使用一个替换语句,比如.replace('\n|\r', '')
        • 以防万一其他人想使用@DoorknobofSnow 的想法,使用正则表达式模块只是一个小改动:import rere.sub('\n|\r', '', '\nx\n\r\n') ==> 'x'
        • 使用@TaylorEdmiston 提到的这个和正则表达式技术应该是正确的答案。
        • @Bhargav 我已根据您的建议根据此评论添加了对此问题的答案,同时还探索了其他一些相关选项。我还澄清了为什么我认为正则表达式比 str.rstrip 更好地解决这个问题,因为这是大多数答案使用的。
        【解决方案10】:

        你可以使用条带:

        line = line.strip()
        

        演示:

        >>> "\n\n hello world \n\n".strip()
        'hello world'
        

        【讨论】:

        • 试过这个解决方案,但它去掉了行中的前导空格。
        • @Tarik 你可以使用 rstrip
        • rstrip 将删除所有尾随空格,不像 chomp 最多只删除一个换行符。
        【解决方案11】:

        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'
        

        【讨论】:

        • 赞,你是唯一指出这个非常重要的细节的人。但是,正如上面提到的那样,如果您从不同的系统读取文件,则使用 os.linesep 将不起作用。这在 Python 中可能需要更多的工作,实际上是检查行尾。
        【解决方案12】:

        小心"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'
        >>>
        

        请改用 "foo".rstrip("\r\n"),正如 Mike 上面所说的那样。

        【讨论】:

        • 另外需要注意的是,它最多不会删除一个换行符,而是所有换行符,不像chomp
        【解决方案13】:

        example in Python's documentation 只使用line.strip()

        Perl 的chomp 函数仅在字符串末尾确实存在时才从字符串末尾删除一个换行序列。

        如果process 在概念上是我需要的函数,以便对该文件中的每一行执行一些有用的操作,那么这就是我计划在 Python 中执行此操作的方法:

        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)
        

        【讨论】:

        • 最后,一个只删除它一次的答案(就像实际的chomp...)并且是操作系统可移植的!
        【解决方案14】:

        我不使用 Python 编程,但我在 python.org 上遇到了一个 FAQ,提倡使用 S.rstrip("\r\n") 用于 python 2.2 或更高版本。

        【讨论】:

          【解决方案15】:
          import re
          
          r_unwanted = re.compile("[\n\t\r]")
          r_unwanted.sub("", your_text)
          

          【讨论】:

          • 这也将删除原始问题不要求的制表符空格。 (由于 \t 字符)
          【解决方案16】:

          如果您的问题是清理多行str对象(oldstr)中的所有换行符,可以根据分隔符'\n'将其拆分为一个列表,然后将该列表加入一个新的str(newstr )。

          newstr = "".join(oldstr.split('\n'))

          【讨论】:

            【解决方案17】:

            我发现能够通过 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.methodcallermap(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)
            【解决方案18】:

            我正在从我之前在另一个答案的 cmets 中发布的一个基于正则表达式的答案中冒泡。我认为使用restr.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 尽可能多地去除尾随字符,所以一个字符串像foo\n\n\n 这样会导致foo 的误报,而您可能希望在去除单个尾随换行符后保留其他换行符。)

            【讨论】:

            • 您可以使用正则表达式 r'\r?\n$' 跳过非捕获组,即使是您的最终方法。可能更有效,因为正则表达式引擎更难优化交替。另请注意,如果您要多次执行此操作,那么在前面使用 re.compile 表达式会明显更快(特别是如果您与其他 re 使用混合),然后使用 sub 方法编译的正则表达式对象;模块函数是 Python 级别的,首先检查已编译正则表达式的缓存(如果缺少则创建/缓存),然后调用匹配方法;跳过该查找会有所帮助。
            • 另外,旁注:由于您尝试直接匹配\n,因此您可能希望使用\Z 而不是$(或者只匹配\r?$,因为@987654349 @ 可以隐式匹配字符串末尾的换行符之前)。
            【解决方案19】:

            特殊情况的解决方案:

            如果换行符是最后一个字符(就像大多数文件输入的情况一样),那么对于集合中的任何元素,您都可以按如下方式进行索引:

            foobar= foobar[:-1]
            

            切掉你的换行符。

            【讨论】:

            • 有时换行符不是 a 最后一个字符,而是最后一个字符,特别是在 Windows 上,正如其他人所指出的那样。
            【解决方案20】:

            似乎 perl 的 chomp 没有完美的模拟。特别是,rstrip 无法处理像 \r\n 这样的多字符换行符分隔符。但是,splitlines 确实是 as pointed out here。 在 my answer 处理不同的问题之后,您可以结合 joinsplitlines 来删除/替换字符串 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 ''
            

            【讨论】:

              【解决方案21】:
              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'
              

              【讨论】:

                【解决方案22】:
                >>> '   spacious   '.rstrip()
                '   spacious'
                >>> "AABAA".rstrip("A")
                  'AAB'
                >>> "ABBA".rstrip("AB") # both AB and BA are stripped
                   ''
                >>> "ABCABBA".rstrip("AB")
                   'ABC'
                

                【讨论】:

                • 我需要的例子!所以 rstrip("\r\n") 将在行尾以任意组合剥离 '\n' 和 '\r' !
                • @Agostino 无需提供"\r\n" 例如:' spacious \n\r\n\r \n\n'.rstrip() 产生' spacious'
                • @olibre 您建议的代码还会去除其他空白/空格字符,这可能不是人们需要的。事实上,我只需要去除 eol 字符的组合。不过,感谢您指出这一点。
                【解决方案23】:

                只需使用:

                line = line.rstrip("\n")
                

                line = line.strip("\n")
                

                你不需要这些复杂的东西

                【讨论】:

                • 请注意,这与 chomp 不同。
                【解决方案24】:

                我们通常会遇到三种类型的行尾:\n\r\r\nre.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 == cTrue

                【讨论】:

                • 您甚至不需要成熟的正则表达式。 rstrip("\r\n") 包罗万象。试试print(text_2.rstrip('\r\n'))
                • @Agostino :是的,因为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() 是一个包罗万象的包罗万象的问题。
                【解决方案25】:

                如果您关心速度(假设您有一个冗长的字符串列表)并且您知道换行符的性质,那么字符串切片实际上比 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 中的字符并进行测试!
                • 正如我在答案介绍中所说:如果您知道换行符的性质,那么这很有用。如果你不这样做,那么是的,你显然需要实现某种字符检查 - 或者只使用 rstrip。我并不是要对 rstrip “不公平”,而只是说明一个在某些情况下可能值得考虑的不那么微不足道的差异。
                【解决方案26】:

                这适用于 windows 和 linux(如果您正在寻找 re 解决方案,re sub 有点贵)

                import re 
                if re.search("(\\r|)\\n$", line):
                    line = re.sub("(\\r|)\\n$", "", line)
                

                【讨论】:

                • 为什么在你只需要re.sub的地方使用re.search
                【解决方案27】:

                一目了然:

                line = line.rstrip('\r|\n')
                

                【讨论】:

                • rstrip 不采用正则表达式。 "hi|||\n\n".rstrip("\r|\n") 返回"hi"
                猜你喜欢
                • 2011-04-01
                • 2016-08-20
                • 1970-01-01
                • 2013-02-10
                • 1970-01-01
                • 1970-01-01
                • 2021-12-29
                • 2016-03-19
                相关资源
                最近更新 更多