将java中的字符串拆分为相等长度的子字符串,同时保持字边界

如何在保持字边界的同时将字符串拆分为最大字符长度的相等部分?

比如说,如果我想将一个字符串“hello world”拆分成最多7个字符的相等子串,它应该返回给我

"hello " 

 "world" 

但我目前的实施回归

 "hello w" 

 "orld " 

我使用以下代码从Split字符串中取代Java中相等长度的子字符串,将输入字符串拆分为相等的部分

 public static List splitEqually(String text, int size) { // Give the list the right capacity to start with. You could use an array // instead if you wanted. List ret = new ArrayList((text.length() + size - 1) / size); for (int start = 0; start < text.length(); start += size) { ret.add(text.substring(start, Math.min(text.length(), start + size))); } return ret; } 

在将字符串拆分为子字符串时是否可以保持字边界?

更具体地说,我需要字符串拆分算法来考虑空格提供的单词边界,而不是仅仅在分割字符串时依赖字符长度,尽管这也需要考虑但更像是字符的最大范围而不是一个硬编码的字符长度。

如果我正确理解你的问题,那么这段代码应该做你需要的(但它假设maxLenght等于或大于最长的单词

 String data = "Hello there, my name is not importnant right now." + " I am just simple sentecne used to test few things."; int maxLenght = 10; Pattern p = Pattern.compile("\\G\\s*(.{1,"+maxLenght+"})(?=\\s|$)", Pattern.DOTALL); Matcher m = p.matcher(data); while (m.find()) System.out.println(m.group(1)); 

输出:

 Hello there, my name is not importnant right now. I am just simple sentecne used to test few things. 

"\\G\\s*(.{1,"+maxLenght+"})(?=\\s|$)"正则表达式的简短解释(或不解释"\\G\\s*(.{1,"+maxLenght+"})(?=\\s|$)"

(让我们记住,在Java \中不仅特殊于正则表达式,而且还在字符串文字中,所以要使用像\d这样的预定义字符集,我们需要将其写为"\\d"因为我们需要将其转义为\字符串字面量)

  • \G – 表示先前创建的匹配结束的锚点,或者如果还没有匹配(当我们刚开始搜索时)字符串的开头(与^相同)
  • \s* – 表示零个或多个空格( \s表示空格, * “零或多个”量词)
  • (.{1,"+maxLenght+"}) – 让它分成更多部分(在运行时:maxLenght将保存一些数值,如10,所以正则表达式会将其视为.{1,10}
    • . 表示任何字符(实际上默认它可以表示除\n\r \n类的行分隔符之外的任何字符,但是由于Pattern.DOTALL标志它现在可以表示任何字符 – 如果要开始拆分,可以删除此方法参数自开始以来,每个句子分别打印在新行中
    • {1,10} – 这是量词,它允许先前描述的元素出现1到10次(默认情况下会尝试找到匹配重复的最大值),
    • .{1,10} – 所以基于我们刚才所说的,它只代表“1到10个任何角色”
    • ( ) – 括号创建组 ,允许我们保持匹配的特定部分的结构(这里我们在\\s*之后添加括号,因为我们只想在空格之后使用部分)
  • (?=\\s|$) – 是先行机制,它将确保匹配.{1,10}文本将在其后:

    • 空间( \\s

      或(写为|

    • 它之后的字符串$的结尾。

谢谢.{1,10}我们最多可以匹配10个字符。 但是在它之后使用(?=\\s|$)我们要求匹配的最后一个字符.{1,10}不是未完成单词的一部分(后面必须有空格或字符串结尾)。

非正则表达式解决方案,以防有人更舒服(?)不使用正则表达式:

 private String justify(String s, int limit) { StringBuilder justifiedText = new StringBuilder(); StringBuilder justifiedLine = new StringBuilder(); String[] words = s.split(" "); for (int i = 0; i < words.length; i++) { justifiedLine.append(words[i]).append(" "); if (i+1 == words.length || justifiedLine.length() + words[i+1].length() > limit) { justifiedLine.deleteCharAt(justifiedLine.length() - 1); justifiedText.append(justifiedLine.toString()).append(System.lineSeparator()); justifiedLine = new StringBuilder(); } } return justifiedText.toString(); } 

测试:

 String text = "Long sentence with spaces, and punctuation too. And supercalifragilisticexpialidocious words. No carriage returns, tho -- since it would seem weird to count the words in a new line as part of the previous paragraph's length."; System.out.println(justify(text, 15)); 

输出:

 Long sentence with spaces, and punctuation too. And supercalifragilisticexpialidocious words. No carriage returns, tho -- since it would seem weird to count the words in a new line as part of the previous paragraph's length. 

它考虑了长于设定限制的单词,因此它不会跳过它们(不像正则表达式,它只是在找到supercalifragilisticexpialidosus时停止处理)。

PS:在我提出这个解决方案之后,关于所有输入词的评论预计会短于设定的限制;)