Tại sao các chuỗi trống được trả về trong kết quả split ()?


120

Điểm '/segment/segment/'.split('/')trở lại là ['', 'segment', 'segment', '']gì?

Chú ý các phần tử trống. Nếu bạn đang tách trên một dấu phân tách xảy ra ở vị trí một và ở cuối chuỗi, thì giá trị bổ sung nào sẽ cung cấp cho bạn để chuỗi trống được trả về từ mỗi đầu?


1
Tôi có cùng một câu hỏi và đã tìm kiếm nó trong một thời gian dài. Bây giờ tôi hiểu kết quả trống thực sự quan trọng. Cảm ơn câu hỏi của bạn.
emeraldhieu

2
Một giải pháp là sử dụng strip()dải ở đầu và đuôi ký tự tách ra từ chuỗi trước khi tách:'/segment/segment/'.strip('/').split('/')
pkamb

Câu trả lời:


178

str.splitbổ sung str.join, vì vậy

"/".join(['', 'segment', 'segment', ''])

giúp bạn lấy lại chuỗi ban đầu.

Nếu các chuỗi trống không có ở đó, chuỗi đầu tiên và cuối cùng '/'sẽ bị thiếu saujoin()


11
Đơn giản, nhưng trả lời đầy đủ câu hỏi.
orokusaki

Tôi đã bị sốc khi phát hiện ra rằng dấu ngoặc kép thực sự hợp lệ trong Python ... nhưng, nhưng ... làm thế nào? Các tài liệu dường như không đề cập đến điều này.
Tim Pietzcker

@ Tim, tôi có không biết bao những dấu ngoặc kép có trong đó: /
John La Rooy

7
Vì vậy, bạn không sử dụng Microsoft Word làm IDE Python của mình? :)
Tim Pietzcker

1
@ aaa90210 ai nói câu trả lời đơn giản không phải là tốt nhất? Đó là một bình luận (đầu tiên, 5 năm trước) về cách trả lời đơn giản, nhưng trả lời đầy đủ câu hỏi. Sử dụng "nhưng" trong một câu không ngụ ý điều gì xấu. Một câu trả lời không đơn giản có thể là một câu trả lời đầy đủ hơn (ví dụ, bao gồm các quyết định có liên quan hoặc một PEP liên quan đến chức năng được lưu ý).
orokusaki

88

Nói chung hơn, để loại bỏ các chuỗi trống được trả về trong split()kết quả, bạn có thể muốn xem xét filterhàm.

Thí dụ:

filter(None, '/segment/segment/'.split('/'))

trả lại

['segment', 'segment']

3
Cảm ơn bạn vì điều này, tôi không biết tại sao câu trả lời này lại xuống quá xa, mọi thứ khác đều là những thứ thô sơ.
Wedge

6
Nếu muốn thu thập kết quả trong một danh sách thay vì lấy một đối tượng bộ lọc làm đầu ra, hãy đặt toàn bộ cấu trúc bộ lọc vào list(...).
Tim Visée

29

Có hai điểm chính cần xem xét ở đây:

  • Mong đợi kết quả '/segment/segment/'.split('/')bằng với ['segment', 'segment']là hợp lý, nhưng sau đó điều này làm mất thông tin. Nếu split()làm việc theo cách bạn muốn, nếu tôi nói với bạn điều đó a.split('/') == ['segment', 'segment'], bạn không thể cho tôi biết điều gì ađã xảy ra.
  • Kết quả của 'a//b'.split()be là gì? ['a', 'b']?, hoặc ['a', '', 'b']? Tức là, nên split()hợp nhất các dấu phân cách liền kề? Nếu đúng như vậy, thì sẽ rất khó phân tích cú pháp dữ liệu được phân tách bằng ký tự và một số trường có thể để trống. Tôi khá chắc chắn có rất nhiều người làm muốn các giá trị rỗng trong kết quả đối với trường hợp trên!

Cuối cùng, nó tóm gọn lại hai điều:

Tính nhất quán: nếu tôi có ndấu phân cách, trong a, tôi nhận n+1lại các giá trị sau dấu split().

Có thể làm những việc phức tạp và dễ làm những việc đơn giản: nếu bạn muốn bỏ qua các chuỗi rỗng do kết quả của dấu split(), bạn luôn có thể làm:

def mysplit(s, delim=None):
    return [x for x in s.split(delim) if x]

nhưng nếu người ta không muốn bỏ qua các giá trị trống, người ta có thể làm được.

Ngôn ngữ phải chọn một định nghĩa về split()—có quá nhiều trường hợp sử dụng khác nhau để đáp ứng yêu cầu của mọi người như một mặc định. Tôi nghĩ rằng lựa chọn của Python là một lựa chọn tốt và hợp lý nhất. (Ngoài ra, một trong những lý do tôi không thích C strtok()là vì nó hợp nhất các dấu phân cách liền kề, khiến việc phân tích cú pháp / mã hóa nó trở nên cực kỳ khó khăn).

Có một ngoại lệ: a.split()không có đối số sẽ ép các khoảng trắng liên tiếp, nhưng người ta có thể tranh luận rằng đây là điều đúng đắn cần làm trong trường hợp đó. Nếu bạn không muốn hành vi, bạn luôn có thể a.split(' ').


Đối với những người tự hỏi liệu có nhanh hơn để xóa các khoảng trắng trùng lặp, sau đó tách hoặc tách và chỉ lấy các chuỗi không rỗng, đây là những gì tôi nhận được: python3 -m timeit "import re ; re.sub(' +', ' foo bar baz ', '').split(' ')"-> 875 nsec mỗi vòng lặp; python3 -m timeit "[token for token in ' foo bar baz '.split(' ') if token]"-> 616 nsec mỗi vòng lặp
s3cur3

8

Luôn x.split(y)luôn trả về một danh sách các 1 + x.count(y)mục là một sự đều đặn quý giá - như @ gnibbler đã chỉ ra rằng nó tạo ra splitjoinđảo ngược chính xác của nhau (như chúng rõ ràng phải như vậy), nó cũng ánh xạ chính xác ngữ nghĩa của tất cả các loại bản ghi được nối với dấu phân cách ( chẳng hạn như csvcác dòng tệp [[mạng các vấn đề trích dẫn]], các dòng /etc/grouptrong Unix, v.v.), nó cho phép (như câu trả lời của @ Roman đã đề cập) dễ dàng kiểm tra (ví dụ) đường dẫn tuyệt đối so với đường dẫn tương đối (trong đường dẫn tệp và URL), và kể từ đó trở đi.

Một cách khác để xem xét nó là bạn không nên chỉ tung thông tin ra ngoài cửa sổ mà không có lợi. Điều gì sẽ đạt được khi làm x.split(y)tương đương với x.strip(y).split(y)? Không có gì, tất nhiên - thật dễ dàng để sử dụng hình thức thứ hai khi đó là những gì bạn có ý nghĩa, nhưng nếu các hình thức đầu tiên được tùy tiện coi là có nghĩa là một thứ hai, bạn sẽ có rất nhiều việc phải làm khi bạn làm muốn là người đầu tiên ( mà không phải là hiếm, như đoạn trước đã chỉ ra).

Nhưng thực sự, suy nghĩ về tính đều đặn của toán học là cách đơn giản và tổng quát nhất mà bạn có thể tự dạy mình để thiết kế các API có thể chuyển được. Để lấy một ví dụ khác, điều rất quan trọng là đối với bất kỳ giá trị nào xy x == x[:y] + x[y:]- điều này ngay lập tức chỉ ra lý do tại sao nên loại trừ một điểm cực trị của phép cắt . Bạn có thể hình thành khẳng định bất biến càng đơn giản, thì càng có nhiều khả năng rằng ngữ nghĩa kết quả là những gì bạn cần trong sử dụng thực tế - một phần của sự thật huyền bí rằng toán học rất hữu ích trong việc xử lý vũ trụ.

Hãy thử xây dựng công thức bất biến cho một splitphương ngữ trong đó các dấu phân cách ở đầu và cuối là dấu phân cách đặc biệt ... ví dụ ngược lại: các phương thức chuỗi chẳng hạn như isspacekhông đơn giản đến mức tối đa - x.isspace()tương đương với x and all(c in string.whitespace for c in x)- hàng đầu ngớ ngẩn đó x andlà lý do tại sao bạn thường thấy mình đang viết mã not x or x.isspace(), để quay trở lại sự đơn giản mà lẽ ra phải được thiết kế thành các is...phương thức chuỗi (theo đó một chuỗi rỗng "là" bất cứ thứ gì bạn muốn - trái với ý thức con người trên đường phố, có thể [[tập hợp rỗng, giống như số không & c, luôn khiến hầu hết mọi người nhầm lẫn ;-)]], nhưng hoàn toàn phù hợp với ý thức chung toán học rõ ràng đã được tinh chỉnh ! -).


5

Tôi không chắc bạn đang tìm kiếm câu trả lời nào? Bạn nhận được ba trận đấu vì bạn có ba dấu phân cách. Nếu bạn không muốn cái trống đó, chỉ cần sử dụng:

'/segment/segment/'.strip('/').split('/')

4
-1 bởi vì bạn nhận được bốn trận đấu không phải ba, và điều này cũng không thực sự trả lời câu hỏi.
Roman

1
+1 để chống lại sự tiêu cực .. Anh ấy không nói rằng bạn sẽ nhận lại ba kết quả. Anh ấy nói "ba que diêm" cho "ba dấu phân cách", nghe có vẻ hợp lý với tôi. Tuy nhiên, bạn không nhận được "bốn trận đấu" của bất cứ điều gì. Tuy nhiên, bạn nhận được "bốn phần tử" được trả về trong kết quả của mình. Ngoài ra, nó không trực tiếp trả lời "tại sao", nhưng nó cung cấp một cách đơn giản để đạt được những gì anh ấy thực sự muốn ... mà tôi không nghĩ xứng đáng với một phản đối. Nếu bạn định đánh lừa ai đó (với một lời tán thành không hơn không kém), hãy cẩn thận hơn! Chúc mừng! 8 ^)
kodybrown

@wasatchwizard Cảm ơn bạn đã làm rõ. Tôi đánh giá cao sự điều chỉnh và khuyến nghị. Rất tiếc, hiện tại phiếu bầu của tôi đã bị khóa và không thể thay đổi được.
Roman

Tôi yêu giải pháp của bạn - dải rồi tách ra để xóa kết cục trống rỗng
Nam G VU

5

Chà, nó cho bạn biết có một dấu phân cách ở đó. Vì vậy, nhìn thấy 4 kết quả cho phép bạn biết bạn đã có 3 dấu phân cách. Điều này cung cấp cho bạn sức mạnh để làm bất cứ điều gì bạn muốn với thông tin này, thay vì để Python thả các phần tử trống và sau đó khiến bạn kiểm tra thủ công các dấu phân cách bắt đầu hoặc kết thúc nếu bạn cần biết.

Ví dụ đơn giản: Giả sử bạn muốn kiểm tra tên tệp tuyệt đối so với tên tệp tương đối. Bằng cách này, bạn có thể làm tất cả với phần tách mà không cần phải kiểm tra ký tự đầu tiên của tên tệp của bạn là gì.


1

Hãy xem xét ví dụ nhỏ nhất này:

>>> '/'.split('/')
['', '']

splitphải cung cấp cho bạn những gì trước và sau dấu phân cách '/', nhưng không có ký tự nào khác. Vì vậy, nó để cung cấp cho bạn những chuỗi rỗng, mà về mặt kỹ thuật trước và sau '/', bởi vì '' + '/' + '' == '/'.

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.