พฤติกรรมของString.split
(ที่เรียกPattern.split
) เปลี่ยนไประหว่าง Java 7 และ Java 8
เอกสารประกอบ
เมื่อเปรียบเทียบระหว่างเอกสารของPattern.split
ในJava 7และJava 8เราสังเกตว่ามีการเพิ่มประโยคต่อไปนี้:
เมื่อมีการจับคู่ความกว้างบวกที่จุดเริ่มต้นของลำดับการป้อนข้อมูลแล้วสตริงย่อยชั้นนำที่ว่างเปล่าจะถูกรวมไว้ที่จุดเริ่มต้นของอาร์เรย์ผลลัพธ์ การจับคู่ความกว้างเป็นศูนย์ที่จุดเริ่มต้น แต่จะไม่สร้างสตริงย่อยชั้นนำที่ว่างเปล่า
ประโยคเดียวกันถูกเพิ่มไปยังString.split
ในJava 8เมื่อเทียบกับJava 7
การใช้งานอ้างอิง
ให้เราเปรียบเทียบรหัสของPattern.split
การใช้การอ้างอิงใน Java 7 และ Java 8 รหัสถูกดึงมาจาก grepcode สำหรับเวอร์ชัน 7u40-b43 และ 8-b132
Java 7
public String[] split(CharSequence input, int limit) {
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<>();
Matcher m = matcher(input);
// Add segments before each match found
while(m.find()) {
if (!matchLimited || matchList.size() < limit - 1) {
String match = input.subSequence(index, m.start()).toString();
matchList.add(match);
index = m.end();
} else if (matchList.size() == limit - 1) { // last one
String match = input.subSequence(index,
input.length()).toString();
matchList.add(match);
index = m.end();
}
}
// If no match was found, return this
if (index == 0)
return new String[] {input.toString()};
// Add remaining segment
if (!matchLimited || matchList.size() < limit)
matchList.add(input.subSequence(index, input.length()).toString());
// Construct result
int resultSize = matchList.size();
if (limit == 0)
while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
resultSize--;
String[] result = new String[resultSize];
return matchList.subList(0, resultSize).toArray(result);
}
จาวา 8
public String[] split(CharSequence input, int limit) {
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<>();
Matcher m = matcher(input);
// Add segments before each match found
while(m.find()) {
if (!matchLimited || matchList.size() < limit - 1) {
if (index == 0 && index == m.start() && m.start() == m.end()) {
// no empty leading substring included for zero-width match
// at the beginning of the input char sequence.
continue;
}
String match = input.subSequence(index, m.start()).toString();
matchList.add(match);
index = m.end();
} else if (matchList.size() == limit - 1) { // last one
String match = input.subSequence(index,
input.length()).toString();
matchList.add(match);
index = m.end();
}
}
// If no match was found, return this
if (index == 0)
return new String[] {input.toString()};
// Add remaining segment
if (!matchLimited || matchList.size() < limit)
matchList.add(input.subSequence(index, input.length()).toString());
// Construct result
int resultSize = matchList.size();
if (limit == 0)
while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
resultSize--;
String[] result = new String[resultSize];
return matchList.subList(0, resultSize).toArray(result);
}
การเพิ่มโค้ดต่อไปนี้ใน Java 8 จะไม่รวมการจับคู่ความยาวเป็นศูนย์ที่จุดเริ่มต้นของสตริงอินพุตซึ่งจะอธิบายถึงพฤติกรรมข้างต้น
if (index == 0 && index == m.start() && m.start() == m.end()) {
// no empty leading substring included for zero-width match
// at the beginning of the input char sequence.
continue;
}
การรักษาความเข้ากันได้
ติดตามพฤติกรรมใน Java 8 ขึ้นไป
เพื่อให้split
ทำงานได้อย่างสม่ำเสมอในทุกเวอร์ชันและเข้ากันได้กับพฤติกรรมใน Java 8:
- หาก regex ของคุณสามารถจับคู่สตริงที่มีความยาวเป็นศูนย์ได้ให้เพิ่ม
(?!\A)
ที่ส่วนท้ายของ regex และรวม regex ดั้งเดิมไว้ในกลุ่มที่ไม่ได้จับภาพ(?:...)
(ถ้าจำเป็น)
- หาก regex ของคุณไม่สามารถจับคู่สตริงที่มีความยาวเป็นศูนย์ได้คุณไม่จำเป็นต้องทำอะไรเลย
- หากคุณไม่ทราบว่า regex สามารถจับคู่สตริงที่มีความยาวเป็นศูนย์ได้หรือไม่ให้ทำทั้งสองอย่างในขั้นตอนที่ 1
(?!\A)
ตรวจสอบว่าสตริงไม่ได้สิ้นสุดที่จุดเริ่มต้นของสตริงซึ่งหมายความว่าการจับคู่เป็นการจับคู่ว่างที่จุดเริ่มต้นของสตริง
พฤติกรรมต่อไปนี้ใน Java 7 และก่อนหน้า
ไม่มีวิธีแก้ปัญหาทั่วไปที่จะทำให้split
เข้ากันได้กับ Java 7 และรุ่นก่อนหน้าโดยไม่ต้องแทนที่อินสแตนซ์ทั้งหมดsplit
เพื่อชี้ไปที่การนำไปใช้งานที่คุณกำหนดเอง
s.split("(?!^)")
ดูเหมือนว่าจะทำงาน