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


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

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

Аналогичный Вопрос:

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

16 95

16 ответов:

вот регулярное выражение однострочной версии:

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.

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

ссылки:

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

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

// more code

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

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

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

и это. Просто как!

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

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

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

положите его в петлю, и вы хорошо идти.

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

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

в случае, если вы хотите разделить строку поровну назад, т. е. справа налево, например, разделить 1010001111 to [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;
}

вот реализация одного лайнера с использованием потоков 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]

Я спросил @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] - [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
     */

}

но мне нравится решение @Jon Skeets в https://stackoverflow.com/a/3760193/1237974 тоже. Для ремонтопригодности в больших проектах, где не все одинаково опытны в регулярных выражениях, я бы, вероятно, использовал Jons решение.

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

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

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

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

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

Я использую следующее решение 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());
}