-1

I am trying to make my own justify()-method that takes a string and an integer as input, and fils in spacing so that the string has the same length as the given integer. I have followed the answers to this question to do it.

I want my code to work somethinglike this:

Input = "hi hi hi" 20
Output = hi       hi       hi

My code looks like this:

//Add spaces to string until it is of desired length
static String justify(StringBuilder text, int width) {

    String[] inputLS = text.toString().split(" ");                //Split string into list of words

    //Sum the length of the words
    int sumOfWordLengths = 0;
    for (String word : inputLS){ sumOfWordLengths += word.length(); }

    int padding = width-sumOfWordLengths;                         //How much spacing we need
    String lastWord = inputLS[inputLS.length - 1];                //Last word in list of strings

    //Remove the last word
    ArrayList<String> withoutLast = new ArrayList<>
                                (Arrays.asList(inputLS).subList(0, inputLS.length - 1));

    StringBuilder result = new StringBuilder();                   //Initialize StringBuilder

    //Iterate over strings and add spacing (we do not add spacing to the last word)
    while (padding > 0){
        for(String word : withoutLast){
            result.append(word).append(" ");
            padding--;
        }
    }
    result.append(lastWord);                                      //Add the last word again
    return result.toString();
}


public static void main(String[] args) {
        // IO
        Scanner scanner = new Scanner(System.in);                       //Initialize scanner
        System.out.println("Please enter a string and an integer: ");   //Ask for input from user

        String line = scanner.nextLine();          //Get input-string from user
        String[] strings = line.split(" ");        //Split string at " " into list of strings
        String text = strings[0];                  //Get first element from list as string
        int width = Integer.parseInt(strings[1]);  //Get second element from list as an int

        // Create a string with three times the input text with spaces between
        StringBuilder forJustify = new StringBuilder();
        for(int i=0; i<3; i++){ forJustify.append(text).append(" "); }

        // Make sure the length of the string is less than the given int
        if (text == null || text.length() > width) {
            System.out.println(text);
            throw new IllegalArgumentException("Whoops! Invalid input. Try again.");
        }

        System.out.println("Gave this as input:\t" + forJustify);
        System.out.println("Justify:\t\t\t" + justify(forJustify, width));
    }

Which gives me this output:

Please enter a string and an integer: 
hi 20
Gave this as input: hi hi hi 
Justify:            hi hi hi hi hi hi hi hi hi hi hi hi hi hi hi

But I want this output:

Please enter a string and an integer: 
hi 20
Gave this as input: hi hi hi 
Justify:            hi       hi       hi

I know that there's something wring with the while-loop, but I don't understand how to fix it. All help is appreciated!

Mampenda
  • 661
  • 4
  • 21
  • Are we to assume you don't want to use `System.out.printf()`? – hfontanez Jan 25 '22 at 21:31
  • No I want to use it, I just don't know how to. – Mampenda Jan 25 '22 at 21:35
  • 1
    My answer should solve your problem. I will appreciate your upvote and the selection of the answer if I fully satisfied your problem. If you give me a few minutes, I can write `justify()` as a function. – hfontanez Jan 25 '22 at 21:46
  • The value 20 is supposed to be the full length of the string, and if I have understood printf correclty, it adds 20 spaces to every "hi". I know the formula to use to calculate the correct amount of padding, so I can fix this in post. If you would be so kind as to write a justify()-method I would really appreciate it. Thank you so much! – Mampenda Jan 25 '22 at 21:52
  • 1
    I assumed that the `int` value was the spacing. Anyway, you can modify my solution according to your needs. As an added bonus, I added logic to either right or left justify your string. – hfontanez Jan 25 '22 at 21:57
  • You will want to calculate the correct padding outside the justify method. Following SOLID principles, it is not the job of the `justify()` function to calculate the padding. You need to create a separate function to do this. Call it `calculatePadding(int strLength)`. – hfontanez Jan 25 '22 at 22:07
  • I don't know if you are familiarized with this type of parameter `String...words`. with the `...`, I can pass an array of strings like in the example OR an unbounded comma-separated list of `String` parameters. For example: `justify (padding, true, "Hello", "World", "Java", "is", "fun");` – hfontanez Jan 25 '22 at 22:26

2 Answers2

2

This solution is super simple using printf()

String test = "hi hi hi";
String[] tokens = test.split(" ");
int spacing = 20;
for (String token : tokens) {
    System.out.printf("%" + spacing + "s", token);          
}
System.out.println();

The output (right-justified):

                  hi                  hi                  hi

For left-justify solution, just add - after the percent sign

for (String token : tokens) {
    System.out.printf("%-" + spacing + "s", token);         
}
System.out.println();

outputs:

hi                  hi                  hi                  

UPDATE: Extracting justification as a function:

public static void justify(int spacing, boolean leftJustified, String...words) {
    for (String word : words) {
        System.out.printf("%" + (leftJustified ? "-" : "") + spacing + "s", word);                      
    }
    System.out.println();
}

To use,

public static void main(String[] args) {
    String test = "hi hi hi";
    String[] tokens = test.split(" ");
    int spacing = 20;
        
    justify(spacing, false, tokens); // right-justified
    justify(spacing, true, tokens); // left-justified
}
hfontanez
  • 5,774
  • 2
  • 25
  • 37
-2

I came up with this solution after using the answer above:

static String justify(StringBuilder text, int width) {

        //Turn StringBuilder into an arraylist of strings
        String[] words = text.toString().split(" ");
        List<String> arraylist = Arrays.asList(words);

        //Find the length of the words and length of the padding needed
        int lengthOfWords = 3 * arraylist.get(0).length();
        int pad = width - lengthOfWords;

        //Add padding by using format on each word separately and then combine the strings and add last word
        String result;
        if (pad % 2 == 0){
            String temp1 = String.format("%" + (-(pad / 2) - 2) + "s", words[0]);
            String temp2 = String.format("%" + (-(pad / 2) - 2) + "s", words[0]);
            result = temp1 + temp2 + words[0];
        } else {
            pad--;
            String temp1 = String.format("%" + (-(pad / 2) - 2) + "s", words[0]);
            String temp2 = String.format("%" + (-(pad / 2) - 2) + "s", words[0]);
            result = temp1 + temp2 + words[0];

            //Turn string into arraylist
            ArrayList<Character> cs = new ArrayList<>();
            for (char c : result.toCharArray()){ cs.add(c); }

            //Add last whitespace between first and second word
            int index = nextSpaceIndex(cs);
            cs.add(index, ' ');

            //Turn arraylist back to string
            StringBuilder str = new StringBuilder();
            for (Character c : cs) { str.append(c); }
            result = str.toString();
        }
        return result;
    }

Which gives me this output:

Please enter a string and an integer: 
hi 20
Justified:      |hi       hi       hi|
Mampenda
  • 661
  • 4
  • 21
  • 1
    If hfontanez answer led you to a solution, then you should probably accept his answer, not your derivative answer. – Hovercraft Full Of Eels Feb 11 '22 at 18:56
  • @HovercraftFullOfEels he actually deselected my answer to select his own which was derived from mine. Oh well... – hfontanez Feb 11 '22 at 19:00
  • 2
    @hfontanez: [this one](https://stackoverflow.com/a/59868244/522444) is even worse. This same OP did a direct copy of someone else's answer to their own question, and then they accepted their plagiarized copy, ignoring the original. I have flagged the moderators for that action since it is truly abusive and should not be tolerated on this site. – Hovercraft Full Of Eels Feb 11 '22 at 19:25
  • @HovercraftFullOfEels were you in the discussion I had on Meta Stack Overflow yesterday? Although I wasn't talking about this incident, this is not the first time it has happened to me. I am not necessarily here for reputation points, but if you work hard to help an OP to get an answer (as I did here), the least the OP can do is the right thing, which was precisely the message I was trying to convey in that discussion. I appreciate the endorsement and raising this issue up with moderators on my behalf! – hfontanez Feb 11 '22 at 19:28