Chia theo dấu phẩy và dải khoảng trắng trong Python


346

Tôi có một số mã python phân tách trên dấu phẩy, nhưng không xóa khoảng trắng:

>>> string = "blah, lots  ,  of ,  spaces, here "
>>> mylist = string.split(',')
>>> print mylist
['blah', ' lots  ', '  of ', '  spaces', ' here ']

Tôi thà kết thúc với khoảng trắng bị xóa như thế này:

['blah', 'lots', 'of', 'spaces', 'here']

Tôi biết rằng tôi có thể lặp qua danh sách và tước () từng mục nhưng, vì đây là Python, tôi đoán có cách làm nhanh hơn, dễ dàng hơn và thanh lịch hơn.

Câu trả lời:


594

Sử dụng hiểu danh sách - đơn giản hơn, và dễ đọc như một forvòng lặp.

my_string = "blah, lots  ,  of ,  spaces, here "
result = [x.strip() for x in my_string.split(',')]
# result is ["blah", "lots", "of", "spaces", "here"]

Xem: Tài liệu Python về Hiểu toàn diện Danh sách
Giải thích 2 giây tốt về hiểu danh sách.


1
Siêu tốt! Tôi đã thêm một mục như sau để loại bỏ các mục trong danh sách trống. > text = [x.strip () cho x trong text.split ('.') nếu x! = '']
RandallShanePhD

@Sean: mã python không hợp lệ / chưa hoàn chỉnh là "mục đích ban đầu của bài đăng" của bạn? Theo những người đánh giá, đó là: stackoverflow.com/review/suggested-edits/21504253 . Bạn có thể vui lòng cho họ biết bằng cách sửa lỗi nếu họ sai (một lần nữa) không?
Thức ăn gia súc

Bản gốc đã được sao chép từ một REPL (nếu tôi nhớ chính xác) và mục tiêu là sự hiểu biết về khái niệm cơ bản (sử dụng khả năng hiểu danh sách để thực hiện một thao tác) - nhưng bạn nói đúng, sẽ hợp lý hơn nếu bạn thấy sự hiểu biết danh sách đó tạo ra một danh sách mới
Sean Vieira

24

Chia bằng cách sử dụng một biểu thức thông thường. Lưu ý tôi làm cho trường hợp tổng quát hơn với không gian hàng đầu. Việc hiểu danh sách là loại bỏ các chuỗi null ở phía trước và phía sau.

>>> import re
>>> string = "  blah, lots  ,  of ,  spaces, here "
>>> pattern = re.compile("^\s+|\s*,\s*|\s+$")
>>> print([x for x in pattern.split(string) if x])
['blah', 'lots', 'of', 'spaces', 'here']

Điều này hoạt động ngay cả khi ^\s+không khớp:

>>> string = "foo,   bar  "
>>> print([x for x in pattern.split(string) if x])
['foo', 'bar']
>>>

Đây là lý do tại sao bạn cần ^ \ s +:

>>> pattern = re.compile("\s*,\s*|\s+$")
>>> print([x for x in pattern.split(string) if x])
['  blah', 'lots', 'of', 'spaces', 'here']

Xem các không gian hàng đầu trong blah?

Làm rõ: ở trên sử dụng trình thông dịch Python 3, nhưng kết quả giống nhau trong Python 2.


8
Tôi tin [x.strip() for x in my_string.split(',')]là nhiều pythonic cho câu hỏi. Có thể có những trường hợp giải pháp của tôi là cần thiết. Tôi sẽ cập nhật nội dung này nếu tôi chạy qua một.
tbc0

Tại sao ^\s+cần thiết? Tôi đã kiểm tra mã của bạn mà không có nó và nó không hoạt động, nhưng tôi không biết tại sao.
laike9m

Nếu tôi sử dụng re.compile("^\s*,\s*$"), kết quả là [' blah, lots , of , spaces, here '].
laike9m

@ laike9m, tôi đã cập nhật câu trả lời của mình để cho bạn thấy sự khác biệt. ^\s+làm cho. Như bạn có thể thấy, ^\s*,\s*$cũng không trả lại kết quả mong muốn. Vì vậy, nếu bạn muốn phân chia với một biểu thức chính, hãy sử dụng ^\s+|\s*,\s*|\s+$.
tbc0

Trận đấu đầu tiên trống nếu mẫu hàng đầu (^ \ s +) không khớp để bạn có được thứ gì đó như ['', 'foo', 'bar'] cho chuỗi "foo, bar".
Steeve McCauley

21

Tôi đến để thêm:

map(str.strip, string.split(','))

nhưng thấy nó đã được Jason Orendorff nhắc đến trong một bình luận .

Đọc bình luận của Glenn Maynard trong cùng một câu trả lời gợi ý sự hiểu biết danh sách trên bản đồ, tôi bắt đầu tự hỏi tại sao. Tôi cho rằng anh ta có nghĩa là vì lý do hiệu suất, nhưng tất nhiên anh ta có thể có nghĩa là vì lý do phong cách, hoặc một cái gì đó khác (Glenn?).

Vì vậy, một thử nghiệm nhanh (có thể thiếu sót?) Trên hộp của tôi áp dụng ba phương pháp trong một vòng lặp đã tiết lộ:

[word.strip() for word in string.split(',')]
$ time ./list_comprehension.py 
real    0m22.876s

map(lambda s: s.strip(), string.split(','))
$ time ./map_with_lambda.py 
real    0m25.736s

map(str.strip, string.split(','))
$ time ./map_with_str.strip.py 
real    0m19.428s

chế tạo map(str.strip, string.split(',')) người chiến thắng, mặc dù có vẻ như tất cả họ đều ở trong cùng một sân bóng.

Chắc chắn mặc dù bản đồ (có hoặc không có lambda) không nhất thiết phải được loại trừ vì lý do hiệu suất, và đối với tôi, nó ít nhất là rõ ràng như một sự hiểu biết danh sách.

Biên tập:

Python 2.6.5 trên Ubuntu 10.04


15

Chỉ cần xóa khoảng trắng khỏi chuỗi trước khi bạn tách nó.

mylist = my_string.replace(' ','').split(',')

10
Loại một vấn đề nếu các mục được phân cách bởi dấu phẩy chứa khoảng trắng nhúng, ví dụ "you just, broke this".
Robert Rossney

1
Geeze, -1 cho điều này. Các bạn thật khó khăn. Nó đã giải quyết vấn đề của anh ta, cung cấp dữ liệu mẫu của anh ta chỉ là những từ đơn và không có thông số kỹ thuật nào cho thấy dữ liệu đó là cụm từ. Nhưng w / e, tôi đoán đó là cách các bạn lăn quanh đây.
dùng489041

Dù sao cũng cảm ơn người dùng. Để công bằng mặc dù tôi đặc biệt yêu cầu phân tách và sau đó dải () và dải loại bỏ khoảng trắng hàng đầu và dấu và không chạm vào bất cứ thứ gì ở giữa. Một thay đổi nhỏ và câu trả lời của bạn sẽ hoạt động hoàn hảo, mặc dù: mylist = mystring.strip (). Split (',') mặc dù tôi không biết liệu điều này có đặc biệt hiệu quả hay không.
Mr_Chimp

12

Tôi biết điều này đã được trả lời, nhưng nếu bạn kết thúc việc này rất nhiều, các biểu thức thông thường có thể là một cách tốt hơn để đi:

>>> import re
>>> re.sub(r'\s', '', string).split(',')
['blah', 'lots', 'of', 'spaces', 'here']

Các \ský tự khớp với bất kỳ ký tự khoảng trắng nào và chúng ta chỉ cần thay thế nó bằng một chuỗi rỗng ''. Bạn có thể tìm thêm thông tin ở đây: http://docs.python.org/l Library / re.html # re.sub


3
Ví dụ của bạn sẽ không hoạt động trên các chuỗi chứa khoảng trắng. "Ví dụ như điều này, một" sẽ trở thành "cho", "đề thi", "một". Không nói đó là giải pháp BAD (nó hoạt động hoàn hảo trên ví dụ của tôi), nó chỉ phụ thuộc vào nhiệm vụ trong tay!
Mr_Chimp

Đúng, điều đó rất đúng! Bạn có thể có thể điều chỉnh regrec để nó có thể xử lý các chuỗi có khoảng trắng, nhưng nếu tính năng hiểu danh sách hoạt động, tôi sẽ nói gắn bó với nó;)
Brad Montgomery

2
import re
result=[x for x in re.split(',| ',your_string) if x!='']

Cái này làm việc tốt cho tôi.


2

re (như trong các biểu thức thông thường) cho phép chia tách nhiều ký tự cùng một lúc:

$ string = "blah, lots  ,  of ,  spaces, here "
$ re.split(', ',string)
['blah', 'lots  ', ' of ', ' spaces', 'here ']

Điều này không hoạt động tốt cho chuỗi ví dụ của bạn, nhưng hoạt động độc đáo cho danh sách được phân tách bằng dấu phẩy. Đối với chuỗi ví dụ của bạn, bạn có thể kết hợp sức mạnh re.split để phân chia trên các mẫu regex để có được hiệu ứng "split-on-this-or-that".

$ re.split('[, ]',string)
['blah',
 '',
 'lots',
 '',
 '',
 '',
 '',
 'of',
 '',
 '',
 '',
 'spaces',
 '',
 'here',
 '']

Thật không may, đó là xấu xí, nhưng filtersẽ làm một mẹo:

$ filter(None, re.split('[, ]',string))
['blah', 'lots', 'of', 'spaces', 'here']

Voila!


2
Tại sao không chỉ re.split(' *, *', string)?
Paul Tomblin

4
@PaulTomblin ý kiến ​​hay. Người ta cũng có thể đã làm điều này: re.split('[, ]*',string)cho hiệu quả tương tự.
Dannid

Dannid tôi nhận ra sau khi viết rằng nó không tước khoảng trắng ở đầu và cuối như câu trả lời của @ tbc0.
Paul Tomblin

@PaulTomblinheh, và phản bác của tôi [, ]*để lại một chuỗi trống ở cuối danh sách. Tôi nghĩ rằng bộ lọc vẫn là một điều tốt đẹp để ném vào đó, hoặc bám vào danh sách hiểu như câu trả lời hàng đầu.
Dannid

1

map(lambda s: s.strip(), mylist)sẽ tốt hơn một chút so với vòng lặp rõ ràng. Hoặc cho tất cả mọi thứ cùng một lúc:map(lambda s:s.strip(), string.split(','))


10
Mẹo: bất cứ khi nào bạn thấy mình đang sử dụng map, đặc biệt nếu bạn đang sử dụng lambdanó, hãy kiểm tra kỹ xem bạn có nên sử dụng tính năng hiểu danh sách hay không.
Glenn Maynard

11
Bạn có thể tránh lambda với map(str.strip, s.split(',')).
Jason Orendorff


1
import re
mylist = [x for x in re.compile('\s*[,|\s+]\s*').split(string)]

Đơn giản, dấu phẩy hoặc ít nhất một khoảng trắng có / không có trước / khoảng trắng thành công.

Vui lòng thử!


0

map(lambda s: s.strip(), mylist)sẽ tốt hơn một chút so với vòng lặp rõ ràng.
Hoặc cho tất cả mọi thứ cùng một lúc:

map(lambda s:s.strip(), string.split(','))

Đó là tất cả mọi thứ bạn cần.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.