简体   繁体   中英

Reverse String Word by Word in Java

I have the following code to reverse a string word by word, I have a question though, first could anyone point at how to make it better code? and second, how can I remove the space that I end up with at the beginning of the new string.

String str = "hello brave new world";
tStr.reverseWordByWord(str)

public String reverseWordByWord(String str){
        int strLeng = str.length()-1;
        String reverse = "", temp = "";

        for(int i = 0; i <= strLeng; i++){
            temp += str.charAt(i);
            if((str.charAt(i) == ' ') || (i == strLeng)){
                for(int j = temp.length()-1; j >= 0; j--){
                    reverse += temp.charAt(j);
                    if((j == 0) && (i != strLeng))
                        reverse += " ";
                }
                temp = "";
            }
        }

        return reverse;
    }

the phrase at the moment becomes:

olleh evarb wen dlrow

notice the space at the beginning of the new string.

Not using the split function the code would look like:

public static void reverseSentance(String str) {
    StringBuilder revStr = new StringBuilder("");
    int end = str.length(); // substring takes the end index -1
    int counter = str.length()-1;
    for (int i = str.length()-1; i >= 0; i--) {     
        if (str.charAt(i) == ' ' || i == 0) {
            if (i != 0) {
                revStr.append(str.substring(i+1, end));
                revStr.append(" ");
            }
            else {
                revStr.append(str.substring(i,end));
            }
            end = counter;
        }
        counter--;
    }
    System.out.println(revStr);
}

If str = "The quick brown fox jumped over the lazy dog!" it will return it like "dog! lazy the over jumped fox brown quick The" ...

  private static String Reverse(String str) {
      char charArray[] = str.toCharArray();
    for (int i = 0; i <str.length(); i++){
        if(charArray[i] == ' ')
        return Reverse(str.substring(i + 1)) + str.substring(0, i) + " ";
    }

    return str + " ";
}

Here's how you could do it:

    StringBuilder result = new StringBuilder();
    StringTokenizer st = new StringTokenizer(input, " ");
    while (st.hasMoreTokens()) {
        StringBuilder thisToken = new StringBuilder(st.nextToken());
        result.append(thisToken.reverse() + " ");
    }
    String resultString = result.toString();

My approach using StringUtils. In a unit test.

@Test
public void testReversesWordsAndThenAllCharacters(){
    String sentence = "hello brave new world";
    String reversedWords = StringUtils.reverseDelimited(sentence, ' ');
    String reversedCharacters = StringUtils.reverse(reversedWords);
    assertEquals("olleh evarb wen dlrow", reversedCharacters);
}

If you static import StringUtils, this could be inlined to:

reverse(reverseDelimited("hello brave new world", ' '))
public class StringReversers {

    public static void main(String[] args) {
        String s = new String(revStr("hello brave new world"));
        String st = new String(revWords("hello brave new world"));
        System.out.println(s);
        System.out.println(st);
    }

    public static String revStr(String s){
        StringBuilder sb = new StringBuilder();
        for (int i=s.length()-1; i>=0;i--){
            sb.append(s.charAt(i));
        }
        return sb.toString();
    }

    public static String revWords(String str) {
        StringBuilder sb = new StringBuilder();
        String revd = revStr(str);
        for (String s : revd.split(" ")){
            sb.append(revStr(s));
            sb.append(" ");
        }
        return sb.toString();
    }

}
public static void reverseByWord(String s) {

        StringTokenizer token = new StringTokenizer(s);

        System.out.println(token.countTokens());
        Stack<String> stack = new Stack<String>();
        while (token.hasMoreElements()) {
            stack.push(token.nextElement().toString());
        }

        while (!stack.isEmpty()) {
            System.out.println(stack.pop());
        }
    }

Another solution without using split method

    public static String reverseWordsWithoutSplit(String str) {
    StringBuffer buffer = new StringBuffer();
    int length = str.length();
    while(length >0) {
        int wordstart = length -1;
        while(wordstart >0 && str.charAt(wordstart) != ' '){
            wordstart--;
        }
        buffer.append(str.substring(wordstart==0?wordstart:wordstart+1, length));
        if(wordstart>0)
            buffer.append(" ");
        length = wordstart;
    }
    return buffer.toString();
}

Another Solution. This solution is in-place.

Reverse words in a string (words are separated by one or more spaces), spaces can precede word(s) i.e space at begin of sentence, end etc... Solve it in-place.

public class ReverseWordsInString {

public static void main(String[] args) {
    // TODO Auto-generated method stub

    char[] sentence = "  Hi my name is person!".toCharArray();
    System.out.println(ReverseSentence(sentence));  

}
private static char[] ReverseSentence(char[] sentence)
{
    //Given: "Hi my name is person!"
    //produce: "iH ym eman si !nosrep"
    //the obvious naive solution: utilize stringtokenize to separate each word into its own array. reverse each word and insert space between each array print
    //better solution: drop stringtokenize and use a counter to count how many characters processed before space was hit. 
    //                 once space hit, then jump back swap characters between counter-1 and start position. O(1) Space

    if(sentence == null) return null;
    if(sentence.length == 1) return sentence;       

    int startPosition=0;
    int counter = 0;
    int sentenceLength = sentence.length-1;

    //Solution handles any amount of spaces before, between words etc...    

    while(counter <= sentenceLength)
    {
        if(sentence[counter] == ' ' && startPosition != -1 || sentenceLength == counter) //Have passed over a word so upon encountering a space or end of string reverse word
        {
            //swap from startPos to counter - 1
            //set start position to -1 and increment counter
            int begin = startPosition;

            int end;
            if(sentenceLength == counter)
            {
                end = counter;
            }
            else                
                end = counter -1;
            char tmp;

        //Reverse characters
            while(end >= begin){

                tmp = sentence[begin];
                sentence[begin] = sentence[end];
                sentence[end] = tmp;

                end--; begin++;

            }               

            startPosition = -1; //flag used to indicate we have no encountered a character of a string


        }

        else if(sentence[counter] !=' ' && startPosition == -1) //first time you encounter a letter in a word set the start position
        {
            startPosition = counter;
        }

        counter++;  
    }

    return sentence;        
}

}

Here's one thread also discussing this problem. I think one answer using split with regex is very clever.

https://codereview.stackexchange.com/questions/43838/reverse-a-string-word-by-word

public String reverseWordByWord(String s) {
  StringBuilder result = new StringBuilder();
  String[] words = sentence.split("\\s+");      
  for (int i = words.length - 1 ; 0 <= i; i--) {
    result.append(words[i]).append(' ');
  }
  return result.toString().trim();
}

The answer to your removal of the starting space character is easy, just

return reverse.trim();

String.trim() returns a copy of the string, with leading and trailing whitespace omitted (as copied from the Javadoc documentation).

For your overall problem, I made this sample up:

String job = "This is a job interview question!";
StringBuilder sb = new StringBuilder(job);
String[] words = job.split(" ");
int i = 0;
for (String word : words) {
    words[i] = (new StringBuilder(word)).reverse().toString();
    i++;
}

System.out.println("job = " + job);
System.out.print("rev = ");
for (String word: words) {
    sb.append(new StringBuilder(word).toString());
    sb.append(" ");
}

String rev = sb.toString().trim();
System.out.println(rev);

and the output is:

job = This is a job interview question!
rev = sihT si a boj weivretni !noitseuq

If you want to be more inclusive of any white space character, e.g., tab character, line break, form feed, then change the split() argument to split("\\s") as \s is the regex character class which embodies [ \t\r\n\f]. Notice how you must escape the backslash character in your Java string representation of a regular expression (which is what the split method expects).

how to reverse word in java

public class ReverseString {

public static void main(String[] args) {
    String reverse = "";
    String original = new String("hidaya");
     
      for ( int i = original.length() - 1 ; i >= 0 ; i-- )
         reverse = reverse + original.charAt(i);
 
      System.err.println("Orignal string is: "+original);
      System.out.println("Reverse string is: "+reverse);
    }
}

Here is a coding technique using the popular split() function, which is available in all major languages, the Java toCharArray(), good for full control of characters in a string form, and the Java StringBuilder class for performance sake (available in C# too).

I think the code is easier to understand when compared to the other posted answers

public static String reverseWordByWord(String sentence) {
    StringBuilder result = new StringBuilder();
    String[] words = sentence.split("\\s+");   // space(s) are the delimiters

    for (String word : words) {
        char[] charArray = word.toCharArray();
        int iEnd = word.length() - 1;

        StringBuilder temp = new StringBuilder();
        for (int i = iEnd; i >= 0; i--) {
            temp.append(charArray[ i]);
        }
        result.append(temp);
        result.append(" ");     // separate the words
    }
    return result.toString().trim();    // remove the trailing spaces
}

Reminder of the requirements posted by the author.
Sample input: "Hello World"
Output: "olleH dlroW"

First thing I would do is to separate code reversing the words form code reversing each word individually. This inner loop:

for(int j = temp.length()-1; j >= 0; j--)
{
    reverse += temp.charAt(j);
    if((j == 0) && (i != strLeng))
        reverse += " ";
}

Would be a function/method call.

Also, to make your code more performant, instead of concatenating strings with the + operator, I would use a string buffer class. Such as StringBuffer or StringBuilder.

First of all you should decouple it in three functions. The first breaking the big string in a list of strings using the space as delimiter, the second reversing one string without spaces, and the last concatenating strings.

When you do that it will be easier to locate what cause the space to appears. You can already see that in the current code but I am not going to tell you :D.

How about using something like this?

String string="yourWord";
String reverse = new StringBuffer(string).reverse().toString();

You could use StringUtils

return StringUtils.reverseDelimitedString(str, " ");

Try this. It takes into account punctuations and whitespace characters of any kind.

public String reverseWordByWord(String inputStr)
{
    BreakIterator wordIterator = BreakIterator.getWordInstance();
    wordIterator.setText(inputStr);
    int start = wordIterator.first();
    StringBuilder tempBuilder;
    StringBuilder outBuilder = new StringBuilder();
    for (int end = wordIterator.next(); end != BreakIterator.DONE; start = end, end = wordIterator.next())
    {
        tempBuilder = new StringBuilder(inputStr.substring(start, end));
        outBuilder.append(tempBuilder.reverse());
    }
    return outBuilder.toString();
}

Take a String and using Stack methods with StringTokenizer Object and with its methods we can cut the String into the piece of Words using delimeter. By the Stack Natural feature insert (push) all the words into the Satck and Remove (pop) all the words from Stack. then print of those all.

Here we can take the String s="hello brave new world"

import java.util.*;
 public class StringReverse {   
  public static void main(String[] argv) { 
      String s = "hello brave new world";      
      Stack<String> myStack = new Stack<String>();
      StringTokenizer st = new StringTokenizer(s); 
        while (st.hasMoreTokens())
           myStack.push((String) st.nextElement());      
           // Print the stack backwards     
           System.out.print('"' + s + '"' + " backwards by word is:\n\t\"");     
         while (!myStack.empty()) {        
           System.out.print(myStack.pop());       
           System.out.print(' ');     
        }     System.out.println('"');
    } 
} 

If you are using any package with your own then check the Output of above program.

   StringBuilder sb = " This  is cool";
    sb.reverse(); //sb now contains "looc si  sihT "
    System.out.println(sb);
    for(int i = 0; i < sb.length(); i++)
    {
        int index = sb.indexOf(" ", i);
       // System.out.println(index);
        if(index > 0)
        {
            sb.replace(i, index, new StringBuilder(sb.substring(i, index)).reverse().toString());
            i = index;
        }
        if(index < 0)

        {
            sb.replace(i, sb.length(), new StringBuilder(sb.substring(i, sb.length())).reverse().toString());
            break;
        }
    }
    System.out.println(sb);
   //output "cool is  This "
  // Create Scanner object
  Scanner s=new Scanner(System.in);

  // Take no.of strings that the user wants
  int n=s.nextInt();

  // Create a temp array
  String temps[]=new String[n];

  // Initialize the variable before the user input is stored in it
  String st="";

  // Create a words array
  String words[];

  // Skip first line, if not used user input will be skipped one time 
  s.nextLine();

  // Read the no.of strings that user wish to..
  for(int k=0;k<n;k++)
  {

  System.out.println("String #"+(k+1)+": ");

  // Read line
  st=s.nextLine();

 // Split words with a space, because words has spaces at start, end positions.
 words=st.split(" "); 

 // Initialize temps[k] to avoid null
 temps[k]="";

 // Reverse string now!
 for(int i=words.length-1;i>=0;i--)
 {

 // Put each word in user input string from end to start with a space
 temps[k]+=words[i]+" ";

 }
 }

    // Now print the words!
    for(int i=0;i<n;i++)
    {

    // Print the reversed strings, trim them to avoid space at last, see in the reverse logic loop, space is attached at last!
    System.out.println("String #"+(i+1)+": "+temps[i].trim());

    }

I think my code below is more efficient than any code available here:

public static void revWordsInStringCStyle(String str){
    char [] str_ch = str.toCharArray();
    System.out.println(str);
    char temp;
    int len = str_ch.length;
    int left = len-1;

    for(int right =0; right<len/2 ;right++){
        temp = str_ch[left];
        str_ch[left] = str_ch[right];
        str_ch[right] = temp;
        left--;
    }

    for(int i =0; i < len ; i++){
        System.out.print(str_ch[i]);

    }

}

Example: "hello world"

will become : "dlrow olleho"

How about this :

    public class Main {
    public static void main(String args[]){
        String input ="***NGuyen**Van******A*******";
        String temp = "";
        String result ="";
        for( int i = 0 ; i < input.length() ; i++)
        {
            if(input.charAt(i) != '*')
            {
                temp = temp + input.charAt(i);
            }
            else
            {
                if(!temp.equals(""))
                    result = temp + result;
                result =  input.charAt(i) + result ;
                temp ="";
            }
        }

        System.out.println(result);
    }
}
Output: *******A******Van**NGuyen***

I tried to do without split function. Instead using substring and for loop.

static String reverseSentenceWithoutSplit(String str){
    StringBuilder sb = new StringBuilder();
    char [] charArray = str.toCharArray();
    int endindex = charArray.length-1;
    // loop in reverse, char by char
    for(int i=charArray.length-1; i>=0; i--){
        char c = charArray[i];
        if(c==' '){
            sb.append(str.substring(i + 1, endindex+1)); // substring- start index inclusive, end index exclusive
            endindex=i-1;// move to first letter
            sb.append(c); // include the space
        }
        if(i==0){ //grab the last word
            sb.append(str.substring(i, endindex+1));
        }
    }
    if(sb.length()==0){ // handle case where string has no space
        return str;
    }
    return sb.toString();
}

Input: Behind you is a symbol of oppression Output: oppression of symbol a is you Behind

Input: ThisIsAllOneWord Output: ThisIsAllOneWord

public String reverseEach(String input)
{
    String[] test = input.split(" ");
    String output="";
    for(String t:test)
    {
        String p ="";
        for(int i=t.length()-1;i>=0;i--)
        {
            p=p+t.charAt(i);
        }
        output=output+p+" ";
    }
    return output;
}
/* this code uses while loop and the position of spaces come correctly which is 
  a problem if you use for loop */


import java.util.*;
class StrWordRev
{
public void rev(String s)
    {
        for(int i=s.length()-1;i>=0;i--)
        {
            System.out.print(s.charAt(i));
        }
        System.out.print(" ");
    }

public void main()
{
    Scanner sc=new Scanner(System.in);
    String s,s1="";
    System.out.println("Enter the string : ");
    s=sc.nextLine();
    int i=0;
    while(i<s.length())
    {
        s1="";
        while(i<s.length() && s.charAt(i)!=' ')
        {
            s1=s1+s.charAt(i);
            i++;
        }
        rev(s1);
        i=i+1;
    }
}

This should work for you:

import java.io.*;

class internal1 {
    public static void main(String s[] {
        DataInputStream dis = new DataInputStream(System.in);

        try {
            String a = "";
            String b = "";
            System.out.print("Enter the string::");
            a = dis.readLine();
            System.out.print(a.length());
            System.out.println(" ");
            for (int i = 0; i <= a.length() - 1; i++) {
                if (a.charAt(i) == ' ' || a.charAt(i) == '.') {
                    for (int j = b.length() - 1; j >= 0; j--) {
                        System.out.print(b.charAt(j));
                    }
                    b = "";
                    System.out.print(" ");
                }
                b = b + a.charAt(i);
            }
        }
        catch (Exception e) {
        }
    }
}

The following should do it in O(n) without any expensive array copying or re-structuring the character array length. Takes care of multiple preceding, in-between and trailing whitespaces.

public class ReverseString {

    public static void main(String[] args) {
        String string1 = "hello brave new world";
        String string2 = "hello brave new world ";
        String string3 = " hello brave new world";
        String string4 = " hello  brave          new world ";

        System.out.println(reverseStringWordByWord(string1));
        System.out.println(reverseStringWordByWord(string2));
        System.out.println(reverseStringWordByWord(string3));
        System.out.println(reverseStringWordByWord(string4));
    }

    private static String reverseStringWordByWord(String string) {
        StringBuilder sb = new StringBuilder();
        int length = string.length();
        for(int i=0;i<length;i++) {
            char c = string.charAt(i);
            if(c == ' ') {
                sb.append(c);
            } else {
                int j = i;
                while(j < length && string.charAt(j) != ' ') {
                    j++;
                }
                sb.append(reverseString(string.substring(i, j)));
                i = j-1;
            }
        }
        return sb.toString();
    }

    private static String reverseString(String string) {
        StringBuilder sb = new StringBuilder();
        for(int i=string.length()-1;i>=0; i--) {
            sb.append(string.charAt(i));
        }
        return sb.toString();
    }

}
public String reverseStringWordByWord(String input) {
        StringBuilder returnValue = new StringBuilder();
        int insertIndex = 0;
        for(int i = 0;i < input.length();i++ ) {
            if(input.charAt(i)!=' ') {
                returnValue.insert(insertIndex, currentChar);
            } else {
                insertIndex = i+1;
                returnValue.append(currentChar);
            }

        }

        return returnValue.toString();
    }

I'm fairly new to Java myself, and I expect I've been beaten to the punch but I thought I'd give it a go anyway. You could solve the extra whitespace problem by building up the string with the assumption that you will delete the unwanted extra space at the end. If performance is a consideration then you might want to rethink this!

Edit: Note that my solution (now) handles leading and trailing whitespace.

public class StringReversal {

public static void main(String[] args) {
    String str = "hello brave new world";
    System.out.println("\"" + reverseWordByWord(str) + "\"");
}

public static String reverseWordByWord(String str) {
    String reverse = "";
    boolean first = true;
    for (String s : str.split(" ")) {
        if (first) {
            first = false;
        } else {
            reverse += " ";
        }
        StringBuilder sb = new StringBuilder();
        for (int i = s.length() - 1; i >= 0; --i) {
            sb.append(s.charAt(i));
        }
        reverse += sb.toString();
    }
    while (reverse.length() < str.length()) {
        reverse += " ";
    }
    return reverse.substring(0, reverse.length());
}
}

So, I'm assuming that you're learning/practicing java and that there is a high risk of homework question... This means that you'll either love or hate this answer...

If you take a look at the String object source code you'll find something like this inside:

private final char value[]; //this stores the String's characters

The first step is to get that value[] with:

char[] myChars = str.toCharArray();

Note the function implementation (from openjdk-7), it returns a copy of the array and not the original one because String objects are immutable.

public char[] toCharArray() {
    char result[] = new char[count];
    getChars(0, count, result, 0); //Calls System.arraycopy(...)
    return result;
}

Now that we have myChars we can play around with it and get to the result in linear time O(n)!

public static String reverseWordByWord(String str) {
    char[] myChars = str.toCharArray();
    int stringLen = myChars.length;

    int left = 0, right = 0;
    for(int index = 0; index < stringLen; index++) {
        if(chars[index] == ' ') {
            //assign right
            reverse(chars, left, right);
            //update left
        }
    }
    //Don't forget to handle the boundary case (last word in the String)!
}

And here is the reverse function:

private static void reverse(char[] chars, int left, int right) {
    while(left < right) {
        //Would you know how to swap 2 chars without using a "char tmp" variable? ;)
        //Update left and right
    }
}

Now just for fun you might want to try to get to the following output instead and maybe you'll get this exact question from some interviewer that ran out of fantasy one day:

world new brave hello

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM