Як я можу видалити нижній рядок?


1688

Що таке еквівалент Python функції Perl chomp, який видаляє останній символ рядка, якщо це новий рядок?


2
Superset: будь-який рядок , а не тільки нового рядка: stackoverflow.com/questions/1038824 / ...
Чіро Сантіллі冠状病毒审查六四事件法轮功

3
Відповідь A + полягає в тому, що якщо це було через забуття open()файлу з відповідним параметром 'newline = ...' для вашої платформи (універсальна підтримка нового рядка), можливо, вам не знадобиться явно видаляти його.
smci

Відповіді:


1868

Спробуйте метод rstrip()(див. Doc Python 2 та Python 3 )

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

rstrip()Метод Python за замовчуванням знімає всі види пробілів, а не один новий рядок, як це робить 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 '

Існують також методи lstrip()та 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
Я не людина Python, тому я не маю відповіді на це, але студія Перла () фактично видаляє роздільник запису вхідних даних з кінця. Це новий рядок про речі Unixy, але він може бути різним (наприклад, Windows), і він може змінюватися. Чи є спосіб видалити це значення лише один раз з кінця рядка?
Брайан d foy

5
Брайан d foy: У Python немає роздільника запису вхідних даних, як awk та Perl.
Пітер Хосей

7
@csde_rats, це неправда: OS X використовує \nдля нових рядків так само, як Unix. (До OS X MacOS використовував \rяк роздільник рядків, але це закінчилося 10 років тому.)
skue

21
@briandfoy Python має вбудовану підтримку універсальних нових рядків (лише під час читання, а не під час написання). Ви відкриваєте файл у режимі "U" або "rU", а потім незалежно від Windows, Linux, Mac, до того моменту, коли текст досягне вашого пітонного коду, будь-який стиль нового рядка буде замінено на "\ n". Див: python.org/dev/peps/pep-0278
бульбашка алькуб'єрре

12
Я збираюся піти вперед і прописати це, тому що я ноб, і я витратив деякий час на питання, чому це не працює. .strip()не змінює рядок (можливо, це має щось спільне з незмінними рядками). Якщо немає в командному рядку, ви захочете"string = string.strip()"
Сценарій Кітті

158

І я б сказав, що "пітонічним" способом отримання рядків без закінчення символів нового рядка є розділові лінії ().

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


146

Канонічним способом позбавлення символів кінця рядка (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, на якій я використовував це повідомлення, додала власний символ \ \ \ \ 'EOL. Тому кінець кожного рядка виглядав як "\ r \ r \ n". Використання rstrip ('\ r \ n') зняло б ціле '\ r \ r \ n', що не те, чого я хотів. У такому випадку я просто нарізав натомість два останні символи.

Зауважте, що на відміну від chompфункції Perl, в кінці рядка буде знято всі вказані символи, а не лише один:

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

7
Зауважте, що сучасні програми Mac OS X використовують \ n. Використовуються лише старі програми Carbon, спочатку написані для Mac OS \ r.
Пітер Хосей

2
Дякуємо за роз’яснення. Звичайно, rstrip ('\ r \ n') все ще працює і в цьому випадку.
Майк

13
Також є os.linesepпослідовність EOL для поточної ОС.
Елі Коллінз

Це найкраща відповідь: він знімає лише нові рядки та робить це правильно для найбільш поширених платформ.
кевінарпе

плюс +1 За використання \nта\r
fechnert

99

Зауважте, що rstrip не працює так само, як Chomp Perl (), оскільки він не змінює рядок. Тобто в Perl:

$x="a\n";

chomp $x

результати в $xбутті "a".

але в Python:

x="a\n"

x.rstrip()

буде означати, що значення досіx є . Навіть не завжди дається однаковий результат, оскільки він позбавляє пробілу всього кінця рядка, а не лише один новий рядок. "a\n"x=x.rstrip()


7
Також strip () видаляє повторювані символи, тоді як chop / chomp видаляє лише один новий рядок
kostmo

50

Я можу використовувати щось подібне:

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

Я думаю, що проблема rstrip("\n")полягає в тому, що ви, ймовірно, хочете переконатися, що роздільник рядків переносний. (за деякими чутками користуються антикваріатні системи "\r\n"). Інша готча - це rstripвикреслити повторний пробіл. Сподіваємось, os.linesepбуде містити правильні символи. вищезазначене працює для мене.


12
Однак це не спрацює, якщо ви намагаєтесь очистити поданий користувачем вміст у веб-програмі. Вміст користувача може надходити з будь-якого джерела і містити будь-які символи нового рядка.
apiguy

2
Добре, за винятком того, що ви можете обробляти "чужі" файли (із старовинних систем) на вашому сучасному ОС.
ChuckCottrill

1
Пам’ятайте також, що якщо ви читаєте файл у текстовому режимі, це також не працюватиме в системі Windows, оскільки контурний символ завжди буде перетворений на '\ n'.
Божевільний фізик

@MadPhysicist Ви праві, що він конвертує його, але він все одно працює, тому що він такий самий, як rstrip('\r\n')і rstrip()буде знімати будь-які символи, які є в аргументі.
dtauxe

41

Ви можете використовувати line = line.rstrip('\n'). Це позбавить усіх нових рядків з кінця рядка, а не лише одного.


35
s = s.rstrip()

видалить усі нові рядки в кінці рядка s. Призначення потрібне, тому що rstripповертає нову рядок замість зміни початкового рядка.


33

Це повторить саме чіп Perl (мінус поведінку на масивах) для термінатора рядка "\ 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

(Примітка: він не змінює рядок "на місці"; він не позбавляє зайвої пробільної області; приймає \ r \ n до уваги)


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

або ви завжди можете отримати geekier за допомогою regexps :)

весело!


Для мене це спрацювало чудово, намагаючись швидко перетворити текстовий файл із закінченнями рядків в один рядок тексту. Я новачок, тож не впевнений, чи є кращий спосіб це зробити, але це спрацювало, дякую! (Стріп, здавалося, працює лише з кінців, а не зсередини)
Стів Кох

2
Чому б просто не використати одну заяву заміни, наприклад .replace('\n|\r', '')?
Doorknob

2
Про всяк випадок, якщо хтось захоче використати ідею від @DoorknobofSnow, це просто невелика зміна для використання модуля регулярного вираження: import re re.sub('\n|\r', '', '\nx\n\r\n')==> 'x'.
Тейлор Едмістон

Використання цієї методики та методів регулярного вираження, як згадується @TaylorEdmiston, має бути правильною відповіддю.
Бхаргав

@Bhargav Я додав відповідь на це питання, грунтуючись на цьому коментарі, як ви запропонували, а також вивчив кілька інших пов'язаних варіантів. Я також уточнив, чому я думаю, що регулярний вираз - це краще рішення цієї проблеми, ніж str.rstrip, оскільки саме для цього використовується більшість відповідей.
Тейлор Едмістон

27

Ви можете використовувати смужку:

line = line.strip()

демонстрація:

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

1
Спробували це рішення, але воно позбавляє провідних заготовок у лінії.
Тарік

@Tarik ви можете використовувати rstrip
Hackaholic

rstrip видалить всю пробільну пробіл, на відміну від chomp, який видаляє лише максимум один новий рядок.
Flimm

20

rstrip не робить те саме, що chomp, на стільки рівнів. Прочитайте http://perldoc.perl.org/functions/chomp.html і переконайтеся, що шипшина справді дуже складна.

Однак моя головна думка полягає в тому, що chomp видаляє максимум 1 рядок, що закінчується, тоді як rstrip видалить стільки, скільки може.

Тут ви можете побачити rstrip видалення всіх нових рядків:

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

Набагато ближче наближення типового використання Perl chomp можна здійснити за допомогою re.sub, як це:

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

2
Кудо, ти єдиний, хто вказав на цю дуже важливу деталь. Однак, як хтось вище зазначав, використання os.linesep не працюватиме, якщо ви читаєте файли з іншої системи. Це може зайняти трохи більше роботи в Python, фактично перевіряючи кінець рядка.
brianmearns

19

Будьте обережні з "foo".rstrip(os.linesep): Це дозволить лише скористатися символами нового рядка для платформи, де виконується ваш Python. Уявіть, що ви перешикуєте рядки файлу Windows під Linux, наприклад:

$ 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")натомість, як говорить Майк вище.


Інша річ, яку слід зазначити, це те, що вона не видаляє максимум один новий рядок, але всі нові рядки, на відміну від chomp.
Flimm

19

Приклад в документації Python просто використовується line.strip().

chompФункція Perl видаляє одну послідовність рядків з кінця рядка, тільки якщо вона є насправді.

Ось як я планую це зробити в 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)

2
Нарешті, відповідь, яка видаляє його лише один раз (як власне балаканина ...) і є ОС портативною!
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

13

Я не програмую в Python, але я натрапив на FAQ на python.org, який виступає за S.rstrip ("\ r \ n") для python 2.2 або пізнішої версії.


10
import re

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

2
Це також видалить пробіл вкладки, який не вимагає оригінального запитання. (Завдяки символу \ t)
NoahR

9

Мені зручно мати змогу отримати з’єднані лінії за допомогою ітератора, паралельно тому, як можна отримати необрізані лінії з файлового об’єкта. Це можна зробити за допомогою наступного коду:

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( itertools.imapна py2) ви можете натиснути цю роботу на рівні 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).
ShadowRanger

8

рішення для вирішення особливих випадків:

якщо символ нового рядка є останнім символом (як це стосується більшості вхідних файлів), то для будь-якого елемента колекції можна проіндексувати наступним чином:

foobar= foobar[:-1]

щоб вирізати ваш новий рядок.


3
Іноді переклад рядки не останній символ, але останні з них, особливо на вікнах, як уже зазначалося.
Cacovsky

8

Якщо ваше питання полягає в тому, щоб очистити всі розриви рядків в об'єкті рядка рядка (oldstr), ви можете розділити його на список відповідно до роздільника '\ n' і потім приєднати цей список до нової str (newstr).

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


7

Схоже, немає ідеального аналога для шипучки Перла . Зокрема, rstrip не може обробляти багатознакові обмежувачі нового рядка, як \r\n. Однак splitlines ж як зазначено тут . Після моєї відповіді на інше запитання, ви можете комбінувати об'єднання та розділові лінії, щоб видалити / замінити всі нові рядки з рядка s:

''.join(s.splitlines())

Далі видаляється рівно один зворотний новий рядок (як я вважаю, Чемп). Переходячи в Trueякості keependsаргументу splitlines зберегти роздільники. Потім ще раз викликаються роздвоєні лінії, щоб видалити роздільники лише на останньому "рядку":

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

7

Я перекидаю свою відповідь на основі регулярного виразу з однієї, яку я опублікував раніше в коментарях іншої відповіді. Я вважаю, що використання 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Стриває якомога більше затяжних символів, тому рядок на зразок foo\n\n\nможе призвести до помилкового позитиву, fooтоді як ви, можливо, захотіли зберегти інші нові рядки після зняття одного останнього.)


Ви можете пропустити групу, яка не захоплює, навіть для вашого остаточного підходу r'\r?\n$'. Напевно, ефективніше, оскільки двигуни регулярного випромінювання мають складніший час оптимізації чергувань. Також зауважте, що якщо ви збираєтеся робити це багато разів, це буде значно швидше (особливо якщо ви переплутаєтесь з іншими способами reвикористання) до re.compileвиразу один раз вперед, тоді використовуйте subметод компільованого об'єкта регулярних виразів ; Функції модуля - рівень Python і спочатку перевіряють кеш на складені регулярні вирази (створення / кешування, якщо вони відсутні), а потім викликають метод відповідності; пропуск цього пошуку допомагає.
ShadowRanger

1
Крім того, бічна примітка: Оскільки ви намагаєтеся \nбезпосередньо відповідати, ви можете скористатись \Zнад $(або просто збігом \r?$, оскільки $неявно може збігатися безпосередньо перед новим рядком в кінці рядка).
ShadowRanger

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

2
@olibre код, який ви пропонуєте, також зніме інші порожні / пробільні символи, які можуть бути не потрібними. Насправді мені потрібно було лише знімати комбінації персонажів еолу. Все ж, дякую, що вказали на це.
Агостіно

4

Просто використовуйте:

line = line.rstrip("\n")

або

line = line.strip("\n")

Вам не потрібно жоден із цих складних речей


2
Зауважте, що це не те саме, що чмокання.
Флейм

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'

З регексом

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'

3

Є три типи лінійних закінчень , які ми зазвичай стикаємося: \n, \rі \r\n. Досить простий регулярний вираз у re.sub, а саме r"\r?\n?$", здатний наздогнати їх усіх.

(І ми повинні їх усіх наздогнати , я прав?)

import re

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

Останнім аргументом ми обмежуємо кількість випадків, замінених на одну, певною мірою імітуючи ченка. Приклад:

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')).
Агостіно

@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"що є іншим рядком.
Internetional

Я намагаюся сказати: str.strip()це вигадка, яка іноді є самою проблемою.
Internetional

1

Якщо ви стурбовані швидкістю (скажімо, у вас є довгий список рядків), і ви знаєте характер char нового рядка, нарізка рядків насправді швидша, ніж 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!
шпигун

Як я вже говорив у вступі до відповіді: Якщо ви знаєте природу знаку нового рядка, то це корисно. Якщо ви цього не зробите так, вам, очевидно, потрібно здійснити якусь перевірку символів - або просто використовувати rstrip. Я не мав на увазі бути «несправедливим» до rstrip, а просто ілюстрував не настільки незначну різницю, яку, можливо, варто врахувати в деяких ситуаціях.
Стівен Міллер

1

Це буде працювати як для Windows, так і для Linux (трохи дорого з перезавантаженням, якщо ви шукаєте лише рішення для переробки)

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


3
Навіщо використовувати re.searchтам, де просто потрібно re.sub?
wjandrea

0

Спочатку розділіть лінії, а потім приєднайте їх будь-яким відомим вам роздільником:

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

повинні працювати як шарм.


-1

Улов усіх:

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

5
rstripне приймає регулярного вираження. "hi|||\n\n".rstrip("\r|\n")повертається"hi"
Flimm
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.