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

Nav*_*Nav 10 java string

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

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

"hello "
Run Code Online (Sandbox Code Playgroud)

"world"
Run Code Online (Sandbox Code Playgroud)

但我目前的实施回归

"hello w"
Run Code Online (Sandbox Code Playgroud)

"orld   "
Run Code Online (Sandbox Code Playgroud)

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

public static List<String> splitEqually(String text, int size) {
    // Give the list the right capacity to start with. You could use an array
    // instead if you wanted.
    List<String> ret = new ArrayList<String>((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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

Psh*_*emo 16

如果我正确理解你的问题,那么这段代码应该做你需要的(但它假定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));
Run Code Online (Sandbox Code Playgroud)

输出:

Hello
there, my
name is
not
importnant
right now.
I am just
simple
sentecne
used to
test few
things.
Run Code Online (Sandbox Code Playgroud)

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

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

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

    • 空间(\\s)

      或(写作|)

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

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

  • 将很快包含对此正则表达式的解释,现在测试它是否是您想要的,并让我知道它是否有效. (2认同)
  • 如果你想获得更好的性能,你可能希望避免调整ArrayList的大小(创建比当前存储当前元素和新元素大2倍的数组,这对于大数组来说可能是昂贵的过程).为了避免它,你可以初始化大小大于预期元素数量的列表,所以可能用"new ArrayList((int)(1.5*text.length())/ size)"来初始化它. (2认同)