java中文字符串分割问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中文字符串分割问题相关的知识,希望对你有一定的参考价值。

下列代码为什么不是输出“北京 上海”?为什么分割后数组长度为6?请高手指教,谢谢~
public class NewClass
public static void main(String[] args)
String aaa="北京|上海";
String[] e=aaa.split("|");
System.out.print(e.length);
for(int i=0;i<e.length;i++)
System.out.print("www"+e[i]);

你这个程序有个小毛病,一般是没有做过数据整理及收集的开发者来说是不熟悉字符串的分割原则的
【建议】
在制定分割符时请在左右保留一个空字位的位置,因为一个字符串是否结束,编译器只看末尾是否有空字位,及空字位之后是否有链接符
String aaa="北京|上海";
改为String aaa="北京 | 上海";
length=1,实际是2,因为数组的Index是从0开始的
参考技术A public class NewClass
public static void main(String[] args)
String aaa="北京|上海";
\\严格用符号'|'分割的要转义加\\,因为在正则中符号'|'表示或
String[] e=aaa.split("\\|");
System.out.print(e.length);
for(int i=0;i<e.length;i++)
System.out.print("www"+e[i]);

本回答被提问者采纳
参考技术B split函数分割时,并不是直接将参数字符串作为分隔文字,而是把参数字符串当做正则表达式匹配分割。所以,你的"|"参数被当做了正则表达式的“或”条件。分割结果自然是错误的。

Java字符串分割

前言

本章介绍字符串分割的使用案例,同时会给出一些使用建议。
版本约定

  • JDK 版本:1.8.0_231
  • Java SE API Documentation:https://docs.oracle.com/javase/8/docs/api/

正文

字符串分割,需要注意两个问题:特殊字符和丢失结尾空字符串,我们一个一个来分析。

特殊字符

字符串分割,一般会使用 String 类的 split 方法,比如我需要按照逗号分割字符串。

public static void main(String[] args) 
    String str = "1,2,3,4";
    String[] arr = str.split(",");
    System.out.println(Arrays.toString(arr));

运行程序,输出:

[1, 2, 3, 4]

但是,如果我想通过特殊符号 | 分割字符串呢?

public static void main(String[] args) 
    String str = "1|2|3|4";
    String[] arr = str.split("|");
    System.out.println(Arrays.toString(arr));

运行程序,输出:

[1, |, 2, |, 3, |, 4]

悲剧的发现,执行结果并不是我们期望的结果,这是为什呢?该如何处理呢?

我们先来看下 String 类中 split 方法的注释和源码。

/**
 * Splits this string around matches of the given <a
 * href="../util/regex/Pattern.html#sum">regular expression</a>.
 *
 * <p> This method works as if by invoking the two-argument @link
 * #split(String, int) split method with the given expression and a limit
 * argument of zero.  Trailing empty strings are therefore not included in
 * the resulting array.
 *
 * <p> The string @code "boo:and:foo", for example, yields the following
 * results with these expressions:
 *
 * <blockquote><table cellpadding=1 cellspacing=0 summary="Split examples showin
 * <tr>
 *  <th>Regex</th>
 *  <th>Result</th>
 * </tr>
 * <tr><td align=center>:</td>
 *     <td>@code  "boo", "and", "foo" </td></tr>
 * <tr><td align=center>o</td>
 *     <td>@code  "b", "", ":and:f" </td></tr>
 * </table></blockquote>
 *
 *
 * @param  regex
 *         the delimiting regular expression
 *
 * @return  the array of strings computed by splitting this string
 *          around matches of the given regular expression
 *
 * @throws  PatternSyntaxException
 *          if the regular expression's syntax is invalid
 *
 * @see java.util.regex.Pattern
 *
 * @since 1.4
 * @spec JSR-51
 */
public String[] split(String regex) 
    return split(regex, 0);

传入 split 方法的分割参数其实代表的是一个正则表达式,它是通过正则表达式来实现字符串分割的。

正则表达式中有些字符具有特殊的含义,如果在匹配中要用到它本来的含义,需要进行转义(在其前面加一个 \\),具体哪些字符需要转移,会另外写一篇文章描述。

不得已,我们需要先对分隔符中的正则表达式特殊字符进行转义,才能传入 split 方法。

public static void main(String[] args) 
    String str = "1|2|3|4";
    String[] arr = str.split("\\\\|");
    System.out.println(Arrays.toString(arr));

运行程序,输出:

[1, 2, 3, 4]

这样才能得出正确的结果。

上面讲字符串比较的时候,最后使用了 StringUtils 工具类的中的方法,那字符串分割,它有提供相应的方法么?

答案是肯定的,貌似重载的方法还挺多,功能丰富,先使用一下,看看效果。

public static void main(String[] args) 
    String str = "1|2|3|4";
    String[] arr = StringUtils.split(str, "|");
    System.out.println(Arrays.toString(arr));

程序,输出:

[1, 2, 3, 4]

直接结果正确,而且我也没考虑特殊字符的情况,因为 StringUtils 的 split 方法不是通过正则表达式的方式实现字符串分割的,所以我们也不用考虑正则表达式的特殊字符转义的问题了

丢失结尾空字符串

先猜一下如下代码的执行结果是多少,是不是和你预期的一样?

public static void main(String[] args) 
    String str = "1||3|";
    String[] arr = str.split("\\\\|");
    System.out.println(arr.length);

行程序,输出:

3

根据字符 | 分割的话,我想上面应该能分成 4 断,那执行结果应该 4,为什么这里输出了 3 呢?

查看 String 类的 split 方法,发现它还调用了另外一个重载方法。

public String[] split(String regex) 
    return split(regex, 0);


public String[] split(String regex, int limit) 
    ......

limit 参数表示什么含义呢?根据注释描述,我们知道 limit 参数用来控制模式应用的次数,因此它会影响所得数组的长度。

  • limit 大于 0:则模式将被最多应用 n-1 次,数组的长度将不会大于 n,而且数组的最后一项将包含所有超出最后匹配的定界符的输入。
  • limit 等于 0:则模式将被应用尽可能多的次数,数组可以是任何长度,并且结尾空字符串将被丢弃。
  • limit 小于 0:则模式将被应用尽可能多的次数,数组可以是任何长度。

而 split(String regex) 方法默认传的 limit 值是 0,那就是说执行结果会丢弃结尾的空字符串,刚好上面的例子中的字符串根据字符 | 分割后,结尾就是一个空字符串,所以执行结果是 3。

根据上面的描述,我们如果想保留结尾的空字符串的话,需要调用 split(String regex, int limit) 方法。

public static void main(String[] args) 
    String str = "1||3|";
    String[] arr = str.split("\\\\|", -1);
    System.out.println(arr.length);

运行程序,输出:

4

这样才能达到预期的结果。

我们使用 StringUtils 工具类中的 split 方法试试呢。

public static void main(String[] args) 
    String str = "1||3|";
    String[] arr = StringUtils.split(str, "|");
    System.out.println(arr.length);

运行程序,输出:

2

这个更狠,把空字符串都丢掉了,所以我们平时在写代码的时候,还是需要写 Unit Test 的,需要把可能的场景列出来,通过 Unit Test 覆盖测试一遍,才能知道我们的代码是否健壮,能否达到预期的结果。

StringUtils 工具类中 split 相关的源码比较多,这里就不一一列出来了,大家直接进到该类中,看注释就能找到你需要执行效果的方法。

比如这里我想包含空字符串,不想过滤空字符串的话,可以使用 StringUtils 类中的 splitByWholeSeparatorPreserveAllTokens 方法。

public static void main(String[] args) 
    String str = "1||3|";
    String[] arr = StringUtils.splitByWholeSeparatorPreserveAllTokens(str, "|");
    System.out.println(arr.length);

运行程序,输出:

4

总结

字符串的分割推荐使用 StringUtils 工具类中的 split 方法,如果不想丢失空字符串,推荐使用 StringUtils 工具类中的 splitByWholeSeparatorPreserveAllTokens 方法。

该工具类中有很多 split 的重载方法,在使用的时候根据自己的需要选择。

以上是关于java中文字符串分割问题的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Java 中用逗号和换行符 (\n) 分割字符串? [复制]

在 Java 中每隔 3 个逗号分割一个字符串

Java正则表达式用逗号分割字符串,但忽略引号和括号[重复]

java分割字符串中的汉字和数字问题

java 竖线分割字符串的问题

Java字符串分割