Какой самый чистый способ редактирования символов в строке на С#?
Что эквивалентно С# этого в С++:
std::string myString = "boom";
myString[0] = "d";
Какой самый чистый способ редактирования символов в строке на С#?
Что эквивалентно С# этого в С++:
std::string myString = "boom";
myString[0] = "d";
Решил, что я почувствовал, где два самых канонических подхода, плюс один, который я бросил как непредставленный; вот что я нашел (Release build):
ReplaceAtChars: 86ms ReplaceAtSubstring: 258ms ReplaceAtStringBuilder: 161ms
Очевидно, что подход массива Char намного лучше всего оптимизируется во время выполнения. Что на самом деле предполагает, что текущий ведущий ответ (StringBuilder), вероятно, не лучший ответ.
И вот тест, который я использовал:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("ReplaceAtChars: " + new Stopwatch().Time(() => "test".ReplaceAtChars(1, 'E').ReplaceAtChars(3, 'T'), 1000000) + "ms");
Console.WriteLine("ReplaceAtSubstring: " + new Stopwatch().Time(() => "test".ReplaceAtSubstring(1, 'E').ReplaceAtSubstring(3, 'T'), 1000000) + "ms");
Console.WriteLine("ReplaceAtStringBuilder: " + new Stopwatch().Time(() => "test".ReplaceAtStringBuilder(1, 'E').ReplaceAtStringBuilder(3, 'T'), 1000000) + "ms");
}
}
public static class ReplaceAtExtensions
{
public static string ReplaceAtChars(this string source, int index, char replacement)
{
var temp = source.ToCharArray();
temp[index] = replacement;
return new String(temp);
}
public static string ReplaceAtStringBuilder(this string source, int index, char replacement)
{
var sb = new StringBuilder(source);
sb[index] = replacement;
return sb.ToString();
}
public static string ReplaceAtSubstring(this string source, int index, char replacement)
{
return source.Substring(0, index) + replacement + source.Substring(index + 1);
}
}
public static class StopwatchExtensions
{
public static long Time(this Stopwatch sw, Action action, int iterations)
{
sw.Reset();
sw.Start();
for (int i = 0; i < iterations; i++)
{
action();
}
sw.Stop();
return sw.ElapsedMilliseconds;
}
}
Вместо этого используйте StringBuilder
.
строка неизменна, как описано в MSDN:
Строки неизменяемы - содержимое строковый объект не может быть изменен после создания объекта, хотя синтаксис заставляет его выглядеть так, как будто вы может это сделать.
Итак, вы хотите что-то вроде:
StringBuilder sb = new StringBuilder("Bello World!");
sb[0] = 'H';
string str = sb.ToString();
Строки в .Net неизменяемы. Это означает, что вы не можете редактировать их. Все, что вы можете сделать, это сделать новые. Вы должны сделать что-то вроде этого:
string myString = "boom";
myString = "d" + myString.Substring(1);
Строки неизменяемы, поэтому вы не можете просто изменить их.
Вы можете получить char [] из строки, внести свои изменения и создать новую строку из измененного массива.
Вы можете использовать такие вещи, как замена, хотя они не дают вам контроля над базой w981 > как C. Они также будут создавать новую строку с каждым изменением, где стиль char [] позволяет вам вносить все изменения, а затем создавать из него новую строку.
Вы не можете, так как строки неизменяемы.
Вы всегда можете использовать собственный метод расширения, чтобы сделать что-то подобное:
public static string ReplaceAtIndex(this string original,
int index, char character)
{
char[] temp = original.ToCharArray();
temp[index] = character;
return new String(temp);
}
И назовите его так:
string newString = myString.ReplaceAtIndex(0, 'd');
Как сказал Брайан, используйте StringBuilder
, вместо этого:
string myString = "boom";
StringBuilder myStringBuilder = new StringBuilder(myString);
myStringBuilder[0] = 'd';
// Whatever else you're going to do to it
Если вам нужна строка снова, вызовите myStringBuilder.ToString()
string myString = "boom";
char[] arr = myString.ToCharArray();
arr[0] = 'd';
myString = new String(arr);
string myString = "boom";
char[] myChars = myString.ToCharArray();
myChars[0] = 'd';
myString = new String(myChars);
Здесь весело, я собрал вместе. Теперь, пожалуйста, имейте в виду, что это не очень эффективно, особенно для простых замен. Однако было интересно писать и поддаваться довольно читаемому шаблону использования. Он также подчеркивает малоизвестный факт, что String реализует IEnumerable.
public static class LinqToStrings
{
public static IQueryable<char> LinqReplace(this string source, int startIndex, int length, string replacement)
{
var querySource = source.AsQueryable();
return querySource.LinqReplace(startIndex, length, replacement);
}
public static IQueryable<char> LinqReplace(this IQueryable<char> source, int startIndex, int length, string replacement)
{
var querySource = source.AsQueryable();
return querySource.Take(startIndex).Concat(replacement).Concat(querySource.Skip(startIndex + length));
}
public static string AsString(this IQueryable<char> source)
{
return new string(source.ToArray());
}
}
И вот пример использования:
public void test()
{
var test = "test";
Console.WriteLine("Old: " + test);
Console.WriteLine("New: " + test.LinqReplace(0, 4, "SOMEPIG")
.LinqReplace(4, 0, "terrific")
.AsString());
}
Выходы:
Old: test New: SOMEterrificPIG
Другая версия того же подхода, которая не так ужасно медленна, проста, используя подстроку:
public static string ReplaceAt(this string source, int startIndex, int length, string replacement)
{
return source.Substring(0, startIndex) + replacement + source.Substring(startIndex + length);
}
И в прекрасном примере, почему вы должны профилировать свой код, и почему вы, вероятно, должны не использовать мою реализацию LinqToStrings в производственном коде, здесь следует провести тест времени:
Console.WriteLine("Using LinqToStrings: " + new Stopwatch().Time(() => "test".LinqReplace(0, 4, "SOMEPIG").LinqReplace(4, 0, "terrific").AsString(), 1000));
Console.WriteLine("Using Substrings: " + new Stopwatch().Time(() => "test".ReplaceAt(0, 4, "SOMEPIG").ReplaceAt(4, 0, "terrific"), 1000));
Какие меры таймер тикает в 1000 итераций, создавая этот вывод:
Using LinqToStrings: 3,818,953 Using Substrings: 1,157
Строки неизменны в С#. Используйте класс StringBuilder или массив символов.
StringBuilder sb = new StringBuilder("boom");
sb[0] = 'd';
IIRC,.NET использует то, что называется String Pooling. Каждый раз, когда создается новый строковый литерал, он сохраняется в памяти как часть пула строк. Если вы создаете вторую строку, которая соответствует строке в пуле строк, обе переменные будут ссылаться на одну и ту же память.
Когда вы пытаетесь выполнить операцию, подобную вашей, чтобы заменить символ "b" символом "d", используя строки в .NET, ваша программа фактически создает вторую строку в пуле строк со значением "doom", хотя с вашей точки зрения это не выглядит так, как будто это происходит вообще. Читая код, можно предположить, что символ заменяется.
Я понял это, потому что я постоянно сталкиваюсь с этим вопросом, и люди часто спрашивают, почему они должны использовать StringBuilder, когда строка может делать то же самое. Ну технически он не может, но он разработан таким образом, чтобы выглядеть так, как если бы он мог.
Попробуйте использовать string.replace
http://msdn.microsoft.com/en-us/library/fk49wtc1.aspx
Наверное, ваш самый чистый, самый простой способ.