基于字符串长度截取字符串

199
我想要在字符串长度超过10个字符时对其进行裁剪。
假设字符串长度为12(String s="abcdafghijkl"),那么新的裁剪后的字符串将包含"abcdefgh.."
我该如何实现这个功能?

6
可能是 up to first N characters 的重复问题。 - Stephen C
请注意,水平省略号是一个单一的字符,而不是两个或三个句号字符:… - Basil Bourque
12个回答

357
s = s.substring(0, Math.min(s.length(), 10));
使用像这样的Math.min可以避免在字符串已经短于10的情况下出现异常。 注意:以上代码只是简单地修剪了字符串。如果您想在字符串太长时用三个点替换最后的字符,请使用Apache Commons StringUtils.abbreviate; 参见@H6的解答。如果您想使用Unicode水平省略号字符,请参见@Basil的解答。对于典型的String实现,s.substring(0, s.length())将返回s而不是分配一个新的String。 如果您的字符串包含超出BMP范围的Unicode代码点(例如表情符号),那么此操作可能会导致错误行为1。有一个(更复杂的)解决方案可以正确处理所有Unicode代码点,请参见@sibnick的解答。 请注意:String.length()不是Unicode文本长度的好指标,因此基于该属性进行修剪可能是错误的做法。1

我们能否进行条件检查,只有在字符串超过所需长度时才进行子字符串操作,而不是使用Math.min函数?例如:s = (s.length() > 10) ? s.substring(0,10) : s ; - rram
1
如果你进入substring方法,你会发现这个行为实际上是在幕后完成的。 - Alexander.Iljushkin

166

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
12
问题显示了8个字符后面跟着2个点,长度限制为10,这很像省略号(只有2个点而不是3个)。许多发现这个问题的人可能认为省略号很有用。 - ToolmakerSteve
15
如果不想使用省略号,可以使用StringUtils.left()来帮助你。 - Superole
2
请注意,水平省略号是一个单一的字符,而不是三个句号字符:… - Basil Bourque

84
有一个Apache Commons的StringUtils函数可以实现此功能。
s = StringUtils.left(s, 10)

如果len个字符不可用或String为null,则String将无异常返回。如果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 Courtesy:Steeve McCauley

30

像往常一样,没人关心UTF-16代理对。请查看以下内容:哪些非BMP Unicode字符在实际使用中最常见?即使是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
在Apache commons的jira中发现了一个bug:https://issues.apache.org/jira/browse/LANG-1343 - Ryan Quinn

10

或者,如果您手头没有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

9

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


18
substring 的第二个参数是排除的,因此此答案将字符串截断为 9 个字符。 - emulcahy

5

这个问题是关于Java的,但是回答是在2014年提出的。
如果你现在使用Kotlin,那么它就非常简单了:

Original Answer翻译成"最初的回答"

yourString.take(10)

该函数返回一个包含该字符串的前n个字符的字符串,如果该字符串长度小于n,则返回整个字符串。 文档

注意:如果您正在寻找Kotlin相关的答案,请在“[kotlin]”标签中搜索Q&A,并在“[kotlin]”标签中提问。 - Stephen C

5

简而言之

你似乎在最后一个位置截断时需要一个省略号(ellipsis))字符。这里有一个一行代码来操作你的输入字符串。

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

查看此代码在IdeOne.com上运行。

abcdefghi…

三元运算符

我们可以使用三元运算符来制作一行代码。

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 9及以后,Java流工具变得更加有趣。但是,这可能不是最佳方法。

我们使用代码点而不是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 ) + "…";
}

如果我能想到一种方法将流线与“超过限制时,进行省略号”部分结合起来就好了。

5

如果您正在寻找一种方法来截取并保留字符串的最后10个字符,以下是一个示例:

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

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接