Click here to Skip to main content
15,867,937 members
Please Sign up or sign in to vote.
4.00/5 (2 votes)
See more:
Input: 1 cup of hot coffee costs 8.00, whereas cold coffee costs 45.00.
Output: 1 puc fo toh eeffoc stsoc 8.00, saerehw dloc eeffoc stsoc 45.00.

I need a method which will return a string after reversing only the alphabets [a-zA-Z] in a sentence, which is passed as an argument to a method.

What I have tried:

C#
static void Main(string[] args)
        {
            string str= ReverseWord("1 cup of hot coffee costs 8.00, whereas cold coffee costs 45.00.");
            Console.WriteLine(str);
            Console.ReadLine();
        }    

 static string ReverseWord(string originalString)
        {
            string[] splitStrings = originalString.Split(' ');
            int test = 0;
           // string result1 = string.Join(".", splitStrings);
            bool result = int.TryParse(splitStrings, out test);

            StringBuilder reverseWordString = new StringBuilder();
            List<char> charlist = new List<char>();
            for (int i = 0; i < originalString.Length; i++)
            {
                if (originalString[i] == ' ' || i == originalString.Length - 1 || result)
                {
                    if (i == originalString.Length - 1)
                        charlist.Add(originalString[i]);
                    for (int j = charlist.Count - 1; j >= 0; j--)
                        reverseWordString.Append(charlist[j]);
                    reverseWordString.Append(' ');
                    charlist = new List<char>();
                }
                else
                {
                    charlist.Add(originalString[i]);
                }
            }
            return reverseWordString.ToString();
        }
Posted
Updated 21-Aug-20 7:47am
v2
Comments
Patrice T 20-Aug-20 4:58am    
What is the problem with this code ?
Afzaal Ahmad Zeeshan 20-Aug-20 5:18am    
Sounds like an interview/homework question.

Where are you stuck?
PIEBALDconsult 20-Aug-20 13:01pm    
Seek thee ye olde Regular Expressions. :D

You're working too hard. Simplify, simplify.
To achieve the goal, you don't actually care about whether or not the non-alphabetic parts are numeric.

C#
public static string
ReverseMatches
(
  string Input
,
  string Pattern
)
{
  System.Text.StringBuilder result = new System.Text.StringBuilder ( Input ) ;

  foreach
  (
    System.Text.RegularExpressions.Match m
  in
    System.Text.RegularExpressions.Regex.Matches ( Input , Pattern )
  )
  {
    for ( int i = 0 ; i < m.Length ; i++ )
    {
      result [ m.Index + i ] = m.Value [ m.Length - 1 - i ] ;
    }
  }

  return ( result.ToString() ) ;
}

string ouput = ReverseMatches ( "1 cup of hot coffee costs 8.00, whereas cold coffee costs 45.00." , "(?i)[A-Z]+" ) ;
 
Share this answer
 
Comments
BillWoodruff 21-Aug-20 0:28am    
+5 handles preservation of the numbers formatted properly.

However, look at the result of var rev = StrReverse("1 cup of hot coffee costs a8.00, whereas cold coffee costs 45.00.");
PIEBALDconsult 21-Aug-20 10:04am    
That wasn't included in the test set.
I assume mine does it correctly.
His also doesn't preserve whitespace (TABs, multiple SPACEs, etc.).
At any rate, a more complete spec would be welcome.
And you're welcome to tweak the Regular Expression as you see fit. :D
Maybe this is what the teacher/interviewer expected:

C#
public static string
ReverseAlpha
(
  string Input
)
{
  System.Text.StringBuilder result = new System.Text.StringBuilder ( Input.Length ) ;

  System.Collections.Generic.Stack<char> s = new System.Collections.Generic.Stack<char>() ;

  foreach ( char c in Input )
  {
    if ( System.Char.IsLetter ( c ) )
    {
      s.Push ( c ) ;
    }
    else
    {
      while ( s.Count > 0 )
      {
        result.Append ( s.Pop() ) ;
      }

      result.Append ( c ) ;
    }
  }

  while ( s.Count > 0 )
  {
    result.Append ( s.Pop() ) ;
  }

  return ( result.ToString() ) ;
}

string ouput = ReverseAlpha ( "1 cup of hot coffee costs 8.00, whereas cold coffee costs 45.00." ) ;
 
Share this answer
 
v3
Comments
BillWoodruff 21-Aug-20 13:58pm    
Glad to see you were (maybe) inspired by my parse char-by-char suggestion :) Have a 5 !
PIEBALDconsult 21-Aug-20 14:08pm    
:D Yeah, kinda.
Get rid of this

 string[] splitStrings = originalString.Split(' ');
 int test = 0;
// string result1 = string.Join(".", splitStrings);
 bool result = int.TryParse(splitStrings, out test);

You are testing if an array of strings can be parsed to an int, which it can't, that code won't even compile. Splitting on space then checking if it will parse to int word by word won't work anyway as when it gets to the 8.00 the "word" will be "8.00," which won't convert to int (or decimal\double etc).

If you read the question a little more carefully;

reversing only the alphabets [a-zA-Z]


then look at your if condition;

if (originalString[i] == ' ' || i == originalString.Length - 1 || result)


First off get rid of "result" as that's now gone (see opening comment), and checking for ' ' doesn't really match the requirements. What you want to do instead is check if it is a letter (a-z) and if it is add it to charlist, and if it isn't add the reverse of charlist to reverseWordString. Updating the "if" to

if (!char.IsLetter(originalString[i]) || i == originalString.Length - 1)


will get you started, then all you need to do is amend the logic inside that "if" statement to make it simpler really, all it has to do is add the reverse of charlist then add the character that isn't a letter.
 
Share this answer
 
It's not complex: just use double.TryParse[^] to see if the "word" you are converting is a number, and if it is, don't reverse it, just append it to teh output instead.
 
Share this answer
 
Comments
George Swan 20-Aug-20 9:49am    
If you ‘Split’ the sentence into an array of words using a space char as the splitter, you will need to ‘Trim’ each word before testing for a double. Also, have a look at the ‘String.Join’ method for reconstituting your array of processed words back into a sentence. As for reversing a string, it’s just a matter of looking up the literature – some methods are much more efficient than others.
OriginalGriff 20-Aug-20 9:56am    
Erm ... no.
Split discards the split character unfortunately, so "abc 123 def" would be rendered as three trimmed strings: "abc", "123", and "def".
He can't use Join to rebuild it because he has to reverse the character order of most of 'em - that's why he's using a StringBuilder. Yes, he could use Array.Reverse for each word, but that means allocating new array space for each of them which isn't a "fast" operation.
George Swan 20-Aug-20 10:03am    
 string tester = "1 cup of hot coffee costs 8.00, whereas cold coffee costs 45.00.";
            string[] words = tester.Split(' ');
            List<string> reversedWords = new List<string>();
            foreach(var word in words)
            {
                 string trimmed = word.Trim(',', '.', ';');
                string s = double.TryParse(trimmed, out _) ? word : ReverseString(word);              
                    reversedWords.Add(s);              
            }
            var reversed = string.Join(" ", reversedWords);
PIEBALDconsult 20-Aug-20 13:02pm    
Hey, we haven't had a Friday Code Challenge in ages... :D
BillWoodruff 21-Aug-20 0:40am    
The problem is Double.TryParse will fail on the trailing chars in on both 8.00, and 45.00. Piebald has an elegant solution, and my "regex challenged" attempt added.
edit: with hindsight, I think the only way to make this robust is to parse the string character by character. Should 5.00x be rendered as x00.5, as I do here, or, throw an error ?

for those "regex challenged" ... a more awkward solution:
private string StrReverse(string data)
{
    char[] splitchars = new char[] {' ','\t','\r','\n'};
    
    StringBuilder odata = new StringBuilder();
    
    string[] splitStrings = data.Split(splitchars, StringSplitOptions.RemoveEmptyEntries);
    
    double num;
    
    foreach (string str in splitStrings)
    {
        if (Double.TryParse(str, out num))
        {
            odata.Append(str);
        }
        else
        {
            // is the last char punctuation ?
            if(Char.IsPunctuation(str.Last()))
            {
                // can we make a number without trailing punctuation ?
                if (Double.TryParse(str.Substring(0, str.Length - 1), out num))
                {
                    // add it with trailing punctuation intact
                    odata.Append(str);
                }
                else
                {
                    // just reverse it
                    odata.Append(str.Reverse().ToArray());
                }
            }
            else
            {
                
                odata.Append(str.Reverse().ToArray());
            }
        }
    
        odata.Append(" ");
    }
    
    return odata.ToString();
}
Note: I suspect using Regex, as shown by Piebald, here, could handle other possible variations.
 
Share this answer
 
v3
Comments
PIEBALDconsult 21-Aug-20 10:43am    
In the absence of a clearer spec, I believe "5.00x" to "x00.5" is incorrect -- you are reversing non-alphabetic characters.
The OP's code may do that, but that would be why he's asking for help.
"US$5.00" to "SU$5.00" may be correct or maybe that should not be altered (I don't know).
What intrigues me, though would be how to treat something like "dotted.text". What would the desired result be: unchanged , "dettod.txet" , "txet.dettod" , "txetde.ttod"
I gots ta know!
BillWoodruff 21-Aug-20 13:55pm    
:) "in the absence of a clearer spec"
PIEBALDconsult 21-Aug-20 14:45pm    
We haven't seen the actual homework assignment.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900