如何在Java中将字符串"Thequickbrownfoxjumps"
拆分为相等大小的子字符串。
例如,当子字符串大小为4时,则输出应为"Theq"
, "uick"
, "brow"
, "nfox"
, "jump"
和"s"
。
["Theq","uick","brow","nfox","jump","s"]
类似问题:
如何在Java中将字符串"Thequickbrownfoxjumps"
拆分为相等大小的子字符串。
例如,当子字符串大小为4时,则输出应为"Theq"
, "uick"
, "brow"
, "nfox"
, "jump"
和"s"
。
["Theq","uick","brow","nfox","jump","s"]
类似问题:
这是一个正则表达式的单行代码版本:
System.out.println(Arrays.toString(
"Thequickbrownfoxjumps".split("(?<=\\G.{4})")
));
\G
是一个零宽度断言,匹配上一次匹配结束的位置。如果之前没有匹配,它将会匹配输入的开头,与 \A
相同。包含的向后查找匹配距离上一次匹配结束位置四个字符的位置。
向后查找和 \G
都是高级正则表达式功能,不是所有版本都支持。此外,\G
在支持它的版本中实现不一致。这个技巧可以在 Java、Perl、.NET 和 JGSoft 中使用,但不能在 PHP(PCRE)、Ruby 1.9+ 或 TextMate(Oniguruma)中使用。JavaScript 的 /y
(粘性标志)不如 \G
灵活,并且即使 JS 支持向后查找,也无法以这种方式使用。
我应该提到,如果你有其他选择,我不一定推荐这个解决方案。其他答案中的非正则表达式解决方案可能更长,但它们也是自我说明的;这个解决方案恰恰相反。 ;)
此外,这在 Android 中不起作用,因为 Android 不支持在向后查找中使用 \G
。
String.substring()
而不是正则表达式,虽然需要多写几行代码,但运行速度会快大约5倍... - drew moore(?s)
:(?s)(?<=\\G.{4})
。 - bobbel使用简单的算术和字符串操作很容易做到这一点:
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;
}
注意:这种做法假设UTF-16代码单元(实际上就是char
)与“字符”一一对应。对于超出基本多语言平面的字符(如表情符号)和(根据计数方法)组合字符,该假设不成立。
我认为没有必要使用正则表达式。
编辑:我不使用正则表达式的原因:
Splitter.fixedLength(4)
,就像seanizer所建议的那样。 - ColinD使用Google Guava非常容易:
for(final String token :
Splitter
.fixedLength(4)
.split("Thequickbrownfoxjumps")){
System.out.println(token);
}
输出:
Theq
uick
brow
nfox
jump
s
如果你需要将结果作为数组返回,可以使用以下代码:
String[] tokens =
Iterables.toArray(
Splitter
.fixedLength(4)
.split("Thequickbrownfoxjumps"),
String.class
);
参考资料:
Splitter.fixedLength()
:按固定长度切分字符串。Splitter.split()
:根据指定的分隔符或匹配模式切分字符串。Iterables.toArray()
:将Iterable转换为数组。注意:上面的示例中直接展示了Splitter的构建方式,但由于Splitters是不可变的且可重用的,最好将它们存储在常量中以便复用。
private static final Splitter FOUR_LETTERS = Splitter.fixedLength(4);
// more code
for(final String token : FOUR_LETTERS.split("Thequickbrownfoxjumps")){
System.out.println(token);
}
String.join(separator, arrayOrCollection)
@AquariusPower String.join(separator, arrayOrCollection)
- Holgerq
替换为FACE WITH MEDICAL MASK:“Theuickbrownfoxjumps”,得到结果:The? ?uic kbro ... - Basil Bourqueq
替换为FACE WITH MEDICAL MASK:“Theuickbrownfoxjumps”,得到结果:The? ?uic kbro ... - Basil Bourquepublic static String[] split(String src, int len) {
String[] result = new String[(int)Math.ceil((double)src.length()/(double)len)];
for (int i=0; i<result.length; i++)
result[i] = src.substring(i*len, Math.min(src.length(), (i+1)*len));
return result;
}
src.length()
和 len
都是 int
类型,所以您的调用 ceiling
并没有实现您想要的效果 - 请查看其他回答中的一些方法:(src.length() + len - 1) / len - Michael Brewer-Davispublic String[] splitInParts(String s, int partLength)
{
int len = s.length();
// Number of parts
int nparts = (len + partLength - 1) / partLength;
String parts[] = new String[nparts];
// Break into parts
int offset= 0;
int i = 0;
while (i < nparts)
{
parts[i] = s.substring(offset, Math.min(offset + partLength, len));
offset += partLength;
i++;
}
return parts;
}
for
循环确实是更自然的选择来使用它:-)感谢您指出这一点。 - Grodriguez这是一个一行代码的版本,使用 Java 8 的 IntStream 来确定切片开始的索引:
String x = "Thequickbrownfoxjumps";
String[] result = IntStream
.iterate(0, i -> i + 4)
.limit((int) Math.ceil(x.length() / 4.0))
.mapToObj(i ->
x.substring(i, Math.min(i + 4, x.length())
)
.toArray(String[]::new);
我更喜欢这个简单的解决方案:
String content = "Thequickbrownfoxjumps";
while(content.length() > 4) {
System.out.println(content.substring(0, 4));
content = content.substring(4);
}
System.out.println(content);
substring
的实现方式,当时从String
类中删除了offset
和count
字段。因此,在此答案发布之前,substring
的复杂度已经变为线性。但对于像示例这样的小字符串,它仍然运行得足够快,而对于更长的字符串...嗯,这种任务在实践中很少发生。 - Holger一个 StringBuilder
版本:
public static List<String> getChunks(String s, int chunkSize)
{
List<String> chunks = new ArrayList<>();
StringBuilder sb = new StringBuilder(s);
while(!(sb.length() ==0))
{
chunks.add(sb.substring(0, chunkSize));
sb.delete(0, chunkSize);
}
return chunks;
}
public static List<String> splitString(final String string, final int chunkSize) {
final int numberOfChunks = (string.length() + chunkSize - 1) / chunkSize;
return IntStream.range(0, numberOfChunks)
.mapToObj(index -> string.substring(index * chunkSize, Math.min((index + 1) * chunkSize, string.length())))
.collect(toList());
}