如何防止 java.lang.String.split() 创建一个前导空字符串?

68

将0作为限制参数传递可以防止末尾出现空字符串,但如何防止开头出现空字符串呢?

例如:

String[] test = "/Test/Stuff".split("/");

结果是一个由"", "Test", "Stuff"组成的数组。

我知道我可以自己编写Tokenizer... 但StringTokenizer的API文档说:

"StringTokenizer是一个保留的遗留类,尽管不建议在新代码中使用,但仍然为了兼容性而保留。建议任何寻求此功能的人使用split方法。"

10个回答

51

你最好的选择可能就是删除任何前导分隔符:

String input = "/Test/Stuff";
String[] test = input.replaceFirst("^/", "").split("/");

你可以将它放在一个方法中,使其更加通用:

public String[] mySplit(final String input, final String delim)
{
    return input.replaceFirst("^" + delim, "").split(delim);
}

String[] test = mySplit("/Test/Stuff", "/");

23

Apache Commons有一个实用程序方法来完成这个任务:org.apache.commons.lang.StringUtils.split

StringUtils.split()

实际上,在我们的公司中,我们现在更喜欢在所有项目中使用这种分割方法。


2
似乎不支持像JDK版本那样的正则表达式。 - Stephan

6

我认为使用内置的split方法无法完成这个任务。所以你有两个选择:

1)自己编写一个split方法。

2)在调用split之后遍历数组并删除空元素。

如果您自己编写了split,可以将这两个选项合并。

public List<String> split(String inString)
{
   List<String> outList = new ArrayList<>();
   String[]     test    = inString.split("/");

   for(String s : test)
   {
       if(s != null && s.length() > 0)
           outList.add(s);
   }

   return outList;
}

或者你可以在调用split之前检查分隔符是否位于第一个位置,并忽略第一个字符:

String   delimiter       = "/";
String   delimitedString = "/Test/Stuff";
String[] test;

if(delimitedString.startsWith(delimiter)){
    //start at the 1st character not the 0th
    test = delimitedString.substring(1).split(delimiter); 
}
else
    test = delimitedString.split(delimiter);

2

我认为你需要手动删除第一个空字符串。一种简单的方法是这样的 -

  String string, subString;
  int index;
  String[] test;

  string = "/Test/Stuff";
  index  = string.indexOf("/");
  subString = string.substring(index+1);

  test = subString.split("/"); 

这将排除前导空字符串。


1
但是使用这段代码,如果输入字符串没有前导分隔符,你将跳过第一个组件。例如,"Test/Stuff" 将只产生一个元素 "Stuff"。 - Joe Attardi
好的观点。在那种情况下,将需要进行额外的检查。 - CodeBlue

1

我认为在Java中没有内置的函数可以删除空字符串。你可以通过删除空白字符来消除空字符串,但这可能会导致错误。为了安全起见,你可以编写以下小段代码来实现:

  List<String> list = new ArrayList<String>();

  for(String str : test) 
  {
     if(str != null && str.length() > 0) 
     {
         list.add(str);
     }
  }

  test = stringList.toArray(new String[list.size()]);

1

当使用JDK8和streams时,在split之后添加skip(1)即可。以下代码片段解码一个(非常奇怪的)十六进制编码字符串。

Arrays.asList("\\x42\\x41\\x53\\x45\\x36\\x34".split("\\\\x"))
    .stream()
    .skip(1) // <- ignore the first empty element
    .map(c->""+(char)Integer.parseInt(c, 16))
    .collect(Collectors.joining())

1

split(regex, limit)等Split方法变种也可以在生成的字符串数组的开头或中间产生空字符串。使用Java 8中的流API过滤器方法,下面的代码将删除所有这些空字符串。

示例代码:

String[] tokens = s.split("/");
Arrays.stream(tokens)
.filter(s1 -> !s1.isEmpty())
.forEach(System.out::println);

0

您可以使用StringTokenizer来实现这个目的...

String test1 = "/Test/Stuff";
        StringTokenizer st = new StringTokenizer(test1,"/");
        while(st.hasMoreTokens())
            System.out.println(st.nextToken());

2
StringTokenizer在API中已被标记为过时,可能不应该使用。 - Hunter McMillen
它没有被弃用!!!http://docs.oracle.com/javase/7/docs/api/java/util/StringTokenizer.html - Shashank Kadne
1
@ShashankKadne,虽然它可能没有标注为“已弃用”,但在API页面中确实有这样一行文字:StringTokenizer是一个遗留类,出于兼容性考虑而保留,尽管在新代码中不建议使用。建议任何需要此功能的人改用String的split方法或java.util.regex包。 - Hunter McMillen
@HunterMcMillen:虽然在新代码中不鼓励使用它,但我认为这并不像说它已被弃用那样强烈。 - Shashank Kadne
@ShashankKadne 这意味着它“不应该”被使用。它本应该从语言中删除,但为了与旧版本的Java兼容而保留。 - Hunter McMillen
显示剩余2条评论

0
这是我解决这个问题的方法。我将字符串调用 .toCharArray() 方法将其拆分为字符数组,然后循环遍历该数组并将其添加到我的字符串列表中(使用 String.valueOf 将每个字符包装起来)。我想象中可能会有一些性能折衷,但它似乎是一个可读的解决方案。希望这可以帮助你!
 char[] stringChars = string.toCharArray(); 
 List<String> stringList = new ArrayList<>(); 

 for (char stringChar : stringChars) { 
      stringList.add(String.valueOf(stringChar)); 
 }

-2

在打印字符串之前,您只能添加像if(StringUtils.isEmpty(string)) continue;这样的语句。我的JDK版本是1.8,不会打印空格。 5 这个 程序 给 我 问题


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