如何在不检查大小或越界的情况下获得一个字符串的前 n 个字符?

如何在 Java 中获得一个字符串的前 n 个字符而不做大小检查(内联是可接受的)或冒 IndexOutOfBoundsException 的风险?

329837 次浏览

使用子字符串方法,如下所示:

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

如果n大于字符串长度,就会抛出异常,正如一位评论者指出的那样。一个简单的解决方案是将所有这些都包装在else子句中的if(s.length()<n)条件中,你可以选择只是打印/返回整个String或以另一种方式处理它。

这里有一个简单的解决方案:

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

意见:虽然这个解决方案是"整洁",我认为它实际上是可读性比一个解决方案使用if / else明显。如果读者没有见过这个技巧,他/她必须更努力地思考才能理解代码。在我看来,该代码的含义在if / else版本中更为明显。要获得更清晰/更可读的解决方案,请参见@paxdiablo's answer

有一类关于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);

这将在你似乎担心的情况下工作(基于你对其他答案的评论),而不是在做大量字符串构建的东西时破坏代码流。

别白费力气了…

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"
String upToNCharacters = String.format("%."+ n +"s", str);

如果n是一个变量(所以你必须构造格式字符串)就很糟糕了,但如果是常量就很清楚了:

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

docs

Apache Commons Lang对此有一个StringUtils.left方法。

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

ApacheCommons惊讶我, StringUtils.abbreviate(String str, int maxWidth)附加"…",没有选项可以更改后缀。

. 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;
}