Câu hỏi Tại sao "chia nhỏ" trên một chuỗi rỗng trả lại một mảng không trống?


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

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

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

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

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


76
2018-02-11 00:50


gốc


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


Các câu trả lời:


Cũng vì lý do đó

",test" split ','

",test," split ','

sẽ trả về một mảng có kích thước 2. Mọi thứ trước khi trận đấu đầu tiên được trả về làm phần tử đầu tiên.


27
2018-02-11 01:52



Chuỗi rỗng là một chuỗi, không có gì. (mọi nơi nhưng trong Excel) - Raphael
@Raphael Hoặc trong một cơ sở dữ liệu Oracle - Austin
@Raphael, bằng bất kỳ ngôn ngữ lập trình nào khác "".split("wtf").length trả về 0. Chỉ trong JS nó là 1.: / - lolmaus - Andrey Mikhaylov
@ DanielC.Sobral Ok, vậy tại sao "," split "," trả về một mảng 0? - Joan
Tại sao không phải tất cả mọi thứ sau trận đấu cuối cùng cũng trở lại? - Didier A.


Nếu bạn chia một lần không màu da cam, bạn có chính xác một mảnh - màu da cam.


58
2018-02-11 04:27



... omitEmptyOranges ... - oluies
Nhưng màu cam không trống rỗng (nếu đó là những gì oluies có nghĩa là), một màu cam của nó. Có thể tách một quả cam nên ở đó, nhưng không, vì vậy bạn lấy lại một giá trị duy nhất: một khoảng trống rỗng xD - Nick Rolando
Đây là một cuộc trò chuyện sâu sắc.
Ẩn dụ này có ý nghĩa cho "orange".split(','), nhưng không rõ ràng có liên quan đến việc tách các chuỗi rỗng. Nếu tôi chia thời gian không màu cam của tôi, tôi vẫn không có màu da cam; chúng ta có thể đại diện cho nó như một danh sách trống không cam, một danh sách chính xác không có cam, một danh sách mười hai không cam, hay cái gì? Nó không phải là một câu hỏi về những gì chúng tôi kết thúc, nhưng làm thế nào chúng tôi đại diện cho nó. - Matchu
Đó là lỗi chia cho số không. - Caleb Mauer


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


40
2018-02-11 00:55



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


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

  • Đầu tiên, chia chuỗi theo dấu phân tách. Hậu quả tự nhiên là nếu chuỗi không chứa dấu tách, một mảng đơn chứa chỉ 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 đó, kết quả của "".split(",") nên 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 giả tạo được giới thiệu. Và điều đó là xấu, nhưng ít nhất nó được ghi lại trong java.util.regex.Pattern, nếu bạn nhớ xem tài liệu:

Đối với n == 0, kết quả là đối với n <0, ngoại trừ các chuỗi rỗng sau   sẽ không được trả lại. (Lưu ý rằng trường hợp đầu vào là chính nó   chuỗi rỗ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 vượt qua n == -1 như 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 rỗng không phải là một cái gì đó mà chương trình của bạn sẽ nhận được như một đầu vào.

TL; DR: Tách chuỗi rỗng là một trường hợp góc được giới thiệu giả tạo và tài liệu cảnh báo bạn về điều đó. Luôn chuyển -1 làm tham số thứ hai để tránh lỗi, trừ khi bạn có lý do chính đáng.

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

Nếu bạn đã sử dụng Ổi trong dự án của mình, bạn có thể thử Bộ tách (tài liệu) lớp học. 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"

25
2018-06-13 18:13



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 phù hợp. Tuy nhiên, tôi không tìm thấy phần nổi bật của nhận xét trong JavaDoc của tôi. - Yogu
Tôi đã tìm thấy nó trong java.util.regex.Pattern, nhưng dường như nó đã biến mất. Tại thời điểm viết, nó chắc chắn đã có mặt trong cây nguồn OpenJDK chính thức như một javadoc. android.googlesource.com/platform/libcore/+/…  Có lẽ chúng ta nên báo cáo một lỗi? - Rok Kralj
Sẽ là một ý tưởng tốt để 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ó cũng phải được ghi lại. - Yogu
@RokKralj Android đã không sử dụng thư viện OpenJDK, nhưng thay vào đó dựa trên Apache Harmony, vì vậy có thể bạn đang tìm kiếm địa điểm sai? - lxgr
"Trường hợp góc được giới thiệu giả tạo" nghĩa là gì? - Andy Hayden


"a".split(",") -> "a" vì thế "".split(",") -> ""


23
2018-04-15 11:06



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


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 chia bằng cách sử dụng bất kỳ dấu 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 nó là một chuỗi rỗng (không trống) thì đó sẽ là một vấn đề khác.


4
2018-02-11 00:57



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> pieces = com.google.common.base.Splitter.on (','). OmitEmptyStrings (). Split (""); - oluies
.Không phải trong Ruby :) - Ashitaka


Điều này split hành vi được kế thừa từ Java, cho tốt hơn hoặc tệ hơn ...
Scala không ghi đè định nghĩa từ String nguyê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 là 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 tách phù hợp cuối cùng. Nếu n là 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ó bất kỳ độ dài nào và các chuỗi rỗng 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", "", "")

Dường như hành vi Java nổi tiếng là hơi bối rối nhưng:

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

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

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

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


1
2017-10-20 04:47