Подтвердить что ты не робот

Редактировать символы в строке в С#

Какой самый чистый способ редактирования символов в строке на С#?

Что эквивалентно С# этого в С++:

std::string myString = "boom";
myString[0] = "d";
4b9b3361

Ответ 1

Решил, что я почувствовал, где два самых канонических подхода, плюс один, который я бросил как непредставленный; вот что я нашел (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;
    }
}

Ответ 2

Вместо этого используйте StringBuilder.

строка неизменна, как описано в MSDN:

Строки неизменяемы - содержимое строковый объект не может быть изменен после создания объекта, хотя синтаксис заставляет его выглядеть так, как будто вы может это сделать.

Итак, вы хотите что-то вроде:

 StringBuilder sb = new StringBuilder("Bello World!");
 sb[0] = 'H';
 string str = sb.ToString();

Ответ 3

Строки в .Net неизменяемы. Это означает, что вы не можете редактировать их. Все, что вы можете сделать, это сделать новые. Вы должны сделать что-то вроде этого:

string myString = "boom";
myString = "d" + myString.Substring(1);

Ответ 4

Строки неизменяемы, поэтому вы не можете просто изменить их.

Вы можете получить char [] из строки, внести свои изменения и создать новую строку из измененного массива.

Вы можете использовать такие вещи, как замена, хотя они не дают вам контроля над базой w981 > как C. Они также будут создавать новую строку с каждым изменением, где стиль char [] позволяет вам вносить все изменения, а затем создавать из него новую строку.

Ответ 5

Вы не можете, так как строки неизменяемы.

Вы всегда можете использовать собственный метод расширения, чтобы сделать что-то подобное:

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');

Ответ 6

Как сказал Брайан, используйте StringBuilder, вместо этого:

string myString = "boom";
StringBuilder myStringBuilder = new StringBuilder(myString);
myStringBuilder[0] = 'd';
// Whatever else you're going to do to it

Если вам нужна строка снова, вызовите myStringBuilder.ToString()

Ответ 7

string myString = "boom";
char[] arr = myString.ToCharArray();
arr[0] = 'd';
myString = new String(arr);

Ответ 8

string myString = "boom";
char[] myChars = myString.ToCharArray();
myChars[0] = 'd';
myString = new String(myChars);

Ответ 9

Здесь весело, я собрал вместе. Теперь, пожалуйста, имейте в виду, что это не очень эффективно, особенно для простых замен. Однако было интересно писать и поддаваться довольно читаемому шаблону использования. Он также подчеркивает малоизвестный факт, что 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

Ответ 10

Строки неизменны в С#. Используйте класс StringBuilder или массив символов.

StringBuilder sb = new StringBuilder("boom");
sb[0] = 'd';

IIRC,.NET использует то, что называется String Pooling. Каждый раз, когда создается новый строковый литерал, он сохраняется в памяти как часть пула строк. Если вы создаете вторую строку, которая соответствует строке в пуле строк, обе переменные будут ссылаться на одну и ту же память.

Когда вы пытаетесь выполнить операцию, подобную вашей, чтобы заменить символ "b" символом "d", используя строки в .NET, ваша программа фактически создает вторую строку в пуле строк со значением "doom", хотя с вашей точки зрения это не выглядит так, как будто это происходит вообще. Читая код, можно предположить, что символ заменяется.

Я понял это, потому что я постоянно сталкиваюсь с этим вопросом, и люди часто спрашивают, почему они должны использовать StringBuilder, когда строка может делать то же самое. Ну технически он не может, но он разработан таким образом, чтобы выглядеть так, как если бы он мог.