Como posso remover uma nova linha à direita?


1689

Qual é o equivalente em Python da chompfunção Perl , que remove o último caractere de uma string se for uma nova linha?


2
Superset: qualquer cadeia de caracteres em vez de apenas nova linha: stackoverflow.com/questions/1038824/…
Ciro Santilli </ set>

3
A resposta do A + é: se isso ocorreu devido ao esquecimento de open()um arquivo com o parâmetro 'newline = ...' apropriado para sua plataforma (suporte universal à nova linha), talvez você não precise removê-lo explicitamente.
SMCI

Respostas:


1868

Experimente o método rstrip()(consulte a documentação Python 2 e Python 3 )

>>> 'test string\n'.rstrip()
'test string'

O rstrip()método do Python retira todos os tipos de espaços em branco à direita por padrão, não apenas uma nova linha como o Perl faz chomp.

>>> 'test string \n \r\n\n\r \n\n'.rstrip()
'test string'

Para retirar apenas novas linhas:

>>> 'test string \n \r\n\n\r \n\n'.rstrip('\n')
'test string \n \r\n\n\r '

Existem também os métodos lstrip()e strip():

>>> 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'

22
Eu não sou uma pessoa Python, então não tenho a resposta para isso, mas o chomp () do Perl remove o separador de registros de entrada do final. Essa é uma nova linha no Unixy, mas pode ser diferente (por exemplo, Windows) e é mutável. Existe uma maneira de remover esse valor apenas uma vez do final de uma string?
Brian D Foy

5
brian d foy: O Python não possui um separador de registros de entrada como o awk e o Perl.
9788 Peter Hosey

7
@csde_rats, isso não é verdade: o OS X usa \npara novas linhas, assim como o Unix. (Antes do OS X, MacOS fez uso \rcomo um separador de linha, mas que terminou há 10 anos.)
skue

21
O @briandfoy Python possui suporte interno para as novas linhas da Universal (somente ao ler, não ao escrever). Você abre o arquivo no modo "U" ou "rU" e, independentemente do Windows, Linux, Mac, o que for, no momento em que o texto atinge seu código python, qualquer estilo de nova linha foi substituído por "\ n". Veja: python.org/dev/peps/pep-0278
AlcubierreDrive

12
Vou seguir em frente e explicar isso porque sou um noob e passei um tempo me perguntando por que não estava funcionando. .strip()não altera a string (provavelmente tem algo a ver com strings imutáveis). Se não estiver em linha de comando, você vai querer"string = string.strip()"
Script Kitty


146

A maneira canônica de remover os caracteres de fim de linha (EOL) é usar o método string strstrip () removendo qualquer \ r ou \ n à direita. Aqui estão exemplos de caracteres Mac, Windows e 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'

Usar '\ r \ n' como parâmetro para rstrip significa que ele removerá qualquer combinação à direita de '\ r' ou '\ n'. É por isso que funciona nos três casos acima.

Essa nuance é importante em casos raros. Por exemplo, uma vez tive que processar um arquivo de texto que continha uma mensagem HL7. O padrão HL7 requer um '\ r' à direita como seu caractere EOL. A máquina Windows em que eu estava usando esta mensagem anexou seu próprio caractere EOL '\ r \ n'. Portanto, o final de cada linha parecia '\ r \ r \ n'. Usar rstrip ('\ r \ n') teria retirado todo o '\ r \ r \ n', que não era o que eu queria. Nesse caso, simplesmente cortei os dois últimos caracteres.

Observe que, diferentemente da chompfunção do Perl , isso remove todos os caracteres especificados no final da string, não apenas um:

>>> "Hello\n\n\n".rstrip("\n")
"Hello"

7
Observe que os aplicativos modernos do Mac OS X usam \ n. Somente aplicativos antigos do Carbon, originalmente criados para o Mac OS, usam \ r.
9788 Peter Hosey

2
Obrigado pelo esclarecimento. Obviamente, a rstrip ('\ r \ n') ainda funciona nesse caso também.
Mike

13
Há também os.linesep, que contém a sequência EOL para o sistema operacional atual.
Eli Collins

Esta é a melhor resposta: apenas retira novas linhas e o faz corretamente para as plataformas mais comuns.
Kevinarpe

mais +1 Para usar \ne\r
fechnert

99

Note que o rstrip não age exatamente como o chomp () do Perl porque não modifica a string. Ou seja, no Perl:

$x="a\n";

chomp $x

resulta em $xser "a".

mas em Python:

x="a\n"

x.rstrip()

significa que o valor de aindax é . Nem sempre dá o mesmo resultado, pois retira todo o espaço em branco do final da string, e não apenas uma nova linha no máximo. "a\n"x=x.rstrip()


7
Além disso, strip () remove caracteres repetidos, enquanto chop / chomp remove apenas uma nova linha
kostmo

50

Eu poderia usar algo como isto:

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

Acho que o problema rstrip("\n")é que você provavelmente desejará garantir que o separador de linhas seja portátil. (há rumores de que alguns sistemas antiquados "\r\n"). A outra pegadinha é a de rstripremover os espaços em branco repetidos. Esperançosamente os.linesepconterá os caracteres certos. o acima funciona para mim.


12
No entanto, isso não funcionará se você estiver tentando limpar o conteúdo enviado pelo usuário em um aplicativo da web. O conteúdo do usuário pode vir de qualquer fonte e conter caracteres de nova linha.
apiguy

2
Bom ponto, exceto que você pode estar processando arquivos 'estrangeiros' (de sistemas antiquados) no seu sistema operacional moderno.
ChuckCottrill

1
Lembre-se também de que, se você estiver lendo um arquivo no modo de texto, isso também não funcionará no sistema Windows, porque o caractere à direita sempre será convertido em '\ n'.
Mad físico

@ MadPhysicist Você está certo ao convertê-lo, mas ainda funciona porque é o mesmo rstrip('\r\n')e rstrip()removerá todos os caracteres que estão no argumento.
Dtauxe 18/04/19

41

Você pode usar line = line.rstrip('\n'). Isso removerá todas as novas linhas do final da cadeia, não apenas uma.


35
s = s.rstrip()

removerá todas as novas linhas no final da string s. A atribuição é necessária porque rstripretorna uma nova sequência em vez de modificar a sequência original.


33

Isso replicaria exatamente o chomp do perl (menos o comportamento nas matrizes) para o "\ n" terminador de linha:

def chomp(x):
    if x.endswith("\r\n"): return x[:-2]
    if x.endswith("\n") or x.endswith("\r"): return x[:-1]
    return x

(Nota: ele não modifica a string 'in place'; não remove o espaço em branco extra; leva \ r \ n em consideração)


27
"line 1\nline 2\r\n...".replace('\n', '').replace('\r', '')
>>> 'line 1line 2...'

ou você sempre pode ficar mais geek com regexps :)

diverta-se!


Isso funcionou muito bem para mim, tentando transformar rapidamente um arquivo de texto com finais de linha em uma linha de texto. Sou novato, por isso não tenho certeza se existe uma maneira melhor de fazê-lo, mas funcionou, obrigado! (Faixa parecia apenas o trabalho das extremidades, não internamente)
Steve Koch

2
Por que não usar apenas uma instrução de substituição, como .replace('\n|\r', '')?
Tckmn 07/07/2013

2
Caso alguém queira usar a idéia do @DoorknobofSnow, é apenas uma pequena alteração para usar o módulo regex: import re re.sub('\n|\r', '', '\nx\n\r\n')==> 'x'.
Taylor Edmiston

Usar esta técnica e a expressão regular como o @TaylorEdmiston mencionado deve ser a resposta correta.
precisa

@Bhargav Adicionei uma resposta a esta pergunta com base neste comentário, como você sugeriu, enquanto explora algumas outras opções relacionadas. Também esclareci por que acho que o regex é uma solução melhor para esse problema do que str.rstrip, já que é isso que a maioria das respostas usa.
Taylor Edmiston

27

você pode usar strip:

line = line.strip()

demo:

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

1
Tentei esta solução, mas ela remove os espaços em branco da linha.
Tarik 01/03

@Tarik você pode usar RSTRIP
Hackaholic

O rstrip excluirá todo o espaço em branco à direita, ao contrário do chomp, que exclui apenas no máximo uma nova linha.
Flimm

20

O rstrip não faz a mesma coisa que o chomp, em muitos níveis. Leia http://perldoc.perl.org/functions/chomp.html e veja que o chomp é realmente muito complexo.

No entanto, meu ponto principal é que o chomp remove no máximo 1 linha final, enquanto o rstrip remove o máximo possível.

Aqui você pode ver o rstrip removendo todas as novas linhas:

>>> 'foo\n\n'.rstrip(os.linesep)
'foo'

Uma aproximação muito mais próxima do uso típico do Perl chomp pode ser realizada com o re.sub, assim:

>>> re.sub(os.linesep + r'\Z','','foo\n\n')
'foo\n'

2
Parabéns, você é o único que apontou esse detalhe muito importante. No entanto, como alguém mencionado acima, o uso do os.linesep não funcionará se você estiver lendo arquivos de um sistema diferente. Isso pode exigir um pouco mais de trabalho em Python, na verdade, inspecionando o final da linha.
Brianmearns

19

Cuidado com "foo".rstrip(os.linesep): Isso apenas incluirá os caracteres de nova linha da plataforma em que seu Python está sendo executado. Imagine que você está chimping as linhas de um arquivo do Windows no Linux, por exemplo:

$ 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'
>>>

Use "foo".rstrip("\r\n"), como Mike diz acima.


A outra coisa a observar é que ela não remove no máximo uma nova linha, mas todas as novas linhas, ao contrário chomp.
Flimm

19

Um exemplo na documentação do Python simplesmente usa line.strip().

A chompfunção Perl remove uma sequência de quebra de linha do final de uma string apenas se ela estiver realmente lá.

Aqui está como eu planejo fazer isso no Python, se processé conceitualmente a função que eu preciso para fazer algo útil para cada linha deste arquivo:

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)

2
Finalmente, uma resposta que a remove apenas uma vez (como o chomp real ...) e é portátil!
Ciro Santilli

13

Eu não programo em Python, mas me deparei com uma FAQ no python.org defendendo S.rstrip ("\ r \ n") para python 2.2 ou posterior.


10
import re

r_unwanted = re.compile("[\n\t\r]")
r_unwanted.sub("", your_text)

2
Isso também removerá o espaço em branco da guia, que a pergunta original não solicita. (Devido ao caráter \ t)
NoahR

9

Eu acho conveniente poder obter as linhas chomped via iterator, paralelamente à maneira como você pode obter as linhas chomped de um objeto de arquivo. Você pode fazer isso com o seguinte código:

def chomped_lines(it):
    return map(operator.methodcaller('rstrip', '\r\n'), it)

Uso da amostra:

with open("file.txt") as infile:
    for line in chomped_lines(infile):
        process(line)

Nota: Com operator.methodcallere map( itertools.imapem Py2) poderá pressionar este trabalho para a camada C, evitando Python código gerador de nível (e correndo assim um pouco mais rápido, embora reconhecidamente I / O sobrecarga é provável para mascarar pequenos ganhos): for line in map(operator.methodcaller('rstrip', '\r\n'), infile):. Ainda pode ser considerado como def chomped_lines(it): return map(operator.methodcaller('rstrip', '\r\n'), it).
ShadowRanger

8

solução alternativa para caso especial:

se o caractere de nova linha for o último caractere (como é o caso da maioria das entradas de arquivo), para qualquer elemento da coleção, você poderá indexar da seguinte maneira:

foobar= foobar[:-1]

para cortar seu caractere de nova linha.


3
Às vezes, a nova linha não é uma último caractere, mas os últimos, especialmente nas janelas, como outros já fora apontado.
Cacovsky

8

Se sua pergunta é limpar todas as quebras de linha em um objeto de várias linhas str (oldstr), você pode dividi-lo em uma lista de acordo com o delimitador '\ n' e ingressar nessa lista em uma nova str (newstr).

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


7

Parece que não existe um análogo perfeito para o chomp do perl . Em particular, o rstrip não pode lidar com delimitadores de nova linha com vários caracteres, como \r\n. No entanto, as linhas de divisão fazem como indicado aqui . Após minha resposta em uma pergunta diferente, você pode combinar linhas de junção e de divisão para remover / substituir todas as novas linhas de uma sequência s:

''.join(s.splitlines())

O seguinte remove exatamente uma nova linha à direita (como o chomp faria, acredito). Passar Truecomo keependsargumento para linhas de divisão mantém os delimitadores. Em seguida, as linhas de divisão são chamadas novamente para remover os delimitadores apenas na última "linha":

def chomp(s):
    if len(s):
        lines = s.splitlines(True)
        last = lines.pop()
        return ''.join(lines + last.splitlines())
    else:
        return ''

7

Estou borbulhando minha resposta com base em expressões regulares de uma que eu postei anteriormente nos comentários de outra resposta. Eu acho que usar reé uma solução mais clara e explícita para esse problema do que str.rstrip.

>>> import re

Se você deseja remover um ou mais caracteres de nova linha à direita :

>>> re.sub(r'[\n\r]+$', '', '\nx\r\n')
'\nx'

Se você deseja remover os caracteres de nova linha em qualquer lugar (não apenas à direita):

>>> re.sub(r'[\n\r]+', '', '\nx\r\n')
'x'

Se você quiser remover apenas 1-2 caracteres final de linha (ou seja, \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'

Sinto que o que a maioria das pessoas realmente deseja aqui é remover apenas uma ocorrência de um caractere de nova linha à direita, um \r\nou \nmais nada.

>>> 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'

(O ?:objetivo é criar um grupo que não seja de captura.)

(A propósito, isso não é o que '...'.rstrip('\n', '').rstrip('\r', '')faz, o que pode não estar claro para os outros que se deparam com esse encadeamento. str.rstripRetira o máximo possível de caracteres finais; portanto, um encadeamento semelhante foo\n\n\nresultaria em um falso positivo, fooenquanto você pode querer preservar o outras linhas novas após remover uma única linha à direita.)


Você pode pular o grupo de não captura, mesmo para sua abordagem final, com a regex r'\r?\n$'. Provavelmente mais eficiente, já que os mecanismos regex têm mais dificuldade em otimizar alternações. Observe também que, se você fizer isso muitas vezes, será significativamente mais rápido (especialmente se estiver misturando-se a outros reusos) à re.compileexpressão uma vez na frente, e use o submétodo do objeto regex compilado; as funções do módulo estão no nível do Python e verificam primeiro no cache os regexes compilados (criando / armazenando em cache, se estiverem faltando) e depois chame o método correspondente; pular essa pesquisa ajuda.
ShadowRanger

1
Além disso, observe: como você está tentando corresponder \ndiretamente, convém usar \Zover $(ou apenas corresponder \r?$, pois $implicitamente pode corresponder pouco antes da nova linha no final de uma string).
ShadowRanger

5
>>> '   spacious   '.rstrip()
'   spacious'
>>> "AABAA".rstrip("A")
  'AAB'
>>> "ABBA".rstrip("AB") # both AB and BA are stripped
   ''
>>> "ABCABBA".rstrip("AB")
   'ABC'

O exemplo que eu precisava! Portanto, rstrip ("\ r \ n") removerá '\ n' e '\ r' em qualquer combinação no final da linha!
Agostino

@Agostino Não há necessidade de fornecer "\r\n"Por exemplo: ' spacious \n\r\n\r \n\n'.rstrip()produz' spacious'
olibre

2
@olibre o código sugerido também removerá outros caracteres em branco / espaço, que podem não ser o que se precisa. Na verdade, eu só precisava retirar combinações de caracteres eol. Ainda assim, obrigado por apontar isso.
Agostino

4

Apenas use :

line = line.rstrip("\n")

ou

line = line.strip("\n")

Você não precisa de nada disso complicado


2
Observe que isso não é o mesmo que chomp.
Flimm

4
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'

Com regex

s = '''  Hello  World 
\t\n\r\tHi '''
print(re.sub(r"\s+", "", s), sep='')  # \s matches all white spaces
>HelloWorldHi

Substituir \ n, \ t, \ r

s.replace('\n', '').replace('\t','').replace('\r','')
>'  Hello  World Hi '

Com regex

s = '''Hello  World \t\n\r\tHi There'''
regex = re.compile(r'[\n\r\t]')
regex.sub("", s)
>'Hello  World Hi There'

com Join

s = '''Hello  World \t\n\r\tHi There'''
' '.join(s.split())
>'Hello  World Hi There'

3

Existem três tipos de finais de linha que normalmente encontrar: \n, \re \r\n. Uma expressão regular bastante simples re.sub, a saber r"\r?\n?$", é capaz de capturá-los todos.

(E temos que pegá-los todos , estou certo?)

import re

re.sub(r"\r?\n?$", "", the_text, 1)

Com o último argumento, limitamos o número de ocorrências substituídas a uma, imitando o chomp até certo ponto. Exemplo:

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)

... onde a == b == cé True.


Você nem precisa de expressões regulares de pleno direito. rstrip("\r\n")é um catch-all. Tente print(text_2.rstrip('\r\n')).
Agostino

@ Agostino: Verdade, dado que str.rstrip()resolve o problema. Depende de quais necessidades você tem. Essa solução foi criada especificamente para os casos em que você precisa remover apenas o último "\n", "\r"ou "\r\n"mas não todos (se houver vários "\n"na cadeia). re.sub(r"\r?\n?$", "", text_1, 1)retorna "hellothere\n\n"e text_1.rstrip("\r\n")retorna "hellothere"que é uma string diferente.
internetional

O que estou tentando dizer é: esse str.strip()é um problema, às vezes é o mesmo problema.
internetional

1

Se você está preocupado com a velocidade (digamos que você tenha uma lista longa de strings) e conhece a natureza do caractere de nova linha, o fatiamento de strings é realmente mais rápido que o rstrip. Um pequeno teste para ilustrar isso:

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()

Resultado:

Method 1: 3.92700004578
Method 2: 6.73000001907

Eu sei que provavelmente deveria usar "loops globais" dentro das funções, mas isso também funciona.
Stephen Miller

Este teste é errado e não é justo .. Em method1você está apenas cortando o último caractere, não importa o que, method2nas .rstrip()primeiras verificações, se o fim da cadeia contém caracteres indesejados e corta-los, apenas se alguns foram encontrados. Por favor, implemente uma verificação de caracteres method1e teste novamente!
Spky # 24/16

Como eu disse na introdução à resposta: Se você conhece a natureza do caractere de nova linha, isso é útil. Caso contrário, obviamente, você precisará implementar algum tipo de verificação de caractere - ou apenas usar rstrip. Não pretendia ser "injusto" despir-me, mas simplesmente ilustrar uma diferença não tão insignificante que pode valer a pena considerar em algumas situações.
Stephen Miller

1

Isso funcionará tanto para Windows quanto para Linux (um pouco caro com re sub se você estiver procurando apenas uma solução)

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


3
Por que usar re.searchonde você só precisa re.sub?
Wjandrea

0

Primeiro divida as linhas e junte-as a qualquer separador que desejar:

x = ' '.join(x.splitlines())

deve funcionar como um encanto.


-1

Uma captura de todos:

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

5
rstripnão recebe expressão regular. "hi|||\n\n".rstrip("\r|\n")retorna"hi"
Flimm
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.