it-swarm.com.de

String in gleich lange Teilstrings in Java aufteilen

So teilen Sie die Zeichenfolge "Thequickbrownfoxjumps" in gleich große Zeichenfolgen in Java auf . "Thequickbrownfoxjumps" von 4 gleichen Größen sollte die Ausgabe ergeben.

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

Ähnliche Frage:

Zeichenfolge in Scala in gleich lange Teilstrings aufteilen

100
Emil

Hier ist die Regex One-Liner-Version:

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

\G ist eine Zusicherung der Breite Null, die mit der Position übereinstimmt, an der die vorherige Übereinstimmung beendet wurde. Wenn es war keine vorherige Übereinstimmung gibt, entspricht dies dem Beginn der Eingabe, genau wie \A. Der umschließende Lookbehind entspricht der Position, die vier Zeichen vom Ende des letzten Matches entfernt ist.

Sowohl lookbehind als auch \G sind erweiterte Regex-Funktionen, die nicht von allen Geschmacksrichtungen unterstützt werden. Darüber hinaus wird \G nicht in allen unterstützten Varianten konsistent implementiert. Dieser Trick funktioniert (zum Beispiel) in Java , Perl, .NET und JGSoft, aber nicht in PHP (PCRE), Ruby 1.9 + oder TextMate (beide Oniguruma). JavaScripts /y (Sticky Flag) ist nicht so flexibel wie \G und kann auf diese Weise nicht verwendet werden, selbst wenn JS Lookbehind unterstützt.

Ich sollte erwähnen, dass ich nicht unbedingt empfehle diese Lösung, wenn Sie andere Optionen haben. Die Nicht-Regex-Lösungen in den anderen Antworten sind möglicherweise länger, aber auch selbstdokumentierend. dies ist nur ungefähr das Gegenteil davon. ;)

Dies funktioniert auch nicht in Android, da die Verwendung von \G in Lookbehinds nicht unterstützt wird.

207
Alan Moore

Nun, es ist ziemlich einfach, dies mit roher Gewalt zu tun:

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;
}

Ich denke nicht, dass es sich wirklich lohnt, dafür einen Regex zu verwenden.

EDIT: Meine Gründe, warum ich keinen Regex benutzt habe:

  • Dies verwendet keinen echten Mustervergleich von Regex. Es zählt nur.
  • Ich verdächtige das obige wird effizienter sein, obwohl es in den meisten Fällen keine Rolle spielt
  • Wenn Sie variable Größen an verschiedenen Stellen verwenden müssen, haben Sie entweder Wiederholungen oder eine Hilfsfunktion, um den Regex auf der Grundlage eines Parameter-ick zu erstellen.
  • Die in einer anderen Antwort angegebene Regex wurde nicht kompiliert (ungültiges Escaping) und funktionierte dann nicht. Mein Code funktionierte beim ersten Mal. Das ist mehr ein Beweis für die Verwendbarkeit von Regexes gegenüber einfachem Code, IMO.
116
Jon Skeet

Dies ist sehr einfach mit Google Guava :

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

Ausgabe:

Theq
uick
brow
nfox
jump
s

Wenn Sie das Ergebnis als Array benötigen, können Sie diesen Code verwenden:

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

Referenz:

Hinweis: Die Splitterkonstruktion wird oben inline angezeigt. Da Splitter jedoch unveränderlich und wiederverwendbar sind, sollten Sie sie in Konstanten speichern:

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

// more code

for(final String token : FOUR_LETTERS.split("Thequickbrownfoxjumps")){
    System.out.println(token);
}
65

Wenn Sie Google guava Allzweckbibliotheken verwenden (und ganz ehrlich, jedes neue Java-Projekt sollte wahrscheinlich sein sein), ist dies mit der Splitter -Klasse irrsinnig trivial:

for (String substring : Splitter.fixedLength(4).split(inputString)) {
    doSomethingWith(substring);
}

und das ist it. Einfach wie!

12
Cowan
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;
}
7
Saul
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;
}
6
Grodriguez

Sie können substring aus String.class (Ausnahmebehandlung) oder aus Apache lang commons (es behandelt Ausnahmen für Sie)

static String   substring(String str, int start, int end) 

Legen Sie es in eine Schleife und Sie können loslegen.

4
pakore

Hier ist eine Einzeiler-Implementierung mit 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();

Es gibt folgende Ausgabe:

[Theq, uick, brow, nfox, jump, s]
3
Pankaj Singhal

Hier ist eine einzeilige Version, die Java 8 verwendet. IntStream um die Indizes der Slice-Anfänge zu bestimmen:

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);
2
Marko Previsic

Ich möchte lieber diese einfache Lösung:

String content = "Thequickbrownfoxjumps";
while(content.length() > 4) {
    System.out.println(content.substring(0, 4));
    content = content.substring(4);
}
System.out.println(content);
2
Cheetah Coder

Wenn Sie die Zeichenfolge gleichermaßen rückwärts teilen möchten, d. H. Von rechts nach links, um beispielsweise 1010001111 in [10, 1000, 1111] zu teilen, geben Sie hier den Code ein

/**
 * @param s         the string to be split
 * @param subLen    length of the equal-length substrings.
 * @param backwards true if the splitting is from right to left, false otherwise
 * @return an array of equal-length substrings
 * @throws ArithmeticException: / by zero when subLen == 0
 */
public static String[] split(String s, int subLen, boolean backwards) {
    assert s != null;
    int groups = s.length() % subLen == 0 ? s.length() / subLen : s.length() / subLen + 1;
    String[] strs = new String[groups];
    if (backwards) {
        for (int i = 0; i < groups; i++) {
            int beginIndex = s.length() - subLen * (i + 1);
            int endIndex = beginIndex + subLen;
            if (beginIndex < 0)
                beginIndex = 0;
            strs[groups - i - 1] = s.substring(beginIndex, endIndex);
        }
    } else {
        for (int i = 0; i < groups; i++) {
            int beginIndex = subLen * i;
            int endIndex = beginIndex + subLen;
            if (endIndex > s.length())
                endIndex = s.length();
            strs[i] = s.substring(beginIndex, endIndex);
        }
    }
    return strs;
}
2
Ivan Huang
public static String[] split(String input, int length) throws IllegalArgumentException {

    if(length == 0 || input == null)
        return new String[0];

    int lengthD = length * 2;

    int size = input.length();
    if(size == 0)
        return new String[0];

    int rep = (int) Math.ceil(size * 1d / length);

    ByteArrayInputStream stream = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_16LE));

    String[] out = new String[rep];
    byte[]  buf = new byte[lengthD];

    int d = 0;
    for (int i = 0; i < rep; i++) {

        try {
            d = stream.read(buf);
        } catch (IOException e) {
            e.printStackTrace();
        }

        if(d != lengthD)
        {
            out[i] = new String(buf,0,d, StandardCharsets.UTF_16LE);
            continue;
        }

        out[i] = new String(buf, StandardCharsets.UTF_16LE);
    }
    return out;
}
0
User8461

Hier ist meine Version basierend auf RegEx und Java 8-Streams. Es ist erwähnenswert, dass die Matcher.results()-Methode seit Java 9 verfügbar ist.

Test enthalten.

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());
}
0
itachi

Eine weitere Brute-Force-Lösung könnte sein, 

    String input = "thequickbrownfoxjumps";
    int n = input.length()/4;
    String[] num = new String[n];

    for(int i = 0, x=0, y=4; i<n; i++){
    num[i]  = input.substring(x,y);
    x += 4;
    y += 4;
    System.out.println(num[i]);
    }

Wo der Code nur mit Teilzeichenfolgen durch die Zeichenfolge geht

0
Hubbly

Java 8-Lösung (wie diese aber ein bisschen einfacher):

public static List<String> partition(String string, int partSize) {
  List<String> parts = IntStream.range(0, string.length() / partSize)
    .mapToObj(i -> string.substring(i * partSize, (i + 1) * partSize))
    .collect(toList());
  if ((string.length() % partSize) != 0)
    parts.add(string.substring(string.length() / partSize * partSize));
  return parts;
}
0

ich verwende die folgende Java 8-Lösung:

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());
}
0
rloeffel
@Test
public void regexSplit() {
    String source = "Thequickbrownfoxjumps";
    // define matcher, any char, min length 1, max length 4
    Matcher matcher = Pattern.compile(".{1,4}").matcher(source);
    List<String> result = new ArrayList<>();
    while (matcher.find()) {
        result.add(source.substring(matcher.start(), matcher.end()));
    }
    String[] expected = {"Theq", "uick", "brow", "nfox", "jump", "s"};
    assertArrayEquals(result.toArray(), expected);
}

Ich fragte @Alan Moore in einem Kommentar zur akzeptierten Lösung , wie Strings mit Zeilenumbrüchen behandelt werden könnten. Er schlug vor, DOTALL zu verwenden.

Mit seinem Vorschlag erstellte ich eine kleine Auswahl, wie das funktioniert:

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] - [[email protected]
     */


    //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] - [[email protected]
    [Idx: 1, length: 4] - [[email protected]
    [Idx: 2, length: 4] - [[email protected]
    [Idx: 3, length: 4] - [[email protected]
    [Idx: 4, length: 4] - [[email protected]
    [Idx: 5, length: 4] - [[email protected]
    [Idx: 6, length: 2] - [[email protected]
     */

}

Aber ich mag die @ Jon Skeets-Lösung in https://stackoverflow.com/a/3760193/1237974 . Für die Wartbarkeit in größeren Projekten, bei denen nicht jeder mit regulären Ausdrücken gleichermaßen vertraut ist, würde ich wahrscheinlich die Lösung von Jons verwenden.

0
joensson
    import static Java.lang.System.exit;
   import Java.util.Scanner;
   import Java.util.Arrays.*;


 public class string123 {

public static void main(String[] args) {


  Scanner sc=new Scanner(System.in);
    System.out.println("Enter String");
    String r=sc.nextLine();
    String[] s=new String[10];
    int len=r.length();
       System.out.println("Enter length Of Sub-string");
    int l=sc.nextInt();
    int last;
    int f=0;
    for(int i=0;;i++){
        last=(f+l);
            if((last)>=len) last=len;
        s[i]=r.substring(f,last);
     // System.out.println(s[i]);

      if (last==len)break;
       f=(f+l);
    } 
    System.out.print(Arrays.tostring(s));
    }}

Ergebnis

 Enter String
 Thequickbrownfoxjumps
 Enter length Of Sub-string
 4

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