在Java中将字符串拆分为相等长度的子字符串

Emi*_*mil 114 java regex string split

如何"Thequickbrownfoxjumps"在Java 中将字符串拆分为相同大小的子字符串.例如."Thequickbrownfoxjumps"等于4的大小应该给出输出.

["Theq","uick","brow","nfox","jump","s"]
Run Code Online (Sandbox Code Playgroud)

类似问题:

在Scala中将字符串拆分为等长子串

Ala*_*ore 212

这是正则表达式的单行版本:

System.out.println(Arrays.toString(
    "Thequickbrownfoxjumps".split("(?<=\\G.{4})")
));
Run Code Online (Sandbox Code Playgroud)

\G是一个零宽度断言,匹配上一个匹配结束的位置.如果以前没有的比赛,它的输入的开始,同相匹配\A.封闭的lookbehind匹配从最后一个匹配结束开始的四个字符的位置.

两者都是lookbehind和\G高级正则表达式功能,并非所有口味都支持.此外,\G并没有在支持它的各种口味中实现一致.这个技巧(例如)可以在Java,Perl,.NET和JGSoft中使用,但不能在PHP(PCRE),Ruby 1.9+或TextMate(都是Oniguruma)中使用.JavaScript /y(粘性标记)不像它那样灵活\G,即使JS确实支持lookbehind也不能以这种方式使用.

我应该提一下,如果你有其他选择,我不一定会推荐这个解决方案.其他答案中的非正则表达式解决方案可能更长,但它们也是自我记录的; 这个与此恰恰相反.;)

此外,这在Android中不起作用,Android不支持\G在lookbehinds中使用.

  • 对于记录,使用`String.substring()`而不是正则表达式,同时需要一些额外的代码行,将在大约5倍的速度运行... (5认同)
  • 为了完整起见:在多行上拆分文本需要在正则表达式中使用前缀`(?s)`:`(?s)(?<= \\ G. {4})`. (5认同)
  • 在PHP 5.2.4中,代码如下:return preg_split('/(?<=\G.{'.$ len.'})/ u',$ str,-1,PREG_SPLIT_NO_EMPTY); (2认同)
  • 在Java中,这对于带有换行符的字符串不起作用.它只会检查第一个换行符,如果该换行符恰好在split-size之前,则不会拆分该字符串.还是我错过了什么? (2认同)
  • @JeffreyBlattman我怀疑你*在编译时*遇到了异常...... (2认同)

Jon*_*eet 127

好吧,通过蛮力这样做很容易:

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)

我认为使用正则表达式并不值得.

编辑:我不使用正则表达式的原因:

  • 这不使用正则表达式的任何实际模式匹配.这只是数数.
  • 怀疑上述内容会更有效率,尽管在大多数情况下无关紧要
  • 如果你需要在不同的地方使用变量大小,你可能需要重复或辅助函数来根据参数构建正则表达式 - ick.
  • 另一个答案中提供的正则表达式首先没有编译(无效转义),然后没有工作.我的代码第一次工作.这更像是对正则表达式与普通代码IMO的可用性的证明.

  • @Emil:实际上,你*没有*要求正则表达式.它在标签中,但问题中没有任何内容要求正则表达式.您将此方法放在一个位置,然后您可以在代码中的任何位置将字符串拆分为一个*非常易读*语句. (8认同)
  • @Emil:我并不打算那么粗鲁,只是异想天开.我的观点中最重要的一点是,虽然是的,我确信你可以想出一个正则表达式来做到这一点 - 我看到艾伦摩尔有一个他声称有效的 - 它是神秘的,因此后来的程序员很难理解和维护.子串解决方案可以直观且可读.见Jon Skeet的第4个子弹:我同意这一点100%. (4认同)
  • 埃米尔这不是正则表达式的用途.期. (3认同)
  • @Emil:如果你想要一个单行分割字符串,我会推荐Guava的`Splitter.fixedLength(4)`,如seanizer所建议的那样. (3认同)
  • @Jay:来吧你不必那么讽刺.我敢肯定可以用一行中的正则表达式完成.一个固定长度的子串也是一个模式.你对这个答案怎么说.http://stackoverflow.com/questions/3760152/split-string-of-equal-lengths-in-java/3761521#3761521. (2认同)
  • @JonSkeet我不会将此解决方案称为“暴力”,因为它不会比其他解决方案做任何更糟糕的事情。事实上,它直接计算子字符串边界,而正则表达式解决方案实际上会迭代字符,以在预期位置找到“匹配”。因此,如果任何已发布的解决方案是“暴力”,那么它就是正则表达式变体。 (2认同)

Sea*_*oyd 70

使用Google Guava非常容易:

for(final String token :
    Splitter
        .fixedLength(4)
        .split("Thequickbrownfoxjumps")){
    System.out.println(token);
}
Run Code Online (Sandbox Code Playgroud)

输出:

Theq
uick
brow
nfox
jump
s
Run Code Online (Sandbox Code Playgroud)

或者,如果您需要将结果作为数组,则可以使用以下代码:

String[] tokens =
    Iterables.toArray(
        Splitter
            .fixedLength(4)
            .split("Thequickbrownfoxjumps"),
        String.class
    );
Run Code Online (Sandbox Code Playgroud)

参考:

注意:拆分器结构如上所示,但由于拆分器是不可变的和可重用的,因此将它们存储在常量中是一种很好的做法:

private static final Splitter FOUR_LETTERS = Splitter.fixedLength(4);

// more code

for(final String token : FOUR_LETTERS.split("Thequickbrownfoxjumps")){
    System.out.println(token);
}
Run Code Online (Sandbox Code Playgroud)

  • 包括Guava在内的@JeffreyBlattman可能就算是矫kill过正,这是真的。但是无论如何,我还是将它用作所有Java代码中的通用库,所以为什么不使用这一附加功能 (2认同)
  • @AquariusPower `String.join(separator, arrayOrCollection)` (2认同)

Cow*_*wan 13

如果你正在使用谷歌的guava通用库(而且老实说,任何新的Java项目可能都应该这样),这对于Splitter类来说是非常微不足道的:

for (String substring : Splitter.fixedLength(4).split(inputString)) {
    doSomethingWith(substring);
}
Run Code Online (Sandbox Code Playgroud)

就是这样.很容易!


Sau*_*aul 8

public 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;
}
Run Code Online (Sandbox Code Playgroud)


Gro*_*uez 6

public 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 出于兴趣,你有什么反对`for`循环? (6认同)

Mar*_*sic 5

这是一个单行版本,它使用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);
Run Code Online (Sandbox Code Playgroud)