Разделить строку на подстроки равной длины в Java

Как разбить строку "Thequickbrownfoxjumps" на подстроки равного размера в Java. Например. "Thequickbrownfoxjumps" из 4 равных размеров должен выдавать результат.

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

Похожие вопросы:

Разделить строку на подстроки равной длины в Scala

Ответ 1

Здесь одноязычная версия регулярного выражения:

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

\G - это утверждение с нулевой шириной, которое соответствует позиции, в которой закончилось предыдущее совпадение. Если предыдущее совпадение не было, оно соответствует началу ввода, так же, как \A. Прилагаемый lookbehind соответствует позиции, состоящей из четырех символов от конца последнего совпадения.

Оба lookbehind и \G являются расширенными функциями регулярного выражения, не поддерживаемыми всеми вкусами. Кроме того, \G не реализуется последовательно по вкусам, которые его поддерживают. Этот трюк будет работать (например) в Java, Perl,.NET и JGSoft, но не в PHP (PCRE), Ruby 1.9+ или TextMate (оба Oniguruma). JavaScript /y (липкий флаг) не такой гибкий, как \G, и не может использоваться таким образом, даже если JS поддерживает lookbehind.

Я должен упомянуть, что я не обязательно рекомендую это решение, если у вас есть другие варианты. Решения без регулярных выражений в других ответах могут быть более длинными, но они также самодокументированы; это одно прямо противоположное тому.;)

Кроме того, это не работает в Android, что не поддерживает использование \G в lookbehinds.

Ответ 2

Что ж, это довольно легко сделать с помощью простых арифметических и строковых операций:

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

Я не думаю, что для этого стоит использовать регулярные выражения.

ОБНОВЛЕНИЕ: Моя причина не использовать регулярное выражение:

  • Это не использует никакого реального сопоставления с образцом регулярных выражений. Это просто подсчет.
  • Я подозреваю, что вышеупомянутое будет более эффективным, хотя в большинстве случаев это не имеет значения
  • Если вам нужно использовать переменные размеры в разных местах, у вас либо есть повторение, либо вспомогательная функция для построения самого регулярного выражения на основе параметра - ick.
  • Регулярное выражение, приведенное в другом ответе, сначала не компилировалось (недопустимое экранирование), а затем не работало. Мой код работал с первого раза. Это еще одно свидетельство удобства использования регулярных выражений по сравнению с простым кодом, IMO.

Ответ 3

Это очень легко с 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
    );

Ссылка:

Примечание. Конструкция сплиттера показана в строке выше, но поскольку Splitters являются неизменяемыми и многоразовыми, рекомендуется хранить их в константах:

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

// more code

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

Ответ 4

Если вы используете Google guava универсальные библиотеки (и, честно говоря, любой новый Java-проект, вероятно, должен быть), это безумно тривиально с классом Splitter:

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

и что он. Легко, как!

Ответ 5

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

Ответ 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;
}

Ответ 7

Вы можете использовать substring из String.class (обработка исключений) или Apache lang commons (он обрабатывает исключения для вас)

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

Поместите его внутри цикла, и вы хорошо пойдете.

Ответ 8

Вот реализация одного liner с использованием потоков Java8:

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();

Он дает следующий результат:

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

Ответ 9

Я предпочел бы это простое решение:

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

Ответ 10

Если вы хотите разделить строку одинаково назад, то есть справа налево, например, чтобы разделить 1010001111 на [10, 1000, 1111], вот код:

/**
 * @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;
}

Ответ 11

Я использую следующее решение java 8:

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

Ответ 12

Вот однострочная версия, которая использует 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);

Ответ 13

Решение Java 8 (как это, но немного проще):

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

Ответ 14

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

Результат

 Enter String
 Thequickbrownfoxjumps
 Enter length Of Sub-string
 4

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

Ответ 15

Я спросил @Alan Moore в комментарии к принятому решению о том, как можно обрабатывать строки с новыми символами. Он предложил использовать DOTALL.

Используя его предложение, я создал небольшой пример того, как это работает:

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: /questions/68872/split-string-to-equal-length-substrings-in-java/467997#467997
    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]
     */

}

Но мне нравится @Jon Skeets решение в fooobar.com/questions/68872/.... Для удобства обслуживания в крупных проектах, где не все одинаково знакомы с регулярными выражениями, я бы, вероятно, использовал решение Jons.

Ответ 16

Другое решение для грубой силы может быть

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

Если код просто проходит через строку с подстроками

Ответ 17

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

Ответ 18

Вот моя версия, основанная на потоках RegEx и Java 8. Стоит отметить, что Matcher.results() доступен с Java 9.

Тест включен.

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

Ответ 19

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

Ответ 20

public static List<String> getSplittedString(String stringtoSplit,
            int length) {

        List<String> returnStringList = new ArrayList<String>(
                (stringtoSplit.length() + length - 1) / length);

        for (int start = 0; start < stringtoSplit.length(); start += length) {
            returnStringList.add(stringtoSplit.substring(start,
                    Math.min(stringtoSplit.length(), start + length)));
        }

        return returnStringList;
    }