Reputation: 14713
I'm looking for String extension methods for TrimStart()
and TrimEnd()
that accept a string parameter.
I could build one myself but I'm always interested in seeing how other people do things.
How can this be done?
Upvotes: 98
Views: 101317
Reputation: 27001
There is no built in function in C# - but you can write your own extension methods which I will show you below - they can be used like the builtin ones to trim characters, but here you can use strings to trim.
Note that with IndexOf / LastIndexOf, you can choose if it is case sensitive / culture sensitive or not.
I have implemented the feature "repetitive trims" as well (see the optional parameters).
Usage:
// myStr: the string that needs to be trimmed
// trimStr: the string to trim from myStr
var trimmed1 = myStr.TrimStart(trimStr);
var trimmed2 = myStr.TrimEnd(trimStr);
var trimmed3 = myStr.TrimStr(trimStr);
var trimmed4 = myStr.Trim(trimStr);
There is one function TrimStr(..)
trimming from the start and from the end of the string, plus three functions implementing .TrimStart(...)
, .TrimEnd(...)
and .Trim(..)
for compatibility with the .NET trims:
public static class Extension
{
public static string TrimStr(this string str, string trimStr,
bool trimEnd = true, bool repeatTrim = true,
StringComparison comparisonType = StringComparison.OrdinalIgnoreCase)
{
int strLen;
do
{
strLen = str.Length;
{
if (trimEnd)
{
if (!(str ?? "").EndsWith(trimStr)) return str;
var pos = str.LastIndexOf(trimStr, comparisonType);
if ((!(pos >= 0)) || (!(str.Length - trimStr.Length == pos))) break;
str = str.Substring(0, pos);
}
else
{
if (!(str ?? "").StartsWith(trimStr)) return str;
var pos = str.IndexOf(trimStr, comparisonType);
if (!(pos == 0)) break;
str = str.Substring(trimStr.Length, str.Length - trimStr.Length);
}
}
} while (repeatTrim && strLen > str.Length);
return str;
}
// the following is C#6 syntax, if you're not using C#6 yet
// replace "=> ..." by { return ... }
public static string TrimEnd(this string str, string trimStr,
bool repeatTrim = true,
StringComparison comparisonType = StringComparison.OrdinalIgnoreCase)
=> TrimStr(str, trimStr, true, repeatTrim, comparisonType);
public static string TrimStart(this string str, string trimStr,
bool repeatTrim = true,
StringComparison comparisonType = StringComparison.OrdinalIgnoreCase)
=> TrimStr(str, trimStr, false, repeatTrim, comparisonType);
public static string Trim(this string str, string trimStr, bool repeatTrim = true,
StringComparison comparisonType = StringComparison.OrdinalIgnoreCase)
=> str.TrimStart(trimStr, repeatTrim, comparisonType)
.TrimEnd(trimStr, repeatTrim, comparisonType);
}
Now you can just use it like
Console.WriteLine("Sammy".TrimEnd("my"));
Console.WriteLine("Sammy".TrimStart("Sam"));
Console.WriteLine("moinmoin gibts gips? gips gibts moin".TrimStart("moin", false));
Console.WriteLine("moinmoin gibts gips? gips gibts moin".Trim("moin").Trim());
which creates the output
Sam
my
moin gibts gips? gips gibts moin
gibts gips? gips gibts
In the last example, the trim function does a repetitive trim, trimming all occurances of "moin" at the beginning and at the end of the string. The example before just trims "moin" only once from the start.
Upvotes: 3
Reputation: 65421
To trim all occurrences of the (exactly matching) string, you can use something like the following:
public static string TrimStart(this string target, string trimString)
{
if (string.IsNullOrEmpty(trimString)) return target;
string result = target;
while (result.StartsWith(trimString))
{
result = result.Substring(trimString.Length);
}
return result;
}
public static string TrimEnd(this string target, string trimString)
{
if (string.IsNullOrEmpty(trimString)) return target;
string result = target;
while (result.EndsWith(trimString))
{
result = result.Substring(0, result.Length - trimString.Length);
}
return result;
}
To trim any of the characters in trimChars from the start/end of target (e.g. "foobar'@"@';".TrimEnd(";@'")
will return "foobar"
) you can use the following:
public static string TrimStart(this string target, string trimChars)
{
return target.TrimStart(trimChars.ToCharArray());
}
public static string TrimEnd(this string target, string trimChars)
{
return target.TrimEnd(trimChars.ToCharArray());
}
Upvotes: 142
Reputation: 2126
Function to trim start/end of a string with a string parameter, but only once (no looping, this single case is more popular, loop can be added with an extra param to trigger it) :
public static class BasicStringExtensions
{
public static string TrimStartString(this string str, string trimValue)
{
if (str.StartsWith(trimValue))
return str.TrimStart(trimValue.ToCharArray());
//otherwise don't modify
return str;
}
public static string TrimEndString(this string str, string trimValue)
{
if (str.EndsWith(trimValue))
return str.TrimEnd(trimValue.ToCharArray());
//otherwise don't modify
return str;
}
}
As mentioned before, if you want to implement the "while loop" approach, be sure to check for empty string otherwise it can loop forever.
Upvotes: -2
Reputation: 527
To match entire string and not allocate multiple substrings, you should use the following:
public static string TrimStart(this string source, string value, StringComparison comparisonType)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
int valueLength = value.Length;
int startIndex = 0;
while (source.IndexOf(value, startIndex, comparisonType) == startIndex)
{
startIndex += valueLength;
}
return source.Substring(startIndex);
}
public static string TrimEnd(this string source, string value, StringComparison comparisonType)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
int sourceLength = source.Length;
int valueLength = value.Length;
int count = sourceLength;
while (source.LastIndexOf(value, count, comparisonType) == count - valueLength)
{
count -= valueLength;
}
return source.Substring(0, count);
}
Upvotes: 6
Reputation: 1874
I thought the question was trying to trim a specific string from the start of a larger string.
For instance, if I had the string "hellohellogoodbyehello", if you tried to call TrimStart("hello") you would get back "goodbyehello".
If that is the case, you could use code like the following:
string TrimStart(string source, string toTrim)
{
string s = source;
while (s.StartsWith(toTrim))
{
s = s.Substring(toTrim.Length - 1);
}
return s;
}
This wouldn't be super-efficient if you needed to do a lot of string-trimming, but if its just for a few cases, it is simple and gets the job done.
Upvotes: 13
Reputation: 3453
from dotnetperls.com,
Performance
Unfortunately, the TrimStart method is not heavily optimized. In specific situations, you will likely be able to write character-based iteration code that can outperform it. This is because an array must be created to use TrimStart.
However: Custom code would not necessarily require an array. But for quickly-developed applications, the TrimStart method is useful.
Upvotes: 3
Reputation: 2965
If you did want one that didn't use the built in trim functions for whatever reasons, assuming you want an input string to use for trimming such as " ~!" to essentially be the same as the built in TrimStart with [' ', '~', '!']
public static String TrimStart(this string inp, string chars)
{
while(chars.Contains(inp[0]))
{
inp = inp.Substring(1);
}
return inp;
}
public static String TrimEnd(this string inp, string chars)
{
while (chars.Contains(inp[inp.Length-1]))
{
inp = inp.Substring(0, inp.Length-1);
}
return inp;
}
Upvotes: -1
Reputation: 136607
I'm assuming you mean that, for example, given the string "HelloWorld" and calling the function to 'trim' the start with "Hello" you'd be left with "World". I'd argue that this is really a substring operation as you're removing a portion of the string of known length, rather than a trim operation which removes an unknown length of string.
As such, we created a couple of extension methods named SubstringAfter
and SubstringBefore
. It would be nice to have them in the framework, but they aren't so you need to implement them yourselves. Don't forget to have a StringComparison
parameter, and to use Ordinal
as the default if you make it optional.
Upvotes: -1
Reputation: 36300
TrimStart and TrimEnd takes in an array of chars. This means that you can pass in a string as a char array like this:
var trimChars = " .+-";
var trimmed = myString.TrimStart(trimChars.ToCharArray());
So I don't see the need for an overload that takes a string parameter.
Upvotes: 18