Python: indent all lines of a line except the first while keeping line breaks?

I want to defer all lines of a multiline line except the first one, without wrapping the text.

For example, I want to rotate:

A very very very very very very very very very very very very very very very very long mutiline string 

in

 A very very very very very very very very very very very very very very very very long multiline string 

I tried

 textwrap.fill(string, width=999999999999, subsequent_indent=' ',) 

But it still puts all the text on one line. Thoughts?

+6
source share
3 answers

You just need to replace the newline character '\n' with the newline character plus spaces '\n ' and store it in a variable (since replace will not change the original string, but will return a new one with a replacement).

 string = string.replace('\n', '\n ') 
+12
source

You mean something like this:

 In [21]: s = 'abc\ndef\nxyz' In [22]: print s abc def xyz In [23]: print '\n '.join(s.split('\n')) abc def xyz 

?

edit: Alternatively (HT @Steven Rumbalski):

 In [24]: print s.replace('\n', '\n ') abc def xyz 
+2
source

The bare replacement mentioned by @ steven-rumbalski will be the most efficient way to accomplish this, but this is not the only way.

Here's another solution using lists. If the text has already been split into a list of lines, it will be much faster than running join() , replace() and splitlines()

 text = """A very very very very very very very very very very very very very very very very long mutiline string""" lines = text.splitlines() indented = [' ' + l for l in lines] indented[0] = lines[0] indented = '\n'.join(indented) 

The list can be changed in place, but there is a significant cost of execution compared to using the second variable. It is also moderately faster to deflect all lines and then swap the first line in another operation.

There is also a textwrap module. I disagree that using textwrap for indentation is non-pythonic. If the lines are combined into one line containing the lines of a new line, this line is essentially wrapped. Indentation is a logical extension of text wrapping, so textwrap makes sense to me.

Except that he is slow. Really, really slow. Like 15 times slower.

Python 3 added indent to textwrap , which makes indentation without textwrap very easy. Of course, a more elegant way to handle a lambda predicate, but that does exactly what the original question asked.

 indented = textwrap.indent(text, ' ', lambda x: not text.splitlines()[0] in x ) 

Here are some timeit results from various methods.

 >>> timeit.timeit(r"text.replace('\n', '\n ')", setup='text = """%s"""' % text) 0.5123521030182019 

Two solutions for understanding the list:

 >>> timeit.timeit(r"indented = [' ' + i for i in lines]; indented[0] = lines[0]", setup='lines = """%s""".splitlines()' % text) 0.7037646849639714 >>> timeit.timeit(r"indented = [lines[0]] + [' ' + i for i in lines[1:]]", setup='lines = """%s""".splitlines()' % text) 1.0310905870283023 

And here is the unsuccessful result of textwrap :

 >>> timeit.timeit(r"textwrap.indent(text, ' ', lambda x: not text.splitlines()[0] in x )", setup='import textwrap; text = """%s"""' % text) 7.7950868209591135 

I thought that part of this time could be a terribly inefficient predicate, but even with the remote textwrap.indent still more than 8 times slower than a bare replacement.

 >>> timeit.timeit(r"textwrap.indent(text, ' ')", setup='import textwrap; text = """%s"""' % text) 4.266149697010405 
0
source

Source: https://habr.com/ru/post/952766/


All Articles