เหตุใดการ "แยก" บนสตริงว่างจึงส่งคืนอาร์เรย์ที่ไม่ว่างเปล่า


111

การแยกสตริงว่างจะส่งกลับอาร์เรย์ขนาด 1:

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

พิจารณาว่าสิ่งนี้ส่งคืนอาร์เรย์ว่าง:

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

กรุณาอธิบาย :)


5
นอกจากนี้ดูเหมือนว่าไม่สอดคล้องกับลักษณะการทำงานที่สังเกตได้เมื่อสตริงมีเพียงอินสแตนซ์เดียวของตัวคั่น ในกรณีนี้ผลลัพธ์คืออาร์เรย์ว่างอย่างมีประสิทธิภาพ: ",". split (","). length == 0
LD

คำตอบ:


37

ด้วยเหตุผลเดียวกันว่า

",test" split ','

และ

",test," split ','

จะส่งคืนอาร์เรย์ขนาด 2 ทุกอย่างก่อนที่การจับคู่แรกจะถูกส่งกลับเป็นองค์ประกอบแรก


5
สตริงว่างคือสตริงไม่ใช่อะไรเลย (ทุกที่ยกเว้นใน Excel)
Raphael

5
@Raphael หรือในฐานข้อมูล Oracle
Austin

7
@Raphael ในภาษาการเขียนโปรแกรมอื่น ๆ"".split("wtf").lengthจะส่งกลับ 0 เฉพาะใน JS เท่านั้น: /
Andrey Mikhaylov - lolmaus

11
@ DanielC.Sobral เอาล่ะทำไม"," split ","ส่งกลับอาร์เรย์เป็น 0
Joan

5
ทำไมทุกอย่างถึงไม่กลับมาเหมือนกัน?
Didier A.

72

ถ้าคุณแบ่งส้มเป็นศูนย์คุณจะมีชิ้นเดียว - สีส้ม


8
แต่ส้มไม่ว่าง (idk ถ้านั่นคือความหมายของ oluies) มันเป็นสีส้ม อาจจะแยกสีส้มที่ควรจะมี แต่ไม่ใช่ดังนั้นคุณจะได้รับค่าเดียว: พื้นที่ว่าง xD
Nick Rolando

8
นี่คือบทสนทนาที่ลึกซึ้ง

31
คำอุปมานี้มีเหตุผลสำหรับ"orange".split(',')แต่ไม่ชัดเจนว่าเกี่ยวข้องกับการแยกสตริงว่างเปล่า ถ้าฉันแยกการขาดสีส้มเป็นศูนย์ครั้งฉันก็ยังไม่มีสีส้ม เราแสดงว่าเป็นรายการที่ไม่มีส้มรายการหนึ่งไม่มีส้มรายการส้มสิบสองผลหรืออะไร ไม่ใช่คำถามว่าเราลงเอยด้วยอะไร แต่เราเป็นตัวแทนของมันอย่างไร
Matchu

1
แต่ถ้าคุณแยกหนังสือที่ไม่มีอยู่จริงตามหน้าหนังสือคุณจะไม่ได้อะไรเลย
SMUsamaShah

49

วิธีการแยก Java และ Scala ทำงานในสองขั้นตอนดังนี้:

  • ขั้นแรกให้แยกสตริงด้วยตัวคั่น ผลที่ตามมาคือถ้าสตริงไม่มีตัวคั่นอาร์เรย์เดี่ยวที่มีเพียงสตริงอินพุตจะถูกส่งกลับ
  • ประการที่สองลบสตริงว่างขวาสุดทั้งหมด นี่คือเหตุผลที่",,,".split(",")ส่งคืนอาร์เรย์ว่าง

ตามนี้ผลลัพธ์ของ"".split(",")ควรจะเป็นอาร์เรย์ว่างเนื่องจากขั้นตอนที่สองใช่ไหม?

มันควรจะ. น่าเสียดายที่นี่เป็นเคสเข้ามุมที่นำมาใช้โดยเทียม และนั่นเป็นสิ่งที่ไม่ดี แต่อย่างน้อยก็มีการบันทึกไว้java.util.regex.Patternหากคุณจำไว้ว่าให้ดูเอกสาร:

สำหรับ n == 0 ผลลัพธ์จะเป็นสำหรับ n <0 ยกเว้นสตริงว่างที่ต่อท้ายจะไม่ถูกส่งกลับ (โปรดทราบว่ากรณีที่อินพุตเป็นสตริงว่างนั้นเป็นแบบพิเศษตามที่อธิบายไว้ข้างต้นและพารามิเตอร์ขีด จำกัด จะไม่ใช้ที่นั่น)

โซลูชันที่ 1: ส่ง -1 เป็นพารามิเตอร์ที่สองเสมอ

ดังนั้นฉันขอแนะนำให้คุณส่งผ่านn == -1เป็นพารามิเตอร์ที่สองเสมอ(ซึ่งจะข้ามขั้นตอนที่สองด้านบน) เว้นแต่คุณจะทราบโดยเฉพาะว่าคุณต้องการบรรลุอะไร / คุณแน่ใจว่าสตริงว่างไม่ใช่สิ่งที่โปรแกรมของคุณจะได้รับเป็นอินพุต

โซลูชันที่ 2: ใช้คลาส Guava Splitter

หากคุณใช้ Guava ในโปรเจ็กต์ของคุณอยู่แล้วคุณสามารถลองใช้คลาสSplitter (เอกสารประกอบ) มี API ที่สมบูรณ์มากและทำให้โค้ดของคุณเข้าใจง่ายมาก

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 นี่เป็นคำตอบเดียวที่อ้างถึงเอกสารจริงและชี้ให้เห็นว่าไม่สอดคล้องกัน อย่างไรก็ตามฉันไม่พบส่วนที่ไฮไลต์ของความคิดเห็นใน JavaDoc ของฉัน
Yogu

ฉันพบมันใน java.util.regex.Pattern แต่ดูเหมือนว่าส่วนใหญ่จะหายไป ในขณะที่เขียนมันมีอยู่ในแผนผังแหล่ง OpenJDK อย่างเป็นทางการในรูปแบบ javadoc android.googlesource.com/platform/libcore/+/… บางทีเราควรรายงานข้อผิดพลาด?
Rok Kralj

เป็นความคิดที่ดีที่จะรายงานข้อบกพร่อง - พฤติกรรมจะไม่เปลี่ยนแปลงอย่างแน่นอน แต่อย่างน้อยควรมีการบันทึกไว้
Yogu

@RokKralj Android ไม่ได้ใช้ไลบรารี OpenJDK แต่ใช้ Apache Harmony แทนดังนั้นคุณอาจมองผิดที่?
lxgr

1
"".split (",", n)สร้างอาร์เรย์องค์ประกอบหนึ่งรายการสำหรับ n in (-1, 0, 1) ด้วย Oracle JDK 8 จะเป็นการดีที่จะได้รับรายการโทเค็นที่ไม่ว่างเปล่าเท่านั้น - เดาว่าอาจจำเป็นต้องใช้ regex แบบเต็ม (บางอย่างเช่น"[^,\\s]+[^,]*[^,\\s]*")
simon.watts

40

การแยกสตริงว่างจะส่งคืนสตริงว่างเป็นองค์ประกอบแรก หากไม่พบตัวคั่นในสตริงเป้าหมายคุณจะได้รับอาร์เรย์ขนาด 1 ที่เก็บสตริงเดิมแม้ว่าจะว่างเปล่าก็ตาม


2
ไม่ถูกต้อง. Split จะลบสตริงว่างขวาสุดทั้งหมดดังนั้นผลลัพธ์ควรเป็นอาร์เรย์ว่าง ดูคำตอบของฉัน ",".split(",")ส่งคืนอาร์เรย์ว่าง
Rok Kralj

23

"a".split(",")-> "a" ดังนั้น "".split(",")->""


6
ไม่ถูกต้อง. Split จะลบสตริงว่างขวาสุดทั้งหมดดังนั้นผลลัพธ์ควรเป็นอาร์เรย์ว่าง ดูคำตอบของฉัน ",".split(",")ส่งคืนอาร์เรย์ว่าง
Rok Kralj

5

ในภาษาโปรแกรมทั้งหมดฉันรู้ว่าสตริงว่างยังคงเป็นสตริงที่ถูกต้อง ดังนั้นการแยกโดยใช้ตัวคั่นใด ๆ จะส่งคืนอาร์เรย์องค์ประกอบเดียวเสมอโดยที่องค์ประกอบนั้นเป็นสตริงว่าง หากเป็นสตริงว่าง (ไม่ว่าง) นั่นจะเป็นปัญหาอื่น


ฉันคิดว่านี่เป็นฟังก์ชันห้องสมุดไม่ใช่ส่วนหนึ่งของภาษา ตัวอย่างเช่นใน google guava คุณสามารถเว้นสตริงว่างได้ > <String> ชิ้นที่ทำซ้ำได้ = com.google.common.base.Splitter.on (','). omitEmptyStrings (). split ("");
oluies

2

นี้splitพฤติกรรมที่จะรับมาจาก Java สำหรับดีขึ้นหรือแย่ลง ...
Scala ไม่แทนที่คำนิยามจากStringดั้งเดิม

โปรดทราบว่าคุณสามารถใช้limitอาร์กิวเมนต์เพื่อแก้ไขลักษณะการทำงาน :

พารามิเตอร์ขีด จำกัด ควบคุมจำนวนครั้งที่ใช้รูปแบบดังนั้นจึงมีผลต่อความยาวของอาร์เรย์ผลลัพธ์ ถ้าขีด จำกัด n มีค่ามากกว่าศูนย์รูปแบบจะถูกนำไปใช้มากที่สุด n - 1 เท่าความยาวของอาร์เรย์จะไม่เกิน n และรายการสุดท้ายของอาร์เรย์จะมีอินพุตทั้งหมดที่อยู่นอกเหนือจากตัวคั่นที่ตรงกันล่าสุด ถ้า n ไม่เป็นค่าบวกรูปแบบจะถูกนำไปใช้กี่ครั้งก็ได้และอาร์เรย์จะมีความยาวเท่าใดก็ได้ ถ้า n เป็นศูนย์รูปแบบจะถูกนำไปใช้กี่ครั้งก็ได้อาร์เรย์สามารถมีความยาวเท่าใดก็ได้และการต่อท้ายสตริงว่างจะถูกทิ้ง

กล่าวคือคุณสามารถตั้งค่าlimit=-1ให้รับพฤติกรรมของ (ทั้งหมด?) ภาษาอื่น:

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

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

ดูเหมือนว่าจะเป็นที่รู้จักกันดีว่าพฤติกรรมของ Java ค่อนข้างสับสนแต่:

พฤติกรรมข้างต้นสามารถสังเกตได้ตั้งแต่ Java 5 ถึง Java 8 เป็นอย่างน้อย

มีความพยายามที่จะเปลี่ยนพฤติกรรมเพื่อกลับอาร์เรย์ที่ว่างเปล่าคือเมื่อแยกสตริงที่ว่างเปล่าในJDK-6559590 อย่างไรก็ตามในไม่ช้ามันก็ถูกเปลี่ยนกลับในJDK-8028321เมื่อมันทำให้เกิดการถดถอยในที่ต่างๆ การเปลี่ยนแปลงนี้ไม่เคยทำให้เป็นรุ่น Java 8 เริ่มต้น

หมายเหตุ: วิธีการแบ่งไม่ได้อยู่ใน Java ตั้งแต่ต้น ( ไม่ใช่ใน 1.0.2 ) แต่จริงๆแล้วมีตั้งแต่อย่างน้อย 1.4 (เช่นดูJSR51ประมาณปี 2545) ฉันยังคงตรวจสอบ ...

อะไรคือเหตุผลที่ชัดเจน Java เลือกนี้ในสถานที่แรก (ความสงสัยของผมก็คือว่ามันเดิมกำกับดูแล / ข้อผิดพลาดในกรณี "ขอบ") แต่ตอนนี้อบถาวรเป็นภาษาและอื่น ๆก็ยังคง


ฉันไม่แน่ใจว่านี้สามารถตอบคำถาม - ในขณะที่มันอาจจะเป็นจริงตัวอย่างเช่นให้ที่นี่ก็ไม่ได้ความช่วยเหลือเกี่ยวกับกรณีของสตริงที่ว่างเปล่า - ยังคงส่งกลับอาร์เรย์องค์ประกอบเดียวเช่น"".split(",") [""]
DaveyDaveDave

@DaveyDaveDave นั่นคือพฤติกรรมที่คาดหวังของทุกภาษา ",,,," เป็นพฤติกรรมที่แปลกประหลาด / แตกต่างใน Scala และแตกต่างกันกับกรณี ""
Andy Hayden

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.