2013-08-29 84 views
6

Tôi muốn thụt lề tất cả các dòng của một chuỗi nhiều dòng trừ chuỗi đầu tiên, mà không cần gói văn bản.Python: Thụt lề tất cả các dòng của một chuỗi ngoại trừ đầu tiên trong khi vẫn bảo vệ dòng?

Ví dụ, tôi muốn chuyển:

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

thành:

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

Tôi đã thử

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

Nhưng điều này vẫn đặt tất cả các văn bản trên cùng một dòng. Suy nghĩ?

+0

Từ tài liệu cho 'next_indent':" Chuỗi sẽ được thêm vào tất cả các dòng đầu ra được bao bọc ". Vì không có gì đang được bọc, không có gì được thụt vào. –

Trả lời

12

Bạn chỉ cần thay thế các ký tự xuống dòng '\n' với một ký tự dòng mới cộng với không gian trắng '\n    ' và lưu nó vào một biến (kể từ replace sẽ không thay đổi chuỗi gốc của bạn, nhưng trả lại chuỗi mới có thay thế).

string = string.replace('\n', '\n ') 
2

Bạn có nghĩa là một cái gì đó như thế này:

In [21]: s = 'abc\ndef\nxyz' 

In [22]: print s 
abc 
def 
xyz 

In [23]: print '\n '.join(s.split('\n')) 
abc 
    def 
    xyz 

?

chỉnh sửa: Ngoài (HT @Steven Rumbalski):

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

Tại sao 'split' và' join' khi bạn chỉ đơn giản là 'replace'? –

+1

@ DavidY.Stephenson: Có vẻ như không có gì lạ khi sử dụng 'textwrap' cho một công việc không cần gói. –

0

Thay thế trần được đề cập bởi @steven-rumbalski sẽ là cách hiệu quả nhất để thực hiện việc này, nhưng không phải là cách duy nhất.

Đây là giải pháp khác sử dụng tính năng hiểu danh sách. Nếu văn bản đã được tách ra thành một danh sách các dòng, điều này sẽ nhanh hơn nhiều so với chạy join(), replace()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) 

Danh sách này có thể được sửa đổi tại chỗ, nhưng có một chi phí hiệu suất đáng kể so với sử dụng một giây biến. Nó cũng nhanh hơn để thụt lề tất cả các dòng và sau đó hoán đổi dòng đầu tiên trong một thao tác khác.

Ngoài ra còn có mô-đun textwrap. Tôi không đồng ý rằng việc sử dụng textwrap cho thụt đầu dòng là unpythonic. Nếu các dòng được nối trong một chuỗi chứa các dòng mới, chuỗi đó vốn đã được bao bọc. Thụt lề là một phần mở rộng hợp lý của gói văn bản, do đó, textwrap có ý nghĩa với tôi.

Ngoại trừ việc nó chậm. Thực sự, rất chậm. Giống như chậm hơn 15 lần.

Python 3 đã thêm indent đến textwrap làm cho thụt lề mà không cần gói lại rất dễ dàng. Có chắc chắn là một cách thanh lịch hơn để xử lý các vị từ lambda, nhưng điều này không chính xác những gì câu hỏi ban đầu đã được yêu cầu.

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

Dưới đây là một số kết quả của các phương pháp khác nhau timeit.

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

Các giải pháp hiểu danh sách hai:

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

Và đây là những bất hạnh textwrap kết quả:

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

Tôi nghĩ một số thời điểm đó có thể là vị khủng khiếp không hiệu quả, nhưng ngay cả với đã bị xóa, textwrap.indent vẫn chậm hơn 8 lần so với thay thế trần.

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