¿Cómo puedo eliminar una nueva línea final?

1689

¿Cuál es el equivalente de Python de la chompfunción de Perl , que elimina el último carácter de una cadena si es una nueva línea?

Georgy
fuente
2
Superconjunto: cualquier cadena en lugar de solo nueva línea: stackoverflow.com/questions/1038824/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
3
La respuesta A + es, si esto se debió a olvidar open()un archivo con el parámetro 'newline = ...' apropiado para su plataforma (soporte universal de nueva línea), es posible que no necesite eliminarlo explícitamente.
smci

Respuestas:

1868

Prueba el método rstrip()(ver doc Python 2 y Python 3 )

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

El rstrip()método de Python elimina de forma predeterminada todo tipo de espacios en blanco al final, no solo una nueva línea como hace Perl chomp.

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

Para quitar solo nuevas líneas:

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

También existen los métodos lstrip()y 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'
Markus Jarderot
fuente
22
No soy una persona de Python, así que no tengo la respuesta a esto, pero el chomp () de Perl en realidad elimina el separador de registro de entrada del final. Esa es una nueva línea en cosas de Unixy, pero puede ser diferente (por ejemplo, Windows) y es mutable. ¿Hay alguna manera de eliminar ese valor solo una vez desde el final de una cadena?
brian d foy
55
brian d foy: Python no tiene un separador de registro de entrada como awk y Perl.
Peter Hosey el
77
@csde_rats, eso no es cierto: OS X usa \npara nuevas líneas como Unix. (Antes de OS X, MacOS hicieron uso \rcomo un separador de línea, pero que terminó hace 10 años.)
skue
21
@briandfoy Python tiene soporte incorporado para líneas nuevas universales (solo al leer, no al escribir). Abre el archivo en modo "U" o "rU", y luego, independientemente de Windows, Linux, Mac, lo que sea, para cuando el texto llegue a su código de Python, cualquier estilo de nueva línea ha sido reemplazado por "\ n". Ver: python.org/dev/peps/pep-0278
AlcubierreDrive
12
Voy a seguir adelante y explicar esto porque soy un novato y me pasé un tiempo preguntándome por qué no estaba funcionando. .strip()no altera la cadena (probablemente tenga algo que ver con cadenas inmutables). Si no está en la línea de comando, querrás"string = string.strip()"
Script Kitty
146

La forma canónica de eliminar los caracteres de fin de línea (EOL) es utilizar el método de cadena rstrip () eliminando cualquier \ r o \ n final. Aquí hay ejemplos para Mac, Windows y personajes 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 eliminará cualquier combinación final de '\ r' o '\ n'. Es por eso que funciona en los tres casos anteriores.

Este matiz es importante en casos raros. Por ejemplo, una vez tuve que procesar un archivo de texto que contenía un mensaje HL7. El estándar HL7 requiere un '\ r' final como su carácter EOL. La máquina de Windows en la que estaba usando este mensaje había agregado su propio carácter '\ r \ n' EOL. Por lo tanto, el final de cada línea se parecía a '\ r \ r \ n'. El uso de rstrip ('\ r \ n') habría eliminado todo el '\ r \ r \ n', que no es lo que quería. En ese caso, simplemente corté los dos últimos caracteres.

Tenga en cuenta que, a diferencia de la chompfunción de Perl , esto eliminará todos los caracteres especificados al final de la cadena, no solo uno:

>>> "Hello\n\n\n".rstrip("\n")
"Hello"
Miguel
fuente
77
Tenga en cuenta que las aplicaciones modernas de Mac OS X usan \ n. Solo las aplicaciones antiguas de Carbon originalmente escritas para Mac OS usan \ r.
Peter Hosey el
2
Gracias por la aclaración. Por supuesto, el rstrip ('\ r \ n') todavía funciona en ese caso también.
Mike
13
También hay os.linesep, que contiene la secuencia EOL para el sistema operativo actual.
Eli Collins el
Esta es la mejor respuesta: solo elimina las nuevas líneas y lo hace correctamente para las plataformas más comunes.
kevinarpe
plus +1 Por usar \ny\r
fechnert
99

Tenga en cuenta que rstrip no actúa exactamente como Chomp () de Perl porque no modifica la cadena. Es decir, en Perl:

$x="a\n";

chomp $x

resulta en $xser "a".

pero en Python:

x="a\n"

x.rstrip()

significará que el valor de xes todavía "a\n" . Even x=x.rstrip()no siempre da el mismo resultado, ya que elimina todos los espacios en blanco desde el final de la cadena, no solo una nueva línea como máximo.

Flimm
fuente
77
Además, strip () elimina los caracteres repetidos, mientras que chop / chomp solo elimina una nueva línea
kostmo el
50

Podría usar algo como esto:

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

Creo que el problema rstrip("\n")es que probablemente querrás asegurarte de que el separador de línea sea portátil. (se rumorea que algunos sistemas anticuados usan "\r\n"). El otro problema es que rstripeliminará los espacios en blanco repetidos. Con suerte os.linesepcontendrá los personajes correctos. Lo anterior funciona para mí.

Jamie
fuente
12
Sin embargo, esto no funcionará si está intentando limpiar el contenido enviado por el usuario en una aplicación web. El contenido del usuario podría provenir de cualquier fuente y contener caracteres de nueva línea.
apiguy el
2
Buen punto, excepto que puede estar procesando archivos 'extraños' (de sistemas anticuados) en su sistema operativo moderno.
ChuckCottrill
1
Tenga en cuenta también que si está leyendo un archivo en modo texto, esto tampoco funcionará en un sistema Windows, porque el carácter final siempre se convertirá a '\ n'.
Físico loco
@MadPhysicist Tienes razón en que sí lo convierte, pero aún funciona porque es el mismo rstrip('\r\n')y rstrip()eliminará todos los caracteres que están en el argumento.
dtauxe
41

Puedes usar line = line.rstrip('\n'). Esto eliminará todas las líneas nuevas desde el final de la cadena, no solo una.

Kiriloff
fuente
35
s = s.rstrip()

eliminará todas las nuevas líneas al final de la cadena s. La asignación es necesaria porque rstripdevuelve una nueva cadena en lugar de modificar la cadena original.

slec
fuente
33

Esto replicaría exactamente el chomp de perl (menos el comportamiento en las matrices) para el terminador de línea "\ 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

(Nota: no modifica la cadena 'en su lugar'; no elimina los espacios en blanco finales adicionales; toma \ r \ n en cuenta)

Forma de vida alienígena
fuente
27
"line 1\nline 2\r\n...".replace('\n', '').replace('\r', '')
>>> 'line 1line 2...'

o siempre puedes ser más geek con regexps :)

¡que te diviertas!

mihaicc
fuente
Esto funcionó muy bien para mí al tratar de convertir rápidamente un archivo de texto con terminaciones de línea en una sola línea de texto. Soy un novato, así que no estoy seguro de si hay una mejor manera de hacerlo, pero funcionó, ¡gracias! (Strip parecía funcionar solo desde los extremos, no internamente)
Steve Koch
2
¿Por qué no usar una sola declaración de reemplazo, como .replace('\n|\r', '')?
tckmn
2
En caso de que alguien más quiera usar la idea de @DoorknobofSnow, es solo un pequeño cambio usar el módulo regex: import re re.sub('\n|\r', '', '\nx\n\r\n')==> 'x'.
Taylor Edmiston
Usar esta técnica y la expresión regular como mencionó @TaylorEdmiston debería ser la respuesta adecuada.
Bhargav
@Bhargav Agregué una respuesta a esta pregunta en base a este comentario, tal como lo sugirió, al tiempo que exploraba algunas otras opciones relacionadas. También aclaré por qué creo que regex es una mejor solución para este problema que str.rstrip, ya que eso es lo que usan la mayoría de las respuestas.
Taylor Edmiston
27

puedes usar strip:

line = line.strip()

manifestación:

>>> "\n\n hello world \n\n".strip()
'hello world'
Adicto al alcohol
fuente
1
Probé esta solución pero quita los espacios en blanco de la línea.
Tarik
@Tarik puedes usar rstrip
Hackaholic
rstrip eliminará todo el espacio en blanco al final, a diferencia de chomp que solo elimina a lo sumo una nueva línea.
Flimm
20

rstrip no hace lo mismo que chomp, en muchos niveles. Lea http://perldoc.perl.org/functions/chomp.html y vea que chomp es muy complejo.

Sin embargo, mi punto principal es que chomp elimina como máximo 1 final de línea, mientras que rstrip eliminará la mayor cantidad posible.

Aquí puede ver rstrip eliminando todas las líneas nuevas:

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

Una aproximación mucho más cercana del uso típico de Perl Chomp se puede lograr con re.sub, así:

>>> re.sub(os.linesep + r'\Z','','foo\n\n')
'foo\n'
ingydotnet
fuente
2
Felicitaciones, eres el único que señaló este detalle tan importante. Sin embargo, como alguien señaló anteriormente, usar os.linesep no funcionará si está leyendo archivos de un sistema diferente. Esto podría tomar un poco más de trabajo en Python, en realidad inspeccionando el final de la línea.
brianmearns
19

Cuidado con "foo".rstrip(os.linesep): Eso solo machacará los caracteres de nueva línea para la plataforma donde se está ejecutando su Python. Imagine que está cambiando las líneas de un archivo de Windows en Linux, por ejemplo:

$ 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 en su "foo".rstrip("\r\n")lugar, como Mike dice anteriormente.

Carlos Valiente
fuente
La otra cosa a tener en cuenta es que no elimina a lo sumo una nueva línea, sino todas las líneas nuevas, a diferencia chomp.
Flimm
19

Un ejemplo en la documentación de Python simplemente usa line.strip().

La chompfunción de Perl elimina una secuencia de salto de línea del final de una cadena solo si realmente está allí.

Aquí es cómo planeo hacer eso en Python, si processconceptualmente es la función que necesito para hacer algo útil en cada línea de este archivo:

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)
minopret
fuente
2
Finalmente, una respuesta que solo lo elimina una vez (como el chomp real ...) y es portátil con sistema operativo.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
13

No programo en Python, pero encontré un FAQ en python.org que abogaba por S.rstrip ("\ r \ n") para python 2.2 o posterior.

Andrew Grimm
fuente
10
import re

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

fuente
2
Esto también eliminará los espacios en blanco de las pestañas, que la pregunta original no solicita. (Debido al carácter \ t)
NoahR
9

Me parece conveniente poder obtener las líneas cortadas a través de un iterador, en paralelo a la forma en que puede obtener las líneas no cortadas de un objeto de archivo. Puedes hacerlo con el siguiente código:

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

Uso de la muestra:

with open("file.txt") as infile:
    for line in chomped_lines(infile):
        process(line)
kuzzooroo
fuente
Nota: Con operator.methodcallery map( itertools.imapen Py2) se puede empujar este trabajo a la capa C, evitando Python código generador de nivel (y con ello correr un poco más rápido, aunque es cierto que I / O es probable sobrecarga de enmascarar pequeñas ganancias): for line in map(operator.methodcaller('rstrip', '\r\n'), infile):. Todavía podría ser factorizado como def chomped_lines(it): return map(operator.methodcaller('rstrip', '\r\n'), it).
ShadowRanger
8

solución alternativa para casos especiales:

si el carácter de nueva línea es el último carácter (como es el caso con la mayoría de las entradas de archivo), entonces, para cualquier elemento de la colección, puede indexar de la siguiente manera:

foobar= foobar[:-1]

para cortar tu personaje de nueva línea.

Chij
fuente
3
A veces, la nueva línea no es un último carácter, sino los últimos, especialmente en ventanas, como otros han señalado.
Cacovsky 01 de
8

Si su pregunta es limpiar todos los saltos de línea en un objeto str de varias líneas (oldstr), puede dividirlo en una lista de acuerdo con el delimitador '\ n' y luego unir esta lista en un nuevo str (newstr).

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

Leozj
fuente
7

Parece que no hay un análogo perfecto para el chomp de Perl . En particular, rstrip no puede manejar delimitadores de nueva línea de caracteres múltiples como \r\n. Sin embargo, splitlines hace lo que se señala aquí . Siguiendo mi respuesta en una pregunta diferente, puede combinar unir y dividir líneas para eliminar / reemplazar todas las nuevas líneas de una cadena s:

''.join(s.splitlines())

Lo siguiente elimina exactamente una nueva línea final (como lo haría chomp, creo). Pasando Truecomo keependsargumento a las líneas divisorias se retienen los delimitadores. Luego, se vuelve a llamar a splitlines para eliminar los delimitadores de la última "línea":

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

Estoy aumentando mi respuesta basada en expresiones regulares de una que publiqué anteriormente en los comentarios de otra respuesta. Creo que usar rees una solución más clara y explícita para este problema que str.rstrip.

>>> import re

Si desea eliminar uno o más caracteres de nueva línea finales :

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

Si desea eliminar caracteres de nueva línea en todas partes (no solo al final):

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

Si desea eliminar sólo 1-2 caracteres salto de línea final (es decir, \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'

Tengo la sensación de que lo que la mayoría de la gente realmente quiere aquí es eliminar solo una ocurrencia de un personaje de nueva línea final, ya sea \r\no \nnada más.

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

(Los ?: objetivo es crear un grupo sin captura).

(Por cierto, esto no es lo '...'.rstrip('\n', '').rstrip('\r', '')que no está claro para otros que se topan con este hilo. str.rstripQuita la mayor cantidad posible de caracteres finales, por lo que una cadena como foo\n\n\nresultaría en un falso positivo foomientras que es posible que haya querido preservar el otras líneas nuevas después de quitar una sola final).

Taylor Edmiston
fuente
Puede omitir el grupo que no captura, incluso para su enfoque final, con la expresión regular r'\r?\n$'. Probablemente más eficiente, ya que los motores regex tienen más dificultades para optimizar las alternancias. También tenga en cuenta que si va a hacer esto muchas veces, será significativamente más rápido (especialmente si se entremezcla con otros reusos) a re.compilela expresión una vez por adelantado, luego use el submétodo del objeto regex compilado; las funciones del módulo son de nivel Python y comprueban primero una memoria caché para expresiones regulares compiladas (creando / almacenando en caché si falta), luego llame al método coincidente; omitir esa búsqueda ayuda.
ShadowRanger
1
Además, nota al margen: dado que está tratando de hacer coincidir \ndirectamente, es posible que desee usar \Zover $(o simplemente hacer coincidir \r?$, ya que $implícitamente puede coincidir justo antes de la nueva línea al final de una cadena).
ShadowRanger
5
>>> '   spacious   '.rstrip()
'   spacious'
>>> "AABAA".rstrip("A")
  'AAB'
>>> "ABBA".rstrip("AB") # both AB and BA are stripped
   ''
>>> "ABCABBA".rstrip("AB")
   'ABC'

fuente
¡El ejemplo que necesitaba! ¡Entonces rstrip ("\ r \ n") eliminará tanto '\ n' como '\ r' en cualquier combinación al final de la línea!
Agostino
@ Agostino No es necesario proporcionar "\r\n"Por ejemplo: ' spacious \n\r\n\r \n\n'.rstrip()produce' spacious'
olibre
2
@olibre el código que sugiere también eliminará otros caracteres en blanco / espacio, que podrían no ser lo que uno necesita. De hecho, solo necesitaba quitar combinaciones de caracteres eol. Aún así, gracias por señalar esto.
Agostino
4

Solo usa :

line = line.rstrip("\n")

o

line = line.strip("\n")

No necesitas nada de estas cosas complicadas

Ayuadame
fuente
2
Tenga en cuenta que esto no es lo mismo 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'

Con expresiones regulares

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

Reemplazar \ n, \ t, \ r

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

Con expresiones regulares

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

con Join

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

Hay tres tipos de finales de línea que normalmente encontramos: \n, \ry \r\n. Una expresión regular bastante simple en re.sub, a saberr"\r?\n?$" , es capaz de atraparlos a todos.

(Y tenemos que atraparlos a todos , ¿estoy en lo cierto?)

import re

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

Con el último argumento, limitamos el número de ocurrencias reemplazadas a una, imitando en cierta medida chomp. Ejemplo:

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)

... donde a == b == cesta True.

internetional
fuente
Ni siquiera necesita expresiones regulares completas. rstrip("\r\n")Es una trampa para todos. Tratar print(text_2.rstrip('\r\n')).
Agostino
@ Agostino: Cierto, dado que str.rstrip()resuelve el problema. Depende de las necesidades que tengas. Esta solución está hecha específicamente para los casos en los que necesita eliminar solo el último "\n", "\r"o "\r\n"no todos (si hay varios "\n"en la cadena). re.sub(r"\r?\n?$", "", text_1, 1)devuelve "hellothere\n\n"y text_1.rstrip("\r\n")devuelve "hellothere"que es una cadena diferente.
internetional
Lo que estoy tratando de decir es: eso str.strip()es un problema general que a veces es el problema.
internetional
1

Si le preocupa la velocidad (digamos que tiene una larga lista de cadenas) y conoce la naturaleza del carácter de nueva línea, el corte de cadenas es en realidad más rápido que rstrip. Una pequeña prueba para ilustrar esto:

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

Salida:

Method 1: 3.92700004578
Method 2: 6.73000001907
Stephen Miller
fuente
Sé que probablemente debería usar "bucles globales" dentro de las funciones, pero esto también funciona.
Stephen Miller
Esta prueba es incorrecta y no es justa. En el momento en method1que está cortando el último carácter, pase lo que pase, en method2las .rstrip()primeras comprobaciones, si el final de la Cadena contiene caracteres no deseados y los corta, solo si se encontraron algunos. ¡Implemente alguna verificación de caracteres method1y pruebe agin!
spky
Como dije en la introducción a la respuesta: Si conoces la naturaleza de la nueva línea char, entonces esto es útil. Si no lo hace, sí, obviamente necesita implementar algún tipo de verificación de caracteres, o simplemente usar rstrip. No quise ser "injusto" para rstrip, sino simplemente ilustrar una diferencia no tan insignificante que puede valer la pena considerar en algunas situaciones.
Stephen Miller,
1

Esto funcionará tanto para Windows como para Linux (un poco caro con re sub si está buscando solo una solución)

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

Venfah Nazir
fuente
3
¿Por qué usar re.searchdonde solo necesitas re.sub?
wjandrea
0

Primero divide las líneas y luego únelas por cualquier separador que quieras:

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

debería funcionar como un encanto.

Azul profundo
fuente
-1

Una trampa para todos:

line = line.rstrip('\r|\n')
usuario4178860
fuente
55
rstripNo toma expresión regular. "hi|||\n\n".rstrip("\r|\n")regresa"hi"
Flimm