ฉันจะรับอักขระ n ตัวแรกของสตริงโดยไม่ตรวจสอบขนาดหรือออกนอกขอบเขตได้อย่างไร


163

ฉันจะได้รับขึ้นอยู่กับวิธีแรกที่nตัวละครของสตริงใน Java โดยไม่ต้องทำการตรวจสอบขนาดแรก (อินไลน์เป็นที่ยอมรับ) หรือการเสี่ยงIndexOutOfBoundsException?


1
ถ้าคุณไม่ได้รับการยกเว้นฉันไม่รู้ว่าคุณวางแผนรับมือกับกรณีที่ความยาวอักขระมากกว่าความยาวสตริงได้อย่างไร
Matt Boehm

2
ทำไม? คุณไม่ชอบการตรวจสอบความยาวหรือข้อยกเว้นอะไร
paxdiablo

1
ด้วยความอยากรู้ทำไมคุณต้องการหลีกเลี่ยงการตรวจสอบขนาด นี่ไม่ใช่ C.
Tom Hawtin - tackline

สิ่งที่ฉันตั้งใจจะแสดงคือความปรารถนาที่จะหลีกเลี่ยง if / else block ไม่ใช่ความรังเกียจที่จะตรวจสอบความยาว
antony.trupe

ซ้ำซ้อนของ: stackoverflow.com/questions/8499698/ …
Mulki

คำตอบ:


347

นี่เป็นวิธีที่เรียบร้อย:

String upToNCharacters = s.substring(0, Math.min(s.length(), n));

ความเห็น: ในขณะที่วิธีการแก้ปัญหานี้เป็น "เรียบร้อย" ฉันคิดว่าจริง ๆ แล้วมันสามารถอ่านได้น้อยกว่าโซลูชันที่ใช้if/ elseอย่างชัดเจน หากผู้อ่านยังไม่เห็นเคล็ดลับนี้เขา / เธอต้องคิดให้เข้าใจรหัสมากขึ้น IMO ความหมายของรหัสนั้นชัดเจนมากขึ้นในif/ elseรุ่น สำหรับโซลูชันที่อ่านได้ง่ายขึ้นดูคำตอบของ @ paxdiablo


1
+1 ยิ่งไปกว่านั้นถ้าสิ่งนี้ถูกห่อหุ้มในฟังก์ชั่นที่ชื่อว่า safe_substring หรือ substring_safe เช่นคำตอบของ paxdiablo ดังนั้นการใช้งานจะง่ายต่อการอ่าน / ตั้งใจชัดเจนขึ้น
ToolmakerSteve

ฉันไม่เห็นด้วยกับสิ่งที่คุณพูด ถ้าสิ่งนี้ถูกห่อหุ้มอยู่ในฟังก์ชั่นมันไม่สำคัญว่าสิ่งที่อยู่ภายในฟังก์ชั่นและ "ความเรียบร้อย" ใด ๆ ที่ได้รับการชั่งน้ำหนักอย่างแน่นอนจากการขาดความชัดเจน ประเด็นของการแก้ปัญหานี้คือ "เรียบร้อย" สำหรับกรณีที่คุณไม่ต้องการสร้างฟังก์ชั่น wrapper
Stephen C

88

อย่าประดิษฐ์ล้อใหม่ ... :

org.apache.commons.lang.StringUtils.substring(String s, int start, int len)

Javadocพูดว่า:

StringUtils.substring(null, *, *)    = null
StringUtils.substring("", * ,  *)    = "";
StringUtils.substring("abc", 0, 2)   = "ab"
StringUtils.substring("abc", 2, 0)   = ""
StringUtils.substring("abc", 2, 4)   = "c"
StringUtils.substring("abc", 4, 6)   = ""
StringUtils.substring("abc", 2, 2)   = ""
StringUtils.substring("abc", -2, -1) = "b"
StringUtils.substring("abc", -4, 2)  = "ab"

ดังนั้น:

StringUtils.substring("abc", 0, 4) = "abc"

1
ไม่ตอบคำถาม แต่ไม่ว่าจะยังคงมีวิธีแก้ปัญหา ถ้า OP สามารถเข้าใจได้ฉันคิดว่านี่เป็นทางออกที่ดีกว่า
aullah

5
นอกจากนี้ยังอาจเป็นประโยชน์ในการชี้ให้เห็นว่าไม่ได้เป็นเช่นเดียวกับStringUtils.substring(yourString, 0, n) yourString.substring(0, n)อดีตคือจากStringUtilsในขณะที่หลังใช้String.substring(ซึ่งให้ยกเว้นถ้าดัชนีสิ้นสุดเกินความยาวสตริง)
ToolmakerSteve

เช่นเดียวกับ FYI หากคุณมองหาแหล่งที่มาของวิธีการนี้มันจะจัดการกับกรณีที่จุดสิ้นสุดมีความยาวมากกว่าความยาวโดยเปลี่ยนจุดสิ้นสุดเป็นความยาว:if (end > str.length()) { end = str.length();}
bholl

1
พารามิเตอร์สุดท้ายของStringUtils.substring(String s, int start, int len)ไม่ใช่ len มันคือ end-Index
gorootde

StringUtils.substring ("abc", 0, 4) = "abc" ได้ผลสำหรับฉัน ขอบคุณมาก!
Akash5288

42

Apache Commons LangมีStringUtils.leftวิธีการนี้

String upToNCharacters = StringUtils.left(s, n);

นี่ไม่ควรเป็นทางออกที่ดีที่สุดหรือ เหตุใดจึงไม่ลงคะแนนนี้มากนัก
จะ

3
อาจเป็นเพราะคนอื่นไม่มีความเห็นแบบเดียวกันกับคุณ? :-)
Stephen C

คำตอบนี้มาช้ากว่าวันถามคำถามเดิม
Mulki

@DoWill: เนื่องจากการเพิ่มไลบรารี่ของบุคคลที่สามเข้ากับสภาพแวดล้อมการปฏิบัติการของคุณนั้นไม่คุ้มค่าเสมอไป
LarsH

12

มีคำถามหลายระดับเกี่ยวกับ SO ดังนั้นบางครั้งก็ใช้ความรู้สึกที่ไม่สมบูรณ์แบบบางครั้งคำถามนี้ปิดอย่างน่ากลัว :-)

บางทีคุณอาจอธิบายความเกลียดชังของคุณโดยใช้หนึ่งในสองวิธีที่คุณตัดออก

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

static String substring_safe (String s, int start, int len) { ... }

ซึ่งจะตรวจสอบความยาวล่วงหน้าและดำเนินการตามนั้น (ส่งคืนสตริงที่มีขนาดเล็กกว่าหรือแผ่นที่มีช่องว่าง)

จากนั้นคุณไม่ต้องกังวลกับมันในรหัสของคุณเลยเพียงแค่โทร:

String s2 = substring_safe (s, 10, 7);

แทน:

String s2 = s.substring (10,7);

สิ่งนี้จะได้ผลในกรณีที่คุณกังวล (ตามความเห็นของคุณสำหรับคำตอบอื่น ๆ ) ไม่ทำลายการไหลของรหัสเมื่อทำสิ่งที่สร้างสตริงจำนวนมาก


1
คุณควรอ่านความคิดเห็นเพิ่มเติมอย่างใกล้ชิด @antony โดยเฉพาะอย่างยิ่งยิ้มและไม่ได้มีค่ามากเกี่ยวกับผู้ที่พยายามช่วย ฉันแค่บอกว่าคุณไม่ได้ให้เหตุผลว่าทำไมคุณต้องหลีกเลี่ยงทั้งสองวิธี และนี่คือคำตอบที่แท้จริงโดยใช้ฟังก์ชั่นตัวช่วยซึ่งเป็นสาเหตุที่มันไม่ได้อยู่ในความคิดเห็น
paxdiablo

1
+1: นี่เป็นวิธีที่ดีกว่าวิธีที่ยอมรับมากเนื่องจากความปรารถนาของ OP ที่จะไม่เกะกะรหัส (หรือดูโซลูชันของ Nickkk ในการรวมไลบรารีที่มีฟังก์ชันที่ทำงานตามที่ต้องการอยู่แล้ว)
ToolmakerSteve

12
String upToNCharacters = String.format("%."+ n +"s", str);

น่ากลัวถ้าnเป็นตัวแปร (ดังนั้นคุณต้องสร้างสตริงรูปแบบ) แต่ค่อนข้างชัดเจนถ้าค่าคงที่:

String upToNCharacters = String.format("%.10s", str);

เอกสาร


ทางเลือกที่น่าสนใจแม้ว่าฉันจะนึกภาพไม่ออกเลยว่าใช้มันแบบเดิม ๆ มากกว่าเดิมเมื่อสี่ปีก่อน
ToolmakerSteve

คำตอบที่ดีที่สุดเพราะ Input String อ่านได้เพียงครั้งเดียวดังนั้นจึงไม่จำเป็นต้องเก็บไว้ในตัวแปรซึ่งทำให้สามารถฝังได้อย่างเรียบร้อย
Profiterole

3

ใช้วิธีการ substring ดังต่อไปนี้:

int n = 8;
String s = "Hello, World!";
System.out.println(s.substring(0,n);

หาก n มากกว่าความยาวของสตริงสิ่งนี้จะส่งข้อยกเว้นเนื่องจากผู้วิจารณ์คนหนึ่งชี้ไป วิธีแก้ไขปัญหาอย่างง่ายอย่างหนึ่งคือการรวมทั้งหมดนี้ไว้ในเงื่อนไขif(s.length()<n)ในelseข้อของคุณคุณสามารถเลือกได้ว่าคุณต้องการพิมพ์ / ส่งคืนสตริงทั้งหมดหรือจัดการด้วยวิธีอื่น


1
ความเสี่ยงนี้จะได้รับ IndexOutOfBoundsException
antony.trupe

อย่างไรก็ตามถ้าคุณวางแผนที่จะเขียนโปรแกรมใน Java คุณควรพยายามจดจำวิธีการ API ส่วนใหญ่สำหรับ String ( java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html )
Matt Boehm

ฉันได้ตัดย่อยสตริงออกแล้วอย่างน้อยก็ไม่ใช่คำตอบ
antony.trupe

คุณต้องตรวจสอบขนาดหรือตรวจสอบข้อยกเว้น ฉันขอถามได้ไหมว่าทำไมการทำอย่างใดอย่างหนึ่งต่อไปนี้จึงไม่สามารถทำงานได้ในสถานการณ์ของคุณ?
Matt Boehm

3
นี่เป็นคำตอบของคำถามได้อย่างไร คำถามนั้นถามว่าจะไม่ต้องทำการตรวจสอบขนาดก่อนหรือทำให้เกิดข้อยกเว้นที่จำเป็นต้องถูกตรวจจับ
ToolmakerSteve

3

หากคุณโชคดีพอที่จะพัฒนากับ Kotlin
คุณสามารถใช้takeเพื่อให้บรรลุเป้าหมาย

val someString = "hello"

someString.take(10) // result is "hello"
someString.take(4) // result is "hell" )))

0

ApacheCommons ทำให้ฉันประหลาดใจ StringUtils.abbreviate(String str, int maxWidth)ผนวก "... " ไม่มีตัวเลือกในการเปลี่ยน postfix WordUtils.abbreviate(String str, int lower, int upper, String appendToEnd)เงยหน้าขึ้นมองพื้นที่ว่างถัดไป

ฉันแค่จะออกจากที่นี่:

public static String abbreviate(String s, int maxLength, String appendToEnd) {
    String result = s;
    appendToEnd = appendToEnd == null ? "" : appendToEnd;
    if (maxLength >= appendToEnd.length()) {
        if (s.length()>maxLength) {
            result = s.substring(0, Math.min(s.length(), maxLength - appendToEnd.length())) + appendToEnd;
        }
    } else {
        throw new StringIndexOutOfBoundsException("maxLength can not be smaller than appendToEnd parameter length.");
    }
    return result;
}

1
@ VolkanGüvenมันเป็นเพราะประโยค "ApacheCommons ทำให้ฉันประหลาดใจ" ฉันทำบาปผ่านห้องสมุด ApacheCommons อันศักดิ์สิทธิ์ หรืออะไรก็ตาม ...
yuceel

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