views:

450

answers:

8

Hi guys

I'm trying to maniplulate a string without making a big issue out of it and spreading it out onto multiple lines, so I'm using some chaining to achieve this. The question I have is, how do I use string.Substring() to drop the last character off my string in this context?

In PHP I can pass a negative number as an argument (i.e. substr(-1)) to achieve this, but obviously this isn't how C# works.

mystring = mystring.Replace('_', ' ').Substring(???);

Also, what is the actual name for the technique used above? I always referred to it as a callback chain, but a callback chain I now think is something completely different.

Please note I want to avoid:

mystring = mystring.Replace('_', ' ');
mystring = mystring.Substring(0, mystring.Length - 1);

Thanks in advance for your time and kind consideration.

Iain

Thanks for your answers guys. It's funny that people can have such strong opinions about string manipulation and other "competing" languages :)

A: 

Method chaining is the term you're looking for. It's true that you cannot pass a negative character like that, but you can still chain the methods:

mystring = mystring.Replace('_', ' ').Substring(0, mystring.Length - 1);

since the string replace in this case, does not affect the length of the string

David Hedlund
As also explained by Timbo, unless both Replace arguments are the same length, the code is wrong since it uses the old mystring.Length.
Tiberiu Ana
Not sure why you were downvoted, but yeah, I kind of simplified my example a bit, there are other methods in the chain which could modify the length.
Iain Fraser
Wouldn't this give him the right output, since he is not trimming the string.mystring = mystring.Substring(0, mystring.Length - 1).Replace('_', ' ');
jaywon
Upvoted for your partial answer of "method chaining"
Iain Fraser
@Tiberiu: both replace arguments *are* the same length in the example
David Hedlund
A: 

mystring = mystring.Replace('_', ' ').Remove(mystring.length -1)

However I would consider this a bad idea since the assignment of mystring doesn't happen until after all the manipulation and change in the length of the string in previous calls will result in unexpected behavior.

rerun
A: 

To further Konamiman's comment:

Just because PHP allows bizarre (and frankly dirty and dangerous) overloads and parameters such as negative starts and counts in SubString, it doesn't mean it's the right, correct or proper way of doing it.

Substring(0, mystring.Length - 1) is the de facto way of trimming off the last character of a string in a wide variety of languages.

iAn
Nothing particularly dirty about negative starts and counts, it's just syntax. As shown, it can shorten your code. Whether this is desirable or not is another discussion.
Tiberiu Ana
I don't think I agree with you there iAn. As Tiberiu commented, the argument you're making is about syntax and although PHP has its problems (dreadfully inconsistent function names being just one), it is pretty good at string manipulation and can do it with a minimal amount of code. I am just starting out in the C# world and although I really like it, so far I find some really simple features to be sorely lacking.
Iain Fraser
+8  A: 

You could write an Extension method RightStrip(). You can't overload SubString for negative start positions.

    static string RightStrip(this string s, int n)
    {
        return s.Substring(0, s.Length - n);
    }


    string s = "Hello World!";
    s = s.Replace('e', 'a').RightStrip(1);
Henk Holterman
Extension methods and some duct tape and you can make the language into everything it's not. +1, this is the only real solution to this question.
Tiberiu Ana
Nice solution Henk, I like it and your example. Its a real pity that such simple features are sorely lacking from the language :( (string.Reverse() being another one of many)
Iain Fraser
+1  A: 

In your sample, you are chaining to a method that doesn't change the length of the original string. Hence answers suggesting using SubString with (originalLength-1), which of course doesn't work in the general case.

The answer as you seem to have realized is - you can't do it in the general case, where previous methods in the chain have modified the length.

But you can write your own extension method in 3.5 to do what you want. Something like the following or a variant thereof:

public static string PhpSubstring(this string value, int length)
{
    if (length < 0) length = value.Length - length;
    return String.Substring(value, length);
}
Joe
As mentioned above, my example is simplified, indeed the length of the string is subject to change. Sorry for the confusion there.
Iain Fraser
+3  A: 

Create an extension class like this:

public static class MyStringExtensions{  
public static string RemoveCharactersFromEnd(this string s, int n)  
{  
    string result = string.Empty;  

    if (string.IsNullOrEmpty(s) == false
        && n > 0)
    {
        result = s.Remove(s.Length - n, n);
    }

    return result;
}}

Call it:
Console.WriteLine("test!!".RemoveCharactersFromEnd(2));

Michel van Engelen
+1  A: 

Hello! Besides everyone else mentioning the term method chaining, or what some call a fluent interface, I had a note or two I wanted to add.

What I wanted to suggest is that the cool thing about extension methods is that you can easily define your own type of transformation functions that feel the same as this, including system methods such as Replace and ToLower, etc.... something that takes some input and returns some kind of transformed string.

The particular transformation you are asking for (cut off the right-most char) might seem clunky if you have to use Substring directly, but you can hide this away neatly in something like:

public string CutOff(this string s, int c)
{
    return s.Substring(0, s.Length - c);
}

...

return myVal.CutOff(1);

(or at least, i think this should work!)

Best of luck!

Funka
Moments after posting my own, I see that Michel van Engelen and I were on the same track, but he has a more graceful solution at hand. Hats off!
Funka
A: 

You could always use regex:

mystring = new Regex("^(.*).$").Match(mystring.Replace('_', ' ')).Groups[1].Value;

Also, since you're just going to remove that last character, it does not matter if it was a '_' that got replaced by a ' '. This would work just fine:

mystring = mystring.Substring(0, mystring.Length - 1).Replace('_', ' ');
ZombieDev