Split string to equal length substrings in Java

2018-12-31 06:33发布

How to split the string "Thequickbrownfoxjumps" to substrings of equal size in Java. Eg. "Thequickbrownfoxjumps" of 4 equal size should give the output.

["Theq","uick","brow","nfox","jump","s"]

Similar Question:

Split string into equal-length substrings in Scala

16条回答
其实,你不懂
2楼-- · 2018-12-31 07:11

Here is my version based on RegEx and Java 8 streams. It's worth to mention that Matcher.results() method is available since Java 9.

Test included.

public static List<String> splitString(String input, int splitSize) {
    Matcher matcher = Pattern.compile("(?:(.{" + splitSize + "}))+?").matcher(input);
    return matcher.results().map(MatchResult::group).collect(Collectors.toList());
}

@Test
public void shouldSplitStringToEqualLengthParts() {
    String anyValidString = "Split me equally!";
    String[] expectedTokens2 = {"Sp", "li", "t ", "me", " e", "qu", "al", "ly"};
    String[] expectedTokens3 = {"Spl", "it ", "me ", "equ", "all"};

    Assert.assertArrayEquals(expectedTokens2, splitString(anyValidString, 2).toArray());
    Assert.assertArrayEquals(expectedTokens3, splitString(anyValidString, 3).toArray());
}
查看更多
泪湿衣
3楼-- · 2018-12-31 07:13

This is very easy with Google Guava:

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

Output:

Theq
uick
brow
nfox
jump
s

Or if you need the result as an array, you can use this code:

String[] tokens =
    Iterables.toArray(
        Splitter
            .fixedLength(4)
            .split("Thequickbrownfoxjumps"),
        String.class
    );

Reference:

Note: Splitter construction is shown inline above, but since Splitters are immutable and reusable, it's a good practice to store them in constants:

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

// more code

for(final String token : FOUR_LETTERS.split("Thequickbrownfoxjumps")){
    System.out.println(token);
}
查看更多
时光乱了年华
4楼-- · 2018-12-31 07:15
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;
}
查看更多
临风纵饮
5楼-- · 2018-12-31 07:15

Here is a one liner implementation using Java8 streams:

String input = "Thequickbrownfoxjumps";
final AtomicInteger atomicInteger = new AtomicInteger(0);
Collection<String> result = input.chars()
                                    .mapToObj(c -> String.valueOf((char)c) )
                                    .collect(Collectors.groupingBy(c -> atomicInteger.getAndIncrement() / 4
                                                                ,Collectors.joining()))
                                    .values();

It gives the following output:

[Theq, uick, brow, nfox, jump, s]
查看更多
皆成旧梦
6楼-- · 2018-12-31 07:17

I asked @Alan Moore in a comment to the accepted solution how strings with newlines could be handled. He suggested using DOTALL.

Using his suggestion I created a small sample of how that works:

public void regexDotAllExample() throws UnsupportedEncodingException {
    final String input = "The\nquick\nbrown\r\nfox\rjumps";
    final String regex = "(?<=\\G.{4})";

    Pattern splitByLengthPattern;
    String[] split;

    splitByLengthPattern = Pattern.compile(regex);
    split = splitByLengthPattern.split(input);
    System.out.println("---- Without DOTALL ----");
    for (int i = 0; i < split.length; i++) {
        byte[] s = split[i].getBytes("utf-8");
        System.out.println("[Idx: "+i+", length: "+s.length+"] - " + s);
    }
    /* Output is a single entry longer than the desired split size:
    ---- Without DOTALL ----
    [Idx: 0, length: 26] - [B@17cdc4a5
     */


    //DOTALL suggested in Alan Moores comment on SO: https://stackoverflow.com/a/3761521/1237974
    splitByLengthPattern = Pattern.compile(regex, Pattern.DOTALL);
    split = splitByLengthPattern.split(input);
    System.out.println("---- With DOTALL ----");
    for (int i = 0; i < split.length; i++) {
        byte[] s = split[i].getBytes("utf-8");
        System.out.println("[Idx: "+i+", length: "+s.length+"] - " + s);
    }
    /* Output is as desired 7 entries with each entry having a max length of 4:
    ---- With DOTALL ----
    [Idx: 0, length: 4] - [B@77b22abc
    [Idx: 1, length: 4] - [B@5213da08
    [Idx: 2, length: 4] - [B@154f6d51
    [Idx: 3, length: 4] - [B@1191ebc5
    [Idx: 4, length: 4] - [B@30ddb86
    [Idx: 5, length: 4] - [B@2c73bfb
    [Idx: 6, length: 2] - [B@6632dd29
     */

}

But I like @Jon Skeets solution in https://stackoverflow.com/a/3760193/1237974 also. For maintainability in larger projects where not everyone are equally experienced in Regular expressions I would probably use Jons solution.

查看更多
不再属于我。
7楼-- · 2018-12-31 07:20

I'd rather this simple solution:

String content = "Thequickbrownfoxjumps";
while(content.length() > 4) {
    System.out.println(content.substring(0, 4));
    content = content.substring(4);
}
System.out.println(content);
查看更多
登录 后发表回答