Java: как разделить строку с разделителем, ограничив количество символов в строке?

У меня есть сценарий, в котором мне нужно разделить строку (со значениями, разделенными запятыми), ограничивая максимальное количество символов в строке при сохранении формата, разделенного запятыми.

Например, String str = "test,et,ste,ts,tst,est,ste,tstete,sts,tet,estst,tet"

Скажем, максимальное количество символов в строке может быть 10. Тогда мой вывод должен быть:

test,et (7 chars)
ste,ts,tst (10 chars)
est,ste (7 chars)
tstete,sts (10 chars)
tet,estst (9 chars)
tet (3 chars)

В основном вывод будет зациклен и добавлен к предложению IN в запросе, но предложение IN может обрабатывать только (максимальное количество символов), поэтому разбивая строку (со значением полных значений, разделенных запятыми) в случае, если длина строки превышает лимит.


person Devi    schedule 26.04.2019    source источник
comment
Я бы просто разделил запятыми, а затем соединил строки таким образом, чтобы они не превышали ваши ограничения по размеру. В качестве дополнительного преимущества, если вы действительно ищете вызов, вы можете изменить порядок строк, чтобы они были оптимальными (т.е. могут быть не последовательные строки в исходном вводе).   -  person mprivat    schedule 27.04.2019
comment
Это домашнее задание?   -  person luksch    schedule 27.04.2019
comment
@luksch нет, это не домашнее задание   -  person Devi    schedule 27.04.2019
comment
@mprivat Я понимаю вашу первую часть ответа, но не вторую часть. это не обязательно должно быть последовательным, но есть ли у вас пример кода для воссоединения строки [] путем ограничения размера символов?   -  person Devi    schedule 27.04.2019


Ответы (3)


Вы можете сделать что-то вроде этого (посмотрите комментарии для объяснения):

public static void main(String[] args) {
    String str = "test,et,ste,ts,tst,est,ste,tstete,sts,tet,estst,tet";

    // Split it first
    String words[] = str.split(",");

    // Use a buffer
    StringBuffer sb = new StringBuffer("");

    List<String> result = new ArrayList<>();

    String delim = "";

    // Iterate through the words. 
    for(int i = 0; i< words.length; i++) {
        // You will add the comma so total length should be less 
        // than 10.
        if(sb.length() + words[i].length() < 10) {
            sb.append(delim);
            sb.append(words[i]);
            delim = ",";
        }
        else {
            delim = "";
            result.add(sb.toString());
            System.out.println(sb.toString());
            sb = new StringBuffer(words[i]);
            delim = ",";
        }
    }

    // Print to check the results
    for(String s: result) {
        System.out.println(s);
    }
}
person Pritam Banerjee    schedule 26.04.2019
comment
Это не дало мне точных результатов, которых я ожидал. Оба напечатанных значения имеют одинаковые значения. Есть ли способ сделать это без создания объектов и использования функций indexof и сделать это проще? - person Devi; 30.04.2019

эта задача непростая — ее решает следующее лямбда-выражение

comma = false; // class boolean variable
last = 0;      // class int variable

Stream.of( str.split( "," ) ).collect(
  Collector.of( () -> new StringBuilder(),
    (buf, s) -> {
      if( buf.length() - last + s.length() < 10 ) {
        buf.append( comma ? "," : "" ).append( s );
        comma = true;
      }
      else {
        int len = buf.length();
        buf.append( " (" ).append( len - last ).append( " chars)\n" );
        last = buf.length();
        buf.append( s );
      }
    },
    (buf1, buf2) -> null,  // unused
    buf -> {
      int len = buf.length();
      return( buf.append( " (" ).append( len - last ).append( " chars)\n" ).toString() );
    } ) );

и без (… символов)-объяснения:

Stream.of( str.split( "," ) ).collect(
  Collector.of( () -> new StringBuilder(),
    (buf, s) -> {
      if( buf.length() - last + s.length() < 10 ) {
        buf.append( comma ? "," : "" ).append( s );
        comma = true;
      }
      else {
        buf.append( '\n' );
        last = buf.length();
        buf.append( s );
      }
    },
    (buf1, buf2) -> null,  // unused
    buf -> {
      return( buf.append( '\n' ).toString() );
    } ) );

требуемый результат возвращается в виде строки...

person Kaplan    schedule 10.07.2019

я бы сделал так:

  1. разделите входную строку запятой. Вы возвращаете массив с отдельными строками, например. arr[]
  2. инициализируйте временную строковую переменную для хранения выходных данных, например. out = ""
  3. цикл по массиву, например. for(int i = 0; i< arr.length; i++)
  4. внутри цикла: если длина out в сочетании с длиной текущей записи массива меньше 10, то добавьте текущую запись массива к out, иначе распечатайте out, сбросьте out и продолжайте, например. if (out.length + arr[i].length < 10) {out += ","+arr[i];} else {print out; out = "";}

Может быть, я что-то забыл... но вы должны уловить идею, верно?

person luksch    schedule 26.04.2019
comment
Есть ли способ сделать это без создания новых объектов и использования функций indexof и сделать это проще? - person Devi; 30.04.2019
comment
мое предлагаемое решение создает один вспомогательный объект, который является строкой. Он не использует indexOf, а использует только свойство длины строки, которое не требует больших вычислительных затрат. Конечно, вы могли бы вместо создания строки out (где другое решение по праву предлагает использовать StringBuffer) вы можете просто использовать переменную count. Добавьте длину каждой записи массива в переменную count и сравните ее с 10. Если больше, создайте строку. Но на самом деле это не намного элегантнее, я думаю. - person luksch; 30.04.2019