5

I want to split a string Like 'Rupees Two Hundred Forty One and Sixty Eight only' when its length is at 35, I want to split this string in 2. I tried this code to split the string.

String text = "Rupees Two Hundred Forty One and Sixty Eight only";
List<String> parts = new ArrayList<>();
int length = text.length();
for (int i = 0; i < length; i += 35) {
    parts.add(text.substring(i, Math.min(length, i + size)));

but the output is like this.

[Rupees Two Hundred Forty One and Si, xty Eight only]

But I want to split the string like this.

[Rupees Two Hundred Forty One and, Sixty Eight only]

There is no cut word when splitting the string. The string varies every time according to the bill amount.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • 1
    Possible duplicate of [Split string to equal length substrings in Java](https://stackoverflow.com/questions/3760152/split-string-to-equal-length-substrings-in-java) – Hadi J Sep 20 '19 at 11:51
  • According to your expected output that you posted, the first string - _Rupees Two Hundred Forty One and_ - is only 32 characters long. – Abra Sep 20 '19 at 11:56
  • @HadiJ . i want cut the string at specific length also the words will not cut, i don't want to cut the string at equal parts – Abdul Rashid A Sep 20 '19 at 11:59
  • @AbdulRashidA do u want to cut at `and` everytime? – Mustahsan Sep 20 '19 at 12:16
  • 4
    The actual goal seems to be clear: Given some text, the text should be broken into separate lines, so that no line is longer than 35 characters. But what should happen when a certain word does not fit into the given boundaries, i.e. if it has more than 35 characters? Should the text always be split at `' '` space characters, or at any whitespace - or even at other characters, like `'-'`? If so, these should probably appear in the output... Many degrees of freedom and caveats here... – Marco13 Sep 20 '19 at 14:07
  • Note the 'no longer than 35 chars'. – MC Emperor Sep 20 '19 at 16:48
  • @Mustahsan, No, the amount will be vary each and every time, So the string length is vary according to the amount. – Abdul Rashid A Sep 21 '19 at 04:43
  • @MCEmperor I can't find the _no longer than 35 chars_ that you mention in your comment. Is it in the text of the question? – Abra Sep 21 '19 at 18:00
  • @Abra Nope, it's an emphasis of what Marco13 said. Just because the question is pretty vague about it. It seems logical that one needs to set a maximum to the line length, instead of setting a minimum. OP's example seems to respect this maximum. – MC Emperor Sep 21 '19 at 18:17

6 Answers6

2

You may not be able to do it exactly. But use String.indexOf() to find the first space starting at 35. Then use the substring method to divide the string.

      String text = "Rupees Two Hundred Forty One and Sixty Eight only";
      int i = text.indexOf(" ", 35);
      if (i < 0) {
         i = text.length();
      }
      String part1 = text.substring(0,i).trim();
      String part2 = text.substring(i).trim();

Here is an alternative method. It has not been fully checked for border cases.

      String[] words = text.split(" ");
      int k;
      part1 = words[0];
      for (k = 1; k < words.length; k++) {
         if (part1.length() >= 35 - words[k].length()) {
            break;
         }
         part1 += " " + words[k];
      }
      if (k < words.length) {
         part2 = words[k++];
         while (k < words.length) {
            part2 += " " + words[k++];
         }
      }
      System.out.println(part1);
      System.out.println(part2);

WJS
  • 36,363
  • 4
  • 24
  • 39
1

Just search for a preferred position at the i+35 position. One thing to consider, is what should happen when there is no such position, i.e. a word exceeds the specified size. The following code will enforce the size limit, breaking in the middle of the word if no good position could be found:

List<String> parts = new ArrayList<>();
int size = 35, length = text.length();
for(int i = 0, end, goodPos; i < length; i = end) {
    end = Math.min(length, i + size);
    goodPos = text.lastIndexOf(' ', end);
    if(goodPos <= i) goodPos = end; else end = goodPos + 1;
    parts.add(text.substring(i, goodPos));
}

If the break happened at a space character, the space will be removed from the result strings.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • How about declaring size and length inside the for loop header itself, which minimizes their scope: `for (int i = 0, size = 5, length = text.length(), end, goodPos; i < length; i = end)` – Ravindra Ranwala Sep 21 '19 at 07:00
  • 1
    @RavindraRanwala I kept the form as close to the OP’s code as possible. You can move the variable into the loop, however for `size` I’d not do it, as it is like a parameter, not to be confused with the other temporary variables. There’s also the option to declare it `final`, which wouldn’t work when moving it into the loop. – Holger Sep 23 '19 at 08:04
  • @Holger declaring `size` outside of loop has effect on performance? – Hadi J Sep 23 '19 at 11:44
  • 1
    @HadiJ no, not even the slightest. Unless we’re talking about the programmer’s performance, as placing it outside allows them easily seeing that this is a value that can be adapted to other use cases. – Holger Sep 23 '19 at 12:08
  • @Holger, Thanks Sir, couple of days ago I read a article(I can't find it now!) that said declaring `size` inside loop decrease performance, since in every step of loop it computes the size. i doubt it. – Hadi J Sep 23 '19 at 12:21
  • 1
    @HadiJ when placing it into the initializer of the `for` loop, like suggested by Ravindra Ranwala, it’s also only evaluated once. When putting it directly into the condition, it implies evaluating it again for each iteration, but even then the impact is low, unless we’re talking about a programming language like C with zero terminated strings, where getting the size requires iterating over the string. In Java, `length()` of `String` implies just reading a final field and that will be inlined when happening repeatedly in a loop. (And even for C’s strings, the optimizer might take care of it). – Holger Sep 23 '19 at 12:37
  • @Holger, Thanks for complete explanation. – Hadi J Sep 23 '19 at 14:17
0

you can find index of "and" and substring the string from 0 to index of "and".

 int i = text.indexOf("and") + 3;
 String part1 = text.substring(0,i);
 String part2 = text.substring(i).trim();
Parmar Kamlesh
  • 151
  • 1
  • 15
0

I would start building the String from the scratch using StringBuilders. An example with some comments inside:

    String text = "Rupees Two Hundred Forty One and Sixty Eight only For seven thousand chickens";
    String split[] = text.split(" "); // Split by space
    // One SB for each sentence
    StringBuilder sentence = new StringBuilder();
    // One SB for the total String
    StringBuilder total = new StringBuilder();
    for (int i = 0; i < split.length; i++) {
        String word = split[i];
        // Check if that words fits to sentence
        if (sentence.length() + word.length() <= 35) {
            sentence.append(word);
            sentence.append(" ");
        } else {
            total.append(sentence.toString().trim());
            total.append(", ");
            // Flush sentence to total and start next sentence
            sentence = new StringBuilder();
            sentence.append(word);
            sentence.append(" ");
        }
    }
    //Add any leftover
    if (sentence.length() > 0)
        total.append(sentence.toString().trim());
    System.out.println(total.toString());

Which outputs to:

Rupees Two Hundred Forty One and, Sixty Eight only For seven thousand, chickens

George Z.
  • 6,643
  • 4
  • 27
  • 47
0

I think you can use while loop to count words holding last faced space character:

public static List<String> split(String str, int length) {
    List<String> res = new ArrayList<>();
    int prvSpace = 0;
    int from = 0;

    while (prvSpace < str.length()) {
        int pos = str.indexOf(' ', prvSpace + 1);

        if (pos == -1) {
            res.add(str.substring(from));
            prvSpace = str.length();
        } else if (pos - from < length)
            prvSpace = pos;
        else {
            res.add(str.substring(from, prvSpace));
            from = prvSpace + 1;
        }
    }

    return res;
}

Demo:

in: "RupeesTwoHundredFortyOneandSixtyEightonly"
out: ["RupeesTwoHundredFortyOneandSixtyEightonly"]

in: "Rupees Two Hundred Forty One and Sixty Eight only"
out: ["Rupees Two Hundred Forty One and", "Sixty Eight only"]
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
0

I found an alternative using Apache commons-lang3:

import java.util.Arrays;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;

class Example {

    public static void main(String[] args) {
        String text = "Rupees Two Hundred Forty One and Sixty Eight only";
        String wrappedText = WordUtils.wrap(text, 35, "\n", false);
        String[] lines = StringUtils.split(wrappedText, "\n");
        System.out.println(Arrays.asList(lines));
        // Outputs [Rupees Two Hundred Forty One and, Sixty Eight only]
    }
}

NB. If your input has line feeds, best remove them.

Steven
  • 129
  • 4