如何在保持字边界的同时将字符串拆分为最大字符长度的相等部分?
比如说,如果我想将一个字符串“hello world”拆分成最多7个字符的相等子串,它应该返回给我
"hello "
和
"world"
但是我当前的实现返回
"hello w"
和
"orld "
我使用以下代码从Split string to equal length substrings in 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;
}
在将字符串拆分为子字符串时是否可以保持字边界?
更具体地说,我需要字符串拆分算法来考虑空格提供的单词边界,而不是仅仅在分割字符串时依赖字符长度,尽管这也需要考虑但更像是最大范围字符而不是硬编码的字符长度。
答案 0 :(得分: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));
输出:
Hello
there, my
name is
not
importnant
right now.
I am just
simple
sentecne
used to
test few
things.
"\\G\\s*(.{1,"+maxLenght+"})(?=\\s|$)"
正则表达式的简短(或不是)解释:
(让我们记住,在Java \
中不仅特殊于正则表达式,而且还在字符串文字中,所以要使用\d
之类的预定义字符集,我们需要将其写为"\\d"
因为我们需要在字符串文字中转义\
\G
- 是代表先前创建的匹配结束的锚点,或者如果还没有匹配(当我们刚刚开始搜索时)字符串的开头(与^
相同)\s*
- 表示零个或多个空格(\s
表示空格,*
“零或多个”量词)(.{1,"+maxLenght+"})
- 让我们将其拆分为更多部分(在运行时:maxLenght
将保留一些数值,如10,因此正则表达式会将其视为.{1,10}
)
.
表示任何字符(实际上默认情况下,它可能表示除\n
或\r
之类的行分隔符以外的任何字符,但是由于Pattern.DOTALL
标记,它现在可以代表任何字符character - 如果你想分别开始分割每个句子,你可以摆脱这个方法参数,因为无论如何它将以新行打印 ){1,10}
- 这是量词,它允许先前描述的元素出现1到10次(默认情况下会尝试找到匹配重复的最大值),.{1,10}
- 基于我们刚才所说的内容,它只代表“1到10个任何字符”(
)
- 括号创建groups,这些结构允许我们保留匹配的特定部分(此处我们在\\s*
之后添加了括号,因为我们只想使用部分在空白之后) (?=\\s|$)
- 是look-ahead机制,可确保.{1,10}
匹配的文字在其后面有:
空格(\\s
)
OR(写作|
)
后面的字符串$
的结尾。
感谢.{1,10}
,我们最多可以匹配10个字符。但是在(?=\\s|$)
之后我们要求与.{1,10}
匹配的最后一个字符不是未完成单词的一部分(在它之后必须有空格或字符串结尾)。
答案 1 :(得分:3)
非正则表达式解决方案,以防有人更舒服(?)不使用正则表达式:
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:在我提出这个解决方案之后,关于所有输入词的评论预计会短于设定的限制;)