Home > Net >  Take only letters from the string and reverse them
Take only letters from the string and reverse them

Time:09-29

I'm preparing for my interview, faced the problem with the task. The case is that we're having a string: test12pop90java989python

I need to return new string where words will be reversed and numbers will stay in the same place:

test12pop90java989python ==> tset12pop90avaj989nohtyp

What I started with:

  1. Transferring string to char array

  2. Use for loop Char.IsNumber

  3. ??

     var charArray = test.ToCharArray();
     for (int i = 0; i < charArray.Length; i  )
     {
         if (!Char.IsNumber(charArray[i]))
         {
         ....
         }
     }
    

but currently I'm stuck and don't know how to proceed, any tips how it can be done?

CodePudding user response:

You can't reverse a run of letters until you've observed the entire run; until then, you need to keep track of the pending letters to be reversed and appended to the final output upon encountering a number or the end of the string. By storing these pending characters in a Stack<> they are naturally returned in the reverse order they were added.

static string Transform(string input)
{
    StringBuilder outputBuilder = new StringBuilder(input.Length);
    Stack<char> pending = new Stack<char>();

    foreach (char c in input)
        if (char.IsNumber(c))
        {
            // In the reverse order of which they were added, consume
            // and append pending characters as long as they are available
            while (pending.Count > 0)
                outputBuilder.Append(pending.Pop());

            // Alternatively...
            //foreach (char p in pending)
            //  outputBuilder.Append(p);
            //pending.Clear();

            outputBuilder.Append(c);
        }
        else
            pending.Push(c);

    // Handle pending characters when input does not end with a number
    while (pending.Count > 0)
        outputBuilder.Append(pending.Pop());

    return outputBuilder.ToString();
}

A similar but buffer-free way is to do it is to store the index of the start of the current run of letters, then walk back through and append each character when a number is found...

static string Transform(string input)
{
    StringBuilder outputBuilder = new StringBuilder(input.Length);
    int lettersStartIndex = -1;

    for (int i = 0; i < input.Length; i  )
    {
        char c = input[i];

        if (char.IsNumber(c))
        {
            if (lettersStartIndex >= 0)
            {
                // Iterate backwards from the previous character to the start of the run
                for (int j = i - 1; j >= lettersStartIndex; j--)
                    outputBuilder.Append(input[j]);
                lettersStartIndex = -1;
            }

            outputBuilder.Append(c);
        }
        else if (lettersStartIndex < 0)
            lettersStartIndex = i;
    }

    // Handle remaining characters when input does not end with a number
    if (lettersStartIndex >= 0)
        for (int j = input.Length - 1; j >= lettersStartIndex; j--)
            outputBuilder.Append(input[j]);

    return outputBuilder.ToString();
}

For both implementations, calling Transform() with...

string[] inputs = new string[] {
    "test12pop90java989python",
    "123test12pop90java989python321",
    "This text contains no numbers",
    "1a2b3c"
};

for (int i = 0; i < inputs.Length; i  )
{
    string input = inputs[i];
    string output = Transform(input);

    Console.WriteLine($" Input[{i}]: \"{input }\"");
    Console.WriteLine($"Output[{i}]: \"{output}\"");
    Console.WriteLine();
}

...produces this output...

 Input[0]: "test12pop90java989python"
Output[0]: "tset12pop90avaj989nohtyp"

 Input[1]: "123test12pop90java989python321"
Output[1]: "123tset12pop90avaj989nohtyp321"

 Input[2]: "This text contains no numbers"
Output[2]: "srebmun on sniatnoc txet sihT"

 Input[3]: "1a2b3c"
Output[3]: "1a2b3c"

CodePudding user response:

A possible solution using Regex and Linq:

using System;
using System.Text.RegularExpressions;
using System.Linq;
                
public class Program
{
    public static void Main()
    {
        var result = "";
        var matchList = Regex.Matches("test12pop90java989python", "([a-zA-Z]*)(\\d*)");
        var list = matchList.Cast<Match>().SelectMany(o =>o.Groups.Cast<Capture>().Skip(1).Select(c => c.Value));
        foreach (var el in list)
        {
            if (el.All(char.IsDigit))
            {
                result  = el;
            }
            else
            {
                result  = new string(el.Reverse().ToArray());
            }
        }

        Console.WriteLine(result);
    }
}

I've used code from stackoverflow.com/a/21123574/1037948 to create a list of Regex matches on line 11:

var list = matchList.Cast<Match>().SelectMany(o =>o.Groups.Cast<Capture>().Skip(1).Select(c => c.Value));

CodePudding user response:

Hey you can do something like:

string test = "test12pop90java989python", tempStr = "", finalstr = "";
            var charArray = test.ToCharArray();

            for (int i = 0; i < charArray.Length; i  )
            {
                if (!Char.IsNumber(charArray[i]))
                {
                    tempStr  = charArray[i];
                }
                else
                {
                    char[] ReverseString = tempStr.Reverse().ToArray();
                    foreach (char charItem in ReverseString)
                    {
                        finalstr  = charItem;
                    }

                    tempStr = "";
                    finalstr  = charArray[i];
                }
            }

            if(tempStr != "" && tempStr != null)
            {
                char[] ReverseString = tempStr.Reverse().ToArray();
                foreach (char charItem in ReverseString)
                {
                    finalstr  = charItem;
                }

                tempStr = "";
            }

I hope this helps

  • Related