6

The following simple program will find the last letter in a string that a user enters and then remove everything after that point. So, if a person enters one string.... everything after the g should be removed. I've got the following as a little program:

class Program
{
    static void Main(string[] args)
    {
        Console.Write("Enter in the value of the string: ");
        List<char> charList = Console.ReadLine().Trim().ToList();

        int x = charList.LastIndexOf(charList.Last(char.IsLetter)) ;
        Console.WriteLine("this is the last letter {0}", x);
        Console.WriteLine("This is the length of the string {0}", charList.Count);
        Console.WriteLine("We should have the last {0} characters removed", charList.Count - x);

        for (int i = x; i < charList.Count; i++)
        {
            charList.Remove(charList[i]);
        }

        foreach (char c in charList)
        {
            Console.Write(c);
        }
        Console.ReadLine();
    }
}

I've tried numerous variations of this and none of them getting it exactly write. This particular program with an input of string.... the output of the program is strin.. So somehow it's leaving on what it should be taking away and it's actually taking away letters that it shouldn't. Can anyone give an indication as to why this is happening? The desired output, again should be string.

JackPoint
  • 4,031
  • 1
  • 30
  • 42
wootscootinboogie
  • 8,461
  • 33
  • 112
  • 197

10 Answers10

5

Try this:

string input = Console.ReadLine();                // ABC.ABC.
int index = input.Select((c, i) => new { c, i })
                 .Where(x => char.IsLetter(x.c))
                 .Max(x => x.i);
string trimmedInput = input.Substring(0, index + 1);
Console.WriteLine(trimmedInput);                  // ABC.ABC
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • +1 No need for `substring`. `String.Join("", input.TakeWhile(char.IsLetter))` – I4V Apr 29 '13 at 13:02
  • This will fail! This will not look for the last letter, it will look for the first NON-letter and delete the rest, including the letters coming after it. – Martin Mulder Apr 29 '13 at 13:03
  • 1
    Yes this fails on `"ABC.ABC."` which (according to the spec) should produce `"ABC.ABC"` – Matthew Watson Apr 29 '13 at 13:06
  • @MartinMulder / MatthewWatson Not as elegant as my initial solution, but it satisfies the requirements better. – p.s.w.g Apr 29 '13 at 13:12
3

Jsut for the explanation, that's because each time you remove a character, you increment the i counter but also decrementing charList.Count so you're actually removing 1 character, leaving the next one, then removing again and so on...

For example, with the input "string...." and x being 5 (index of the G letter) you're doing :

1st iteration : Remove the g char so x becomes 6 and charList.Count becomes 9 (10-1)

Next iteration : Remove the char at index 6 which is now the second . (your string being "strin....").

So you missed the first point.

I let you check other answers as they contains more elegant solutions for your problems.

Marshall777
  • 1,196
  • 5
  • 15
2

I think it would be a lot more straight forward to simply Substring the string the user entered. So consider the following modified code:

 class Program
 {
    static void Main(string[] args)
    {
        Console.Write("Enter in the value of the string: ");
        var s = Console.ReadLine().Trim();
        List<char> charList = s.ToList();

        int x = charList.LastIndexOf(charList.Last(char.IsLetter)) ;
        Console.WriteLine("this is the last letter {0}", x);
        Console.WriteLine("This is the length of the string {0}", charList.Count);
        Console.WriteLine("We should have the last {0} characters removed", charList.Count - x);

        Console.WriteLine(s.Substring(0, x + 1);
        Console.ReadLine();
    }
}

here we store the value the user entered into s, find the last index of a letter, and then Substring through that letter when writing out to the console.

JackPoint
  • 4,031
  • 1
  • 30
  • 42
Mike Perrenoud
  • 66,820
  • 29
  • 157
  • 232
2
string s = console.ReadLine();
s = s.Substring(0, s.ToList().FindLastIndex(char.IsLetter) + 1);
Martin Mulder
  • 12,642
  • 3
  • 25
  • 54
1

You also can use a function of string called SubString, to get everything from the first to the last letter index.

Michel Keijzers
  • 15,025
  • 28
  • 93
  • 119
1

Here's a pretty inefficient way to do it (just for fun!)

var trimmedInput = string.Join("", input.Reverse().SkipWhile(x => !char.IsLetter(x)).Reverse());
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
1

You could use this extension:

public static string TrimLettersLeft(this string input)
{ 
    int lastLetterIndex = -1;
    for (int i = input.Length - 1; i >= 0; i--)
    {
        if (Char.IsLetter(input[i]))
        {
            lastLetterIndex = i;
            break;
        }
    }

    if( lastLetterIndex == -1)
        return input;
    else
        return input.Substring(0, lastLetterIndex + 1);
}

Input: test...abc... Output: test...abc

DEMO

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
1

Solution will be like this.

string charList = "string..."; //any string place here
int x = charList.LastIndexOf(charList.Last(char.IsLetter));
String str = charList.ToString().Substring(0, x + 1);
umirza47
  • 940
  • 2
  • 10
  • 21
0

This will match every word character (A-Z, 0-9 and _):

string Input = Console.ReadLine();
string Userinput = String.Empty;
Regex TextSearch = new Regex(@"\w*");

if(TextSearch.IsMatch(Input))
    Userinput = TextSearch.Match(Input).Groups[0].Value;
else
    // No valid Input
Mecaveli
  • 1,507
  • 10
  • 16
0

What I believe would be the shortest, simplest option:

Edit: A comment pointed out an initial error here, so I added a little fix. Should work nicely now (might not be the optimal solution, but I thought it was a fun an simple solution anyway):

var userInput = Console.ReadLine();

Console.WriteLine(new string(userInput.Reverse()
                                      .SkipWhile(c => !char.IsLetter(c))
                                      .Reverse()
                                      .ToArray()));
Kjartan
  • 18,591
  • 15
  • 71
  • 96
  • This will fail! This will not look for the last letter, it will look for the first NON-letter and delete the rest, including the letters coming after it. – Martin Mulder Apr 29 '13 at 13:08
  • @MartinMulder Thanks for pointing that out, you were quite right. Made a little change now, so I believe it should be correct now. – Kjartan Apr 29 '13 at 13:26
  • Great... but... be aware: This answer was already presented by Matthew Watson. – Martin Mulder Apr 29 '13 at 13:28
  • Coincidence, so what? My original answer was here first, and fixed with a minor twist. Big deal. (Besides, mine is arguably more readable, both initially and after the edit ;) ) – Kjartan Apr 29 '13 at 13:41