如何去除字符串中的空格?

30

我正在为一个J2ME应用程序编写此函数,因此我没有一些更高级/现代的Java类可用。在这上面我得到了java.lang.ArrayIndexOutOfBoundsException错误。所以,显然要么它不喜欢我初始化newChars数组的方式,要么我在调用System.arraycopy时做错了什么。

/*
 * remove any leading and trailing spaces
 */
public static String trim(String str) {
    char[] chars = str.toCharArray();
    int len = chars.length;
    // leading
    while ( (len > 0 ) && ( chars[0] == ' ' ) ) {
        char[] newChars = new char[] {}; // initialize empty array
        System.arraycopy(chars, 1, newChars, 0, len - 1);
        chars = newChars;
        len = chars.length;
    }
    // TODO: trailing
    return chars.toString();
}

1
正如指出的那样,我错过了String.trim()方法。然而,我想添加一下我在此期间发现的内容,因为我是一个Java新手,这可能对其他人有所帮助。从System.arraycopy()的文档中可以看到:“如果destPos+length大于dest.length(目标数组的长度),则会抛出IndexOutOfBoundsException异常。”也就是说,我可以通过像这样初始化我的临时数组来修复我的代码:“char[] newChars = new char[len - 1];” - user458442
8个回答

42
简单地去除前导和后置空格的方法是调用 String.trim()。从Java 11开始,您还可以使用String.strip(),它使用了不同的“空白”解释方式1
如果您只想去除前导和后置空格(而不是所有前导和后置空格),则有一个叫做StringUtils.strip(String, String)的Apache commons方法可以完成此操作;将其作为第二个参数调用" "
您尝试的代码存在许多错误,并且基本上效率低下。如果您真的想要自己实现这个功能,则应该:
  1. 计算前导空格字符数。
  2. 计算尾随空格字符数。
  3. 如果任一计数值非零,则调用String.substring(from, end)来创建一个包含要保留的字符的新字符串。
此方法避免了复制任何字符2

1 - 不同含义的解释在相应的javadocs中说明。或者,阅读Java 11中String trim()和strip()方法之间的区别的答案。

2 - 实际上,这取决于String的实现。对于某些实现,不会进行任何复制;对于其他实现,可能会进行一次复制。但无论哪种情况,都比您的方法要好,因为您的方法至少需要复制两次,如果要修剪任何字符,则需要更多次。


14

String.trim()非常古老,至少在Java 1.3中就有了。你没有它吗?


1
实际上,是的 - 当我寻找解决方案时,不知怎么错过了它。:/ 非常感谢。 - user458442
1
IIRC trim() was in Java 1.1 - Stephen C

4

Apache StringUtils.strip 是最佳答案,适用于所有预期的空格字符(不仅仅是空格),并且 可以在此处下载

这里是相关代码从此源文件中提取以在您自己的类中实现它,但实际上,只需下载并使用StringUtils即可获得更多收益!请注意,您也可以使用StringUtils.stripStart从java字符串中修剪任何前导字符。

public static final int INDEX_NOT_FOUND = -1

public static String strip(final String str) {
    return strip(str, null);
}

public static String stripStart(final String str, final String stripChars) {
    int strLen;
    if (str == null || (strLen = str.length()) == 0) {
        return str;
    }
    int start = 0;
    if (stripChars == null) {
        while (start != strLen && Character.isWhitespace(str.charAt(start))) {
            start++;
        }
    } else if (stripChars.isEmpty()) {
        return str;
    } else {
        while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
            start++;
        }
    }
    return str.substring(start);
}

public static String stripEnd(final String str, final String stripChars) {
    int end;
    if (str == null || (end = str.length()) == 0) {
        return str;
    }

    if (stripChars == null) {
        while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
            end--;
        }
    } else if (stripChars.isEmpty()) {
        return str;
    } else {
        while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
            end--;
        }
    }
    return str.substring(0, end);
}

public static String strip(String str, final String stripChars) {
    if (str == null || str.length() == 0) {
        return str;
    }
    str = stripStart(str, stripChars);
    return stripEnd(str, stripChars);
}

2
为了照顾盲目的复制粘贴者:public static final int INDEX_NOT_FOUND = -1; - Mike
糟糕!谢谢你的提示 - 我刚刚添加了它。 - Brad Parks

3
首先,其他人提到的String.trim()是正确的。真的,不要重复造轮子。
但是为了记录,你代码中出错的原因是Java数组不可调整大小。当你最初设置目标数组时,你将其创建为大小为0的数组。然后告诉System.arraycopy将len-1个字符放入其中。那是行不通的。如果你想让它起作用,你需要这样设置数组:
char[] newChars = new char[len - 1];

但这是相当低效的,每次循环重新分配和复制一个新数组。使用 Stephen C 提到的三步骤,最后以 substring 结束。


3

现在使用JDK/11,您可以利用 String.strip API 返回一个值为此字符串的字符串,并删除所有前导和尾随空格。相应的javadoc如下:

/**
 * Returns a string whose value is this string, with all leading
 * and trailing {@link Character#isWhitespace(int) white space}
 * removed.
 * <p>
 * If this {@code String} object represents an empty string,
 * or if all code points in this string are
 * {@link Character#isWhitespace(int) white space}, then an empty string
 * is returned.
 * <p>
 * Otherwise, returns a substring of this string beginning with the first
 * code point that is not a {@link Character#isWhitespace(int) white space}
 * up to and including the last code point that is not a
 * {@link Character#isWhitespace(int) white space}.
 * <p>
 * This method may be used to strip
 * {@link Character#isWhitespace(int) white space} from
 * the beginning and end of a string.
 *
 * @return  a string whose value is this string, with all leading
 *          and trailing white space removed
 *
 * @see Character#isWhitespace(int)
 *
 * @since 11
 */
public String strip()

这些内容的示例案例可能包括:--
System.out.println("".strip());
System.out.println("  both  ".strip());
System.out.println("  leading".strip());
System.out.println("trailing  ".strip());

我交换了重复的问题,因为另一个问答拥有更多的浏览量(尽管已经关闭),而这个问答是一个调试问题。我认为你应该在另一个问题下发布这个答案,因为更多的人会看到它。(否则,一些访问该网站的6/7人将无法看到新方法。) - Radiodef
@Radiodef 好的,没问题。已经移动了答案 - Naman
这与trim()函数有何不同? - CuriousCoder
@CuriousCoder 在Java 11中,String的trim()和strip()方法有什么区别? - Naman

1
如果您不想使用String.trim()方法,那么可以按照以下方式实现。该逻辑将处理空格、制表符和其他特殊字符等不同情况。
public static String trim(String str){
    int i=0;
    int j = str.length();
    char[] charArray = str.toCharArray();
    while((i<j) && charArray[i] <=' '){
        i++;
    }
    while((i<j) && charArray[j-1]<= ' '){
        j--;
    }
    return str.substring(i, j+1);

}

public static void main(String[] args) {
    System.out.println(trim("    abcd ght trip              "));

}

0

你可以使用Guava CharMatcher

String outputString = CharMatcher.whitespace().trimFrom(inputString);

注意:这是因为空格都在BMP中。

0
目标数组newChars不够大以容纳复制的值。您需要将其初始化为要复制的数据的长度(因此为length-1)。

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