ตัดแต่งสตริงตามความยาวสตริง


136

ฉันต้องการตัดสตริงหากความยาวเกิน 10 อักขระ

สมมติว่าหากความยาวสาย 12 ( String s="abcdafghijkl") "abcdefgh.."แล้วสตริงตัดแต่งใหม่จะประกอบด้วย

ฉันจะบรรลุเป้าหมายนี้ได้อย่างไร?


6
เป็นไปได้ที่จะซ้ำกันได้ถึง N อักขระตัวแรก
Stephen C

FYI HORIZONTAL ELLIPSISเป็นอักขระเดี่ยวไม่ใช่อักขระFULL STOPสองหรือสามตัว: …
Basil Bourque

คำตอบ:


262
s = s.substring(0, Math.min(s.length(), 10));

ใช้เช่นนี้หลีกเลี่ยงข้อยกเว้นในกรณีที่สตริงที่มีอยู่แล้วที่สั้นกว่าMath.min10


หมายเหตุ:

  1. ข้างต้นทำการตัดแต่งจริง ถ้าคุณต้องการจริงที่จะมาแทนที่ช่วงสาม (!) ตัวอักษรที่มีจุดถ้ามันตัดทอนแล้วใช้ Apache StringUtils.abbreviateคอมมอนส์

  2. สิ่งนี้อาจทำงานไม่ถูกต้อง1หากสตริงของคุณมีจุดรหัส Unicode นอก BMP เช่น Emojis สำหรับ (ซับซ้อนมากขึ้น) การแก้ปัญหาที่ทำงานอย่างถูกต้องสำหรับทุก Unicode รหัสจุดดู @ sibnick ของการแก้ปัญหา


1 - จุดรหัส Unicode ที่ไม่ได้อยู่บนระนาบ 0 (BMP) จะแสดงเป็น "คู่ตัวแทน" (คือสองcharค่า) ในString. การเพิกเฉยต่อสิ่งนี้เราอาจตัดทอนโค้ดให้น้อยกว่า 10 จุดหรือ (แย่กว่านั้น) ตัดตรงกลางคู่ตัวแทน ในทางกลับกันString.length()ไม่ได้เป็นการวัดความยาวข้อความ Unicode ในอุดมคติอีกต่อไปดังนั้นการตัดแต่งโดยอ้างอิงจากข้อมูลดังกล่าวอาจเป็นสิ่งที่ไม่ถูกต้อง


แทนที่จะเป็น Math.min เราไม่สามารถตรวจสอบเงื่อนไขและทำการสตริงย่อยได้ก็ต่อเมื่อต้องใช้สตริงสูงสุดเท่านั้น? เช่น:s = (s.length() > 10) ? s.substring(0,10) : s ;
rram

1
ใช่แน่นอนคุณทำได้ อ่านคำตอบอื่น ๆ สำหรับวิธีอื่น ๆ ในการแก้ปัญหา!
Stephen C

132

StringUtils.abbreviateจากห้องสมุดApache Commons Langอาจเป็นเพื่อนของคุณ:

StringUtils.abbreviate("abcdefg", 6) = "abc..."
StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
StringUtils.abbreviate("abcdefg", 4) = "a..."

Commons Lang3อนุญาตให้ตั้งค่าสตริงที่กำหนดเองเป็นเครื่องหมายแทนที่ ด้วยวิธีนี้คุณสามารถตั้งค่าจุดไข่ปลาอักขระเดี่ยวได้

StringUtils.abbreviate("abcdefg", "\u2026", 6) = "abcde…"

5
อาจเป็นได้ แต่คำถามของ OP ไม่ถามถึง "จุดไข่ปลา"
Stephen C

9
@StephenC - คำถามแสดงอักขระ 8 ตัวตามด้วยจุด 2 จุดโดยกำหนดความยาวได้ 10 ซึ่งเหมือนกับจุดไข่ปลา (เพียง 2 จุดแทนที่จะเป็น 3) เป็นไปได้ว่าหลาย ๆ คนที่พบคำถามนี้จะคิดว่าจุดไข่ปลามีประโยชน์
ToolmakerSteve

12
... และถ้าคุณไม่ต้องการจุดไข่ปลา StringUtils.left () สามารถช่วยคุณได้
Superole

1
FYI, HORIZONTAL ELLIPSISเป็นอักขระเดี่ยวไม่ใช่อักขระFULL STOPสามตัว: …
Basil Bourque

53

มีStringUtilsฟังก์ชันApache Commons ที่ทำสิ่งนี้

s = StringUtils.left(s, 10)

หากไม่มีอักขระ len หรือสตริงเป็นโมฆะสตริงจะถูกส่งกลับโดยไม่มีข้อยกเว้น สตริงว่างจะถูกส่งกลับหาก len เป็นค่าลบ

StringUtils.left (null, ) = null
StringUtils.left (
, -ve) = ""
StringUtils.left ("", *) = ""
StringUtils.left ("abc", 0) = ""
StringUtils.left (" abc ", 2) =" ab "
StringUtils.left (" abc ", 4) =" abc "

StringUtils.Left JavaDocs

มารยาท: Steeve McCauley


22

ตามปกติไม่มีใครสนใจคู่ตัวแทน UTF-16 ดูเกี่ยวกับพวกเขา: อักขระ Unicode ที่ไม่ใช่ BMP ที่พบบ่อยที่สุดในการใช้งานจริงคืออะไร? แม้แต่ผู้เขียน org.apache.commons / commons-lang3

คุณสามารถเห็นความแตกต่างระหว่างรหัสที่ถูกต้องและรหัสปกติในตัวอย่างนี้:

public static void main(String[] args) {
    //string with FACE WITH TEARS OF JOY symbol
    String s = "abcdafghi\uD83D\uDE02cdefg";
    int maxWidth = 10;
    System.out.println(s);
    //do not care about UTF-16 surrogate pairs
    System.out.println(s.substring(0, Math.min(s.length(), maxWidth)));
    //correctly process UTF-16 surrogate pairs
    if(s.length()>maxWidth){
        int correctedMaxWidth = (Character.isLowSurrogate(s.charAt(maxWidth)))&&maxWidth>0 ? maxWidth-1 : maxWidth;
        System.out.println(s.substring(0, Math.min(s.length(), correctedMaxWidth)));
    }
}

1
พบข้อผิดพลาดใน jira ของ Apache commons: issue.apache.org/jira/browse/LANG-1343
Ryan Quinn

10

s = s.length() > 10 ? s.substring(0, 9) : s;


16
พารามิเตอร์ตัวที่สองของสตริงย่อยเป็นเอกสิทธิ์ดังนั้นคำตอบนี้จึงตัดสตริงเป็น 9 อักขระ
emulcahy

8

หรือคุณสามารถใช้วิธีนี้ในกรณีที่คุณไม่มี StringUtils ในมือ:

public static String abbreviateString(String input, int maxLength) {
    if (input.length() <= maxLength) 
        return input;
    else 
        return input.substring(0, maxLength-2) + "..";
}

รหัสของคุณใช้ไม่ได้สำหรับฉัน ลองสิ่งนี้System.out.println(abbreviateString("ABC\ud83d\udc3bDEF", 6));
T3rm1

4

ในกรณีที่คุณกำลังมองหาวิธีตัดและคงอักขระ 10 ตัวสุดท้ายของสตริงไว้

s = s.substring(Math.max(s.length(),10) - 10);

3

ด้วย Kotlin มันง่ายเหมือน:

yourString.take(10)

ส่งคืนสตริงที่มีอักขระ n ตัวแรกจากสตริงนี้หรือทั้งสตริงหากสตริงนี้สั้นกว่า

เอกสาร


1

TL; DR

ดูเหมือนว่าคุณจะขอตัวละครจุดไข่ปลา ( ) ในตำแหน่งสุดท้ายเมื่อตัดทอน นี่คือหนึ่งซับในการจัดการสตริงอินพุตของคุณ

String input = "abcdefghijkl";
String output = ( input.length () > 10 ) ? input.substring ( 0 , 10 - 1 ).concat ( "…" ) : input;

ดูโค้ดนี้ใช้งานได้ที่ IdeOne.com

ABCDEFGHI ...

ตัวดำเนินการ Ternary

เราสามารถทำให้หนึ่งซับโดยใช้ประกอบ ternary

String input = "abcdefghijkl" ;

String output = 
    ( input.length() > 10 )          // If too long…
    ?                                
    input     
    .substring( 0 , 10 - 1 )         // Take just the first part, adjusting by 1 to replace that last character with an ellipsis.
    .concat( "…" )                   // Add the ellipsis character.
    :                                // Or, if not too long…
    input                            // Just return original string.
;

ดูโค้ดนี้ใช้งานได้ที่ IdeOne.com

ABCDEFGHI ...

สตรีม Java

สิ่งอำนวยความสะดวก Java Streams ทำให้สิ่งนี้น่าสนใจตั้งแต่ Java 9 และใหม่กว่า น่าสนใจ แต่อาจไม่ใช่แนวทางที่ดีที่สุด

เราใช้จุดรหัสมากกว่าcharค่า charประเภทคือมรดกและจะถูก จำกัดย่อยของเป็นไปได้ทั้งหมดUnicodeตัวอักษร

String input = "abcdefghijkl" ;
int limit = 10 ;
String output =
        input
                .codePoints()
                .limit( limit )
                .collect(                                    // Collect the results of processing each code point.
                        StringBuilder::new,                  // Supplier<R> supplier
                        StringBuilder::appendCodePoint,      // ObjIntConsumer<R> accumulator
                        StringBuilder::append                // BiConsumer<R,​R> combiner
                )
                .toString()
        ;

ถ้าเรามีตัวละครส่วนเกินตัดทอนแทนที่ตัวอักษรตัวสุดท้ายที่มี จุดไข่ปลา

if ( input.length () > limit )
{
    output = output.substring ( 0 , output.length () - 1 ) + "…";
}

ถ้าฉันคิดวิธีรวมสายสตรีมด้วยส่วน "ถ้าเกินขีด จำกัด ให้ทำจุดไข่ปลา"


ไม่เห็นได้ชัดว่าเขาต้องการตัดความยาวของสตริงถ้ายาวถึง 11 หรือมากกว่านั้น คุณต้องทำงานกับระบบ AI ใหม่ oO
JD333

1
@ JD333 ความคิดเห็นของคุณหนีฉัน การตัดทอนให้มีความยาว 10 รวมทั้งจุดไข่ปลาคือสิ่งที่ฉันแสดงไว้ที่นี่
Basil Bourque

0
str==null ? str : str.substring(0, Math.min(str.length(), 10))

หรือ,

str==null ? "" : str.substring(0, Math.min(str.length(), 10))

ทำงานร่วมกับ null

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