Что такое Python-эквивалент функции Perl chomp, которая удаляет последний символ строки, если это новая строка?
Ответ A +: если это произошло из-за того, что open() забыл файл с соответствующим параметром 'новая строка = ...' для вашей платформы (универсальная поддержка новой строки), вам, возможно, не нужно явно удалять его.






Попробуйте метод rstrip() (см. Документы Python 2 и Python 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 '
Также существуют методы strip(), 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'
Я не человек Python, поэтому у меня нет ответа на этот вопрос, но функция chomp () Perl фактически удаляет разделитель входных записей с конца. Это новая строка для Unixy, но она может быть другой (например, Windows) и изменчива. Есть ли способ удалить это значение только один раз из конца строки?
brian d foy: Python не имеет разделителя входных записей, как в awk и Perl.
\ N достаточно? >>> "тестовая строка \ r \ n" .rstrip ("\ n") 'тестовая строка \ r'
Сам \ r нигде не запускает новую строку (кроме OSX, но кого волнует OSX?)
@csde_rats, это неправда: OS X использует \n для новой строки, как и Unix. (До OS X MacOS действительно использовала \r в качестве разделителя строк, но это закончилось 10 лет назад.)
@briandfoy Python имеет встроенную поддержку универсальных символов новой строки (только при чтении, а не при записи). Вы открываете файл в режиме «U» или «rU», а затем, независимо от Windows, Linux, Mac, любого другого, к тому времени, когда текст достигнет вашего кода Python, любой стиль новой строки будет заменен на «\ n». См .: python.org/dev/peps/pep-0278
Это удаляет только первые \ n, а не все \ n. Что, если у меня есть строка типа: "sadsa \ nsadas \ nsadsad \ n" Как я могу удалить ВСЕ символы новой строки? replace ('\ n', '') тоже не работает.
На всякий случай, если кто-то неправильно понял пример: аргумент для strip, rstrip, lstrip используется как список символов, а не строка. Итак, 'abcdedcba'.strip("abc") дает def, а не cdedcba!
@skue: А как насчет Windows? Если вы удалите \n, вы все равно получите \r.
@yegle, я думаю, вы имеете в виду «ded», а не «def». :)
@AlixAxel Как указано выше в @AlcubierreDrive, перенос новой строки означает, что они преобразуются в каноническую форму \n при чтении из файла. Тогда ваша программа, работающая со строками, никогда не увидит символы \r.
Я знаю, что это не совсем вопрос, но он поднимается в комментариях. Есть ли причина, по которой text.rstrip(os.linesep) не может работать независимо от ОС для достижения этой цели?
Я собираюсь продолжить и изложить это, потому что я новичок, и я некоторое время задавался вопросом, почему это не работает. .strip() не изменяет строку (вероятно, имеет какое-то отношение к неизменяемым строкам). Если не в командной строке, вам понадобится "string = string.strip()"
rstrip () сам по себе доставит вам много головной боли, если вы обрабатываете TSV с некоторыми пустыми столбцами. Например, "foo \ tbar \ t \ t \ n" .rstrip () удалит последние два пустых столбца из ваших данных.
Необходимо для получения чистых строковых переменных, передаваемых через argparse. Новые строки Windows заставили их вообще не отображаться при конкатенации строк.
Канонический способ удалить символы конца строки (EOL) - использовать строковый метод rstrip (), удаляющий любые завершающие \ r или \ n. Вот примеры символов EOL для Mac, Windows и Unix.
>>> '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 \ n'. Таким образом, конец каждой строки выглядел как '\ r \ r \ n'. Использование rstrip ('\ r \ n') сняло бы весь '\ r \ r \ n', чего я не хотел. В этом случае я просто вырезал последние два символа.
Обратите внимание, что в отличие от функции Perl chomp, это удалит все указанные символы в конце строки, а не только один:
>>> "Hello\n\n\n".rstrip("\n")
"Hello"
Обратите внимание, что современные приложения Mac OS X используют \ n. Только старые приложения Carbon, изначально написанные для Mac OS, используют \ r.
Благодарю за разъяснение. Конечно, в этом случае rstrip ('\ r \ n') все еще работает.
Также существует os.linesep, который содержит последовательность EOL для текущей ОС.
Это лучший ответ: Только удаляет символы новой строки и делает это правильно для наиболее распространенных платформ.
плюс +1 Для использования \n и \r
@Tim: обычно вы не увидите \r на входе, потому что Python по умолчанию использует универсальный режим новой строки ('\n', '\r' или '\r\n' транслируются в '\n' при чтении). Если вы хотите учитывать символы новой строки Unicode; см. str.splitlines().
Голосование за, потому что это намного безопаснее, чем rstrip () без аргументов.
И я бы сказал, что «питонический» способ получить строки без завершающих символов новой строки - это splitlines ().
>>> text = "line 1\nline 2\r\nline 3\nline 4"
>>> text.splitlines()
['line 1', 'line 2', 'line 3', 'line 4']
Обратите внимание, что rstrip не действует точно так же, как chomp () Perl, потому что он не изменяет строку. То есть в Perl:
$x = "a\n";
chomp $x
приводит к тому, что $x является "a".
но в Python:
x = "a\n"
x.rstrip()
будет означать, что значение x равно по-прежнему"a\n". Даже x=x.rstrip() не всегда дает одинаковый результат, поскольку удаляет все пробелы в конце строки, а не только одну строку новой строки.
Кроме того, strip () удаляет повторяющиеся символы, тогда как chop / chomp удаляет только одну новую строку
Я не программирую на Python, но я наткнулся на Часто задаваемые вопросы на python.org, защищающий S.rstrip ("\ r \ n") для python 2.2 или новее.
Я мог бы использовать что-то вроде этого:
import os
s = s.rstrip(os.linesep)
Я думаю, проблема с rstrip("\n") в том, что вы, вероятно, захотите убедиться, что разделитель строк переносимый. (ходят слухи, что некоторые устаревшие системы используют "\r\n"). Другая проблема заключается в том, что rstrip удаляет повторяющиеся пробелы. Надеюсь, os.linesep будет содержать правильные символы. выше работает для меня.
Однако это не сработает, если вы пытаетесь очистить отправленный пользователем контент в веб-приложении. Пользовательский контент может поступать из любого источника и содержать любые символы новой строки.
Хороший момент, за исключением того, что вы можете обрабатывать «чужие» файлы (из устаревших систем) на своей современной ОС.
Также имейте в виду, что если вы читаете файл в текстовом режиме, это не будет работать и в системе Windows, потому что конечный символ всегда будет преобразован в '\ n'.
@MadPhysicist Вы правы в том, что он конвертирует его, но он все еще работает, потому что он такой же, как rstrip('\r\n'), а rstrip() удаляет все символы, которые есть в аргументе.
rstrip не делает то же самое, что chomp, на многих уровнях. Прочтите http://perldoc.perl.org/functions/chomp.html и убедитесь, что chomp действительно очень сложен.
Однако я считаю, что 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'
Престижность, вы единственный, кто указал на эту очень важную деталь. Однако, как уже отмечалось выше, использование os.linesep не будет работать, если вы читаете файлы из другой системы. В Python это может занять немного больше времени, фактически проверяя конец строки.
Осторожно с "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, он удаляет не более одного символа новой строки, а все новые строки.
обходное решение для особого случая:
если символ новой строки является последним символом (как в случае с большинством входных файлов), то для любого элемента в коллекции вы можете индексировать следующим образом:
foobar= foobar[:-1]
чтобы вырезать символ новой строки.
Иногда новая строка - это не последний символ а, а последний, особенно в окнах, как указывали другие.
"line 1\nline 2\r\n...".replace('\n', '').replace('\r', '')
>>> 'line 1line 2...'
или вы всегда можете стать более вызывающим с регулярными выражениями :)
веселиться!
Это отлично сработало для меня, пытаясь быстро превратить текстовый файл с окончанием строки в одну строку текста. Я новичок, поэтому не уверен, есть ли способ лучше, но он сработал, спасибо! (Полоса, казалось, работает только с концов, а не внутри)
Почему бы просто не использовать один оператор замены, например .replace('\n|\r', '')?
На всякий случай, если кто-то еще захочет использовать идею @DoorknobofSnow, это всего лишь небольшое изменение для использования модуля регулярных выражений: import rere.sub('\n|\r', '', '\nx\n\r\n') ==> 'x'.
Использование этого метода и метода регулярных выражений, упомянутого в @TaylorEdmiston, должно быть правильным ответом.
@Bhargav Я добавил ответ на этот вопрос на основе этого комментария, как вы предложили, а также изучил несколько других связанных вариантов. Я также пояснил, почему я считаю, что регулярное выражение - лучшее решение этой проблемы, чем str.rstrip, поскольку это то, что использует большинство ответов.
Вы можете использовать line = line.rstrip('\n'). Это удалит все символы новой строки из конца строки, а не только одну.
Если ваш вопрос состоит в том, чтобы очистить все разрывы строк в многострочном объекте str (oldstr), вы можете разделить его на список в соответствии с разделителем '\ n', а затем присоединить этот список к новому str (newstr).
newstr = "".join(oldstr.split('\n'))
пример в документации Python просто использует line.strip().
Функция Perl chomp удаляет одну последовательность разрыва строки из конца строки, только если она действительно существует.
Вот как я планирую сделать это в 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)
Наконец, ответ, который удаляет только однажды (как настоящий chomp ...) и переносится на ОС!
import re
r_unwanted = re.compile("[\n\t\r]")
r_unwanted.sub("", your_text)
Это также удалит пробелы табуляции, которые не запрашиваются в исходном вопросе. (Из-за символа \ t)
Уловить все:
line = line.rstrip('\r|\n')
rstrip не принимает регулярное выражение. "hi|||\n\n".rstrip("\r|\n") возвращает "hi"вы можете использовать полоску:
line = line.strip()
демо:
>>> "\n\n hello world \n\n".strip()
'hello world'
Пробовал это решение, но оно убирает ведущие пробелы в строке.
@Tarik, вы можете использовать rstrip
rstrip удалит все завершающие пробелы, в отличие от chomp, который удаляет не более одной новой строки.
Я считаю удобным иметь возможность получать обработанные строки через итератор, параллельно с тем, как вы можете получить неотрезанные строки из файлового объекта. Вы можете сделать это с помощью следующего кода:
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 (и тем самым работая немного быстрее, хотя, по общему признанию, накладные расходы ввода-вывода могут маскировать небольшой выигрыш): for line in map(operator.methodcaller('rstrip', '\r\n'), infile):. Его все еще можно было бы исключить как def chomped_lines(it): return map(operator.methodcaller('rstrip', '\r\n'), it).
s = s.rstrip()
удалит все символы новой строки в конце строки s. Присваивание необходимо, потому что rstrip возвращает новую строку вместо изменения исходной строки.
Это будет в точности повторять chomp 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)
Если вас беспокоит скорость (например, у вас есть длинный список строк) и вы знаете природу символа новой строки, нарезка строк на самом деле быстрее, чем 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. Я не хотел быть «несправедливым» по отношению к первой, а просто проиллюстрировал не столь незначительную разницу, которую, возможно, стоит учитывать в некоторых ситуациях.
Просто используйте:
line = line.rstrip("\n")
или же
line = line.strip("\n")
Вам не нужно ничего из этого сложного
Обратите внимание, что это не то же самое, что chomp.
>>> ' 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. Тем не менее, спасибо, что указали на это.
Обычно мы встречаем три типа окончаний строк: \n, \r и \r\n. Достаточно простое регулярное выражение в re.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 == 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", который представляет собой другую строку.
Я пытаюсь сказать: то, что str.strip() - это все, иногда является самой проблемой.
Похоже, идеального аналога Perl чавкать не существует. В частности, полоса не может обрабатывать многосимвольные разделители новой строки, такие как \r\n. Однако Splitlines выполняет как указано здесь.
Следуя мой ответ по другому вопросу, вы можете комбинировать присоединиться и Splitlines, чтобы удалить / заменить все новые строки из строки s:
''.join(s.splitlines())
Следующее удаляет новую строку ровно один конечный (как я полагаю, chomp). Передача True в качестве аргумента keepends для splitlines сохраняет разделители. Затем снова вызывается splitlines, чтобы удалить разделители только на последней «строке»:
def chomp(s):
if len(s):
lines = s.splitlines(True)
last = lines.pop()
return ''.join(lines + last.splitlines())
else:
return ''
Я всплываю в своем ответе на основе регулярного выражения из ответа, который я опубликовал ранее в комментариях к другому ответу. Я думаю, что использование 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 и сначала проверяют кеш на наличие скомпилированных регулярных выражений (создание / кеширование, если они отсутствуют), а затем вызывают метод сопоставления; пропуск этого поиска помогает.
Кроме того, примечание: поскольку вы пытаетесь сопоставить \n напрямую, вы можете использовать \Z вместо $ (или просто сопоставить \r?$, поскольку $ неявно может соответствовать непосредственно перед новой строкой в конце строки).
Это будет работать как для Windows, так и для Linux (немного дороже с re sub, если вы ищете только повторное решение)
import re
if re.search("(\\r|)\\n$", line):
line = re.sub("(\\r|)\\n$", "", line)
Зачем использовать re.search там, где вам просто нужен re.sub?
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'
Надмножество: любая строка вместо новой строки: stackoverflow.com/questions/1038824/…