Я ищу методы расширения String для TrimStart()
и TrimEnd()
, которые принимают строковый параметр.
Я мог бы построить его сам, но мне всегда интересно видеть, как другие люди делают что-то.
Как это можно сделать?
Я ищу методы расширения String для TrimStart()
и TrimEnd()
, которые принимают строковый параметр.
Я мог бы построить его сам, но мне всегда интересно видеть, как другие люди делают что-то.
Как это можно сделать?
Чтобы обрезать все вхождения (точно совпадающие) строки, вы можете использовать что-то вроде следующего:
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;
}
Чтобы обрезать любой из символов в trimChars от начала/конца цели (например, "foobar'@"@';".TrimEnd(";@'")
вернет "foobar"
), вы можете использовать следующее:
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());
}
TrimStart и TrimEnd берут массив символов. Это означает, что вы можете передать строку как массив char следующим образом:
var trimChars = " .+-";
var trimmed = myString.TrimStart(trimChars.ToCharArray());
Поэтому я не вижу необходимости в перегрузке, которая принимает строковый параметр.
Я думал, что вопрос пытается обрезать определенную строку с начала более крупной строки.
Например, если бы у меня была строка "hellohellogoodbyehello", если вы попытались позвонить TrimStart ( "привет" ), вы вернетесь "goodbyehello".
Если это так, вы можете использовать следующий код:
string TrimStart(string source, string toTrim)
{
string s = source;
while (s.StartsWith(toTrim))
{
s = s.Substring(toTrim.Length - 1);
}
return s;
}
Это не было бы суперэффективно, если бы вам нужно было много обрезки строк, но если это всего лишь для нескольких случаев, это просто и выполняется.
из dotnetperls.com,
Производительность
К сожалению, метод TrimStart не сильно оптимизирован. В в определенных ситуациях вы, вероятно, сможете писать на основе символов итерационный код, который может превзойти его. Это связано с тем, что массив должен создаются для использования TrimStart.
Однако: Пользовательский код не обязательно должен иметь массив. Но для быстро разработанные приложения, метод TrimStart полезен.
Чтобы сопоставить всю строку и не выделять несколько подстрок, вы должны использовать следующее:
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);
}
В С# нет встроенной функции, но вы можете написать свои собственные расширения, которые ведут себя точно так, как вы ожидаете.
Обратите внимание, что с IndexOf/LastIndexOf вы можете выбрать, чувствителен ли он к регистру/культура или нет.
Я также использовал функцию "повторяющиеся обрезки".
Существует одна функция TrimStr(..)
, работающая как с обрезками, так и с тремя функциями, реализующими .TrimStart(...)
, .TrimEnd(...)
и .Trim(..)
для совместимости с .NET-обрезками:
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
{
if (!(str ?? "").EndsWith(trimStr)) return str;
strLen = str.Length;
{
if (trimEnd)
{
var pos = str.LastIndexOf(trimStr, comparisonType);
if ((!(pos >= 0)) || (!(str.Length - trimStr.Length == pos))) break;
str = str.Substring(0, pos);
}
else
{
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);
}
Теперь вы можете просто использовать его как
Console.WriteLine("Sammy".TrimEnd("my"));
Console.WriteLine("moinmoin gibts gips? gips gibts moin".TrimStart("moin", false));
Console.WriteLine("moinmoin gibts gips? gips gibts moin".Trim("moin").Trim());
который создает выходные данные
Сэм
moin gibts gips? gips gibts moin
gibts gips? gips gibts
Я предполагаю, что вы имеете в виду, что, например, учитывая строку "HelloWorld" и вызывая функцию "обрезать" начало с помощью "Hello", вы останетесь с "World". Я бы сказал, что это действительно операция подстроки, поскольку вы удаляете часть строки известной длины, а не операцию обрезки, которая удаляет неизвестную длину строки.
Таким образом, мы создали пару методов расширения с именем SubstringAfter
и SubstringBefore
. Было бы неплохо иметь их в рамках, но они не настолько, что вам нужно их реализовать. Не забудьте указать параметр StringComparison
и использовать Ordinal
как значение по умолчанию, если вы сделаете его необязательным.
Если вам нужен тот, который не использовал встроенные функции отделки по каким-либо причинам, предполагая, что вы хотите использовать строку ввода для обрезки, такую как "~!" по существу, такой же, как встроенный TrimStart с ['', '~', '!']
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;
}
Функция для обрезки начала/конца строки с помощью строкового параметра, но только один раз (без циклов, этот единственный случай более популярен, цикл может быть добавлен с дополнительным параметром для его запуска):
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;
}
}
Как упомянуто ранее, если вы хотите реализовать подход "в то время как цикл", не забудьте проверить наличие пустой строки, иначе он может зацикливаться вечно.