Tại sao “phân tách” trên một chuỗi rỗng trả về một mảng không trống?


111

Tách trên một chuỗi trống trả về một mảng có kích thước 1:

scala> "".split(',')
res1: Array[String] = Array("")

Hãy xem xét rằng điều này trả về mảng trống:

scala> ",,,,".split(',')
res2: Array[String] = Array()

Vui lòng giải thích :)


5
Ngoài ra, nó có vẻ không phù hợp với hành vi được quan sát khi chuỗi chỉ chứa một trường hợp của dấu phân tách. Trong trường hợp này, kết quả thực sự là một mảng trống: ",". Split (","). Length == 0
LD.

Câu trả lời:


37

Vì lý do tương tự mà

",test" split ','

",test," split ','

sẽ trả về một mảng có kích thước 2. Mọi thứ trước khi so khớp đầu tiên được trả về dưới dạng phần tử đầu tiên.


5
Chuỗi rỗng là một chuỗi, không phải là không có gì. (bất cứ nơi nào trừ trong Excel)
Raphael

5
@Raphael Hoặc trong cơ sở dữ liệu Oracle
Austin

7
@Raphael, trong bất kỳ ngôn ngữ lập trình nào khác "".split("wtf").lengthtrả về 0. Chỉ trong JS là 1.: /
Andrey Mikhaylov - lolmaus 22/02

11
@ DanielC.Sobral Ok, vậy tại sao "," split ","trả về mảng 0?
Joan

5
Tại sao mọi thứ sau trận đấu cuối cùng cũng không trở lại?
Didier A.

72

Nếu bạn chia một quả cam 0 lần, bạn có đúng một mảnh - quả cam.


8
Nhưng quả cam không trống rỗng (idk nếu đó là ý nghĩa của oluies), nó là một quả cam. Có lẽ tách một màu cam nên có mặt ở đó, nhưng không phải là, vì vậy bạn lấy lại một giá trị duy nhất: một không gian trống rỗng xD
Nick Rolando

8
Đây là một cuộc trò chuyện sâu sắc.

31
Phép ẩn dụ này có ý nghĩa "orange".split(','), nhưng rõ ràng không liên quan đến việc tách các chuỗi rỗng. Nếu tôi chia số thiếu màu cam của tôi bằng 0 lần, tôi vẫn không có quả cam; chúng ta có biểu thị điều đó dưới dạng danh sách trống không có quả cam, danh sách chính xác một quả không có quả cam, danh sách mười hai quả không có quả cam, hay là gì? Vấn đề không phải là chúng ta rốt cuộc là gì, mà là chúng ta đại diện cho nó như thế nào.
Matchu

1
Nhưng nếu bạn chia một cuốn sách không tồn tại theo các trang của nó, bạn sẽ không nhận được gì.
SMUsamaShah

49

Phương pháp tách Java và Scala hoạt động theo hai bước như sau:

  • Đầu tiên, chia chuỗi bằng dấu phân cách. Hệ quả tự nhiên là nếu chuỗi không chứa dấu phân cách, một mảng singleton chỉ chứa chuỗi đầu vào được trả về,
  • Thứ hai, loại bỏ tất cả các chuỗi trống ngoài cùng bên phải. Đây là lý do ",,,".split(",")trả về mảng trống.

Theo điều này, kết quả của "".split(",")phải là một mảng trống vì ở bước thứ hai, phải không?

Nó nên. Thật không may, đây là một trường hợp góc được giới thiệu nhân tạo. Và đó là xấu, nhưng ít nhất nó được ghi chép lại trong java.util.regex.Pattern, nếu bạn nhớ để có một cái nhìn tại các tài liệu:

Đối với n == 0, kết quả giống như đối với n <0, ngoại trừ các chuỗi trống ở cuối sẽ không được trả về. (Lưu ý rằng trường hợp đầu vào là một chuỗi trống là đặc biệt, như được mô tả ở trên và tham số giới hạn không áp dụng ở đó.)

Giải pháp 1: Luôn chuyển -1 làm tham số thứ hai

Vì vậy, tôi khuyên bạn nên luôn truyền n == -1dưới dạng tham số thứ hai (điều này sẽ bỏ qua bước hai ở trên), trừ khi bạn biết cụ thể những gì bạn muốn đạt được / bạn chắc chắn rằng chuỗi trống không phải là thứ mà chương trình của bạn sẽ lấy làm đầu vào.

Giải pháp 2: Sử dụng lớp Guava Splitter

Nếu bạn đang sử dụng Guava trong dự án của mình, bạn có thể thử lớp Splitter (tài liệu) . Nó có một API rất phong phú và làm cho mã của bạn rất dễ hiểu.

Splitter.on(".").split(".a.b.c.") // "", "a", "b", "c", ""
Splitter.on(",").omitEmptyStrings().split("a,,b,,c") // "a", "b", "c"
Splitter.on(CharMatcher.anyOf(",.")).split("a,b.c") // "a", "b", "c"
Splitter.onPattern("=>?").split("a=b=>c") // "a", "b", "c"
Splitter.on(",").limit(2).split("a,b,c") // "a", "b,c"

1
+1, đây là câu trả lời duy nhất thực sự trích dẫn tài liệu và chỉ ra rằng nó không nhất quán. Tuy nhiên, tôi không tìm thấy phần được đánh dấu của nhận xét trong JavaDoc của mình.
Yogu

Tôi đã tìm thấy nó trong java.util.regex.Pattern, nhưng có vẻ như nó đã gần như biến mất. Tại thời điểm viết bài, nó chắc chắn có mặt trong cây nguồn OpenJDK chính thức dưới dạng javadoc. android.googlesource.com/platform/libcore/+/… Có lẽ chúng ta nên báo cáo lỗi?
Rok Kralj

Sẽ là một ý kiến ​​hay khi báo cáo lỗi - hành vi chắc chắn sẽ không bị thay đổi, nhưng ít nhất nó phải được ghi lại.
Yogu

@RokKralj Android đã không sử dụng thư viện OpenJDK mà thay vào đó dựa trên Apache Harmony, vì vậy có thể bạn đang tìm nhầm chỗ?
lxgr

1
"".split (",", n)tạo một mảng một phần tử cho n trong (-1, 0, 1) bằng Oracle JDK 8. Sẽ rất tuyệt nếu chỉ nhận được danh sách các mã thông báo không trống - hãy đoán một regex đầy đủ có thể cần thiết (đại loại là "[^,\\s]+[^,]*[^,\\s]*").
simon.watts

40

Tách một chuỗi trống trả về chuỗi trống làm phần tử đầu tiên. Nếu không tìm thấy dấu phân tách trong chuỗi đích, bạn sẽ nhận được một mảng có kích thước 1 đang giữ chuỗi ban đầu, ngay cả khi nó trống.


2
Sai lầm. Split loại bỏ tất cả các chuỗi trống ngoài cùng bên phải, do đó kết quả phải là một mảng trống. Hãy xem câu trả lời của tôi. ",".split(",")trả về mảng trống.
Rok Kralj

23

"a".split(",")-> "a" do đó "".split(",")->""


6
Sai lầm. Split loại bỏ tất cả các chuỗi trống ngoài cùng bên phải, do đó kết quả phải là một mảng trống. Hãy xem câu trả lời của tôi. ",".split(",")trả về mảng trống.
Rok Kralj

5

Trong tất cả các ngôn ngữ lập trình, tôi biết một chuỗi trống vẫn là một Chuỗi hợp lệ. Vì vậy, thực hiện phân tách bằng bất kỳ dấu phân tách nào sẽ luôn trả về một mảng phần tử duy nhất trong đó phần tử đó là Chuỗi trống. Nếu đó là một chuỗi null (không trống) thì đó sẽ là một vấn đề khác.


Tôi nghĩ rằng đây là một chức năng thư viện và không phải là một phần của ngôn ngữ. Ví dụ trong google ổi, bạn có thể bỏ qua các chuỗi trống. > Iterable <String> piece = com.google.common.base.Splitter.on (','). OmitEmptyStrings (). Split ("");
oluies

2

Đây splithành vi được thừa hưởng từ Java, cho tốt hơn hoặc tồi tệ hơn ...
Scala không ghi đè lên các định nghĩa từ Stringnguyên thủy.

Lưu ý rằng bạn có thể sử dụng limitđối số để sửa đổi hành vi :

Tham số giới hạn kiểm soát số lần mẫu được áp dụng và do đó ảnh hưởng đến độ dài của mảng kết quả. Nếu giới hạn n lớn hơn 0 thì mẫu sẽ được áp dụng nhiều nhất n - 1 lần, độ dài của mảng sẽ không lớn hơn n và mục nhập cuối cùng của mảng sẽ chứa tất cả đầu vào vượt quá dấu phân cách được so khớp cuối cùng. Nếu n không dương thì mẫu sẽ được áp dụng nhiều lần nhất có thể và mảng có thể có độ dài bất kỳ. Nếu n bằng 0 thì mẫu sẽ được áp dụng nhiều lần nhất có thể, mảng có thể có độ dài bất kỳ và các chuỗi trống theo sau sẽ bị loại bỏ.

tức là bạn có thể đặt limit=-1để có được hành vi của (tất cả?) các ngôn ngữ khác:

@ ",a,,b,,".split(",")
res1: Array[String] = Array("", "a", "", "b")

@ ",a,,b,,".split(",", -1)  // limit=-1
res2: Array[String] = Array("", "a", "", "b", "", "")

Có vẻ như ai cũng biết rằng hành vi của Java khá khó hiểu nhưng:

Hành vi trên có thể được quan sát từ ít nhất Java 5 đến Java 8.

Đã có nỗ lực thay đổi hành vi để trả về một mảng trống khi tách một chuỗi trống trong JDK-6559590 . Tuy nhiên, nó đã sớm được hoàn nguyên trong JDK-8028321 khi nó gây ra hồi quy ở nhiều nơi khác nhau. Thay đổi không bao giờ được đưa vào bản phát hành Java 8 đầu tiên.

Lưu ý: Phương pháp phân tách đã không có trong Java ngay từ đầu (nó không có trong 1.0.2 ) nhưng thực sự có từ ít nhất 1.4 (ví dụ: xem JSR51 khoảng năm 2002). Tôi vẫn đang điều tra ...

Điều không rõ ràng là tại sao Java lại chọn điều này ngay từ đầu (tôi nghi ngờ rằng nó ban đầu là một lỗi / lỗi trong "trường hợp cạnh"), nhưng bây giờ không thể thu hồi được đưa vào ngôn ngữ này và vì vậy nó vẫn còn .


Tôi không chắc rằng điều này trả lời câu hỏi - mặc dù nó có thể đúng với ví dụ được đưa ra ở đây, nhưng nó không giúp ích gì cho trường hợp chuỗi rỗng - "".split(",")vẫn trả về một mảng phần tử như vậy [""].
DaveyDaveDave

@DaveyDaveDave đó là hành vi được mong đợi của mọi ngôn ngữ khác. ",,,," là hành vi kỳ lạ / khác biệt trong Scala và khác với trường hợp "".
Andy Hayden

0

Chuỗi rỗng không có trạng thái đặc biệt trong khi tách chuỗi. Bạn có thể sử dụng:

Some(str)
  .filter(_ != "")
  .map(_.split(","))
  .getOrElse(Array())
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.