Изменение значения внутри строки

248
07 марта 2017, 13:21

Есть ли способ изменить значение внутри строки не переводя её в массив символов? Например "Машинная сила" в "Машинная пила".

Answer 1

Нет.

Строки в C# неизменяемые, так что вам придётся создавать новую строку, изменить уже существующую строку невозможно*.

Если нужна запись символов по индексу, то проще всего перегнать строку в StringBuilder, в котором можно менять значения по индексу, а также добавлять их и удалять. А после окончания обработки снова перегнать в строку:

string s = "Машинная сила";
StringBuilder sb = new StringBuilder(s);
sb[9] = 'п';
s = sb.ToString();

Если нужно заменить один символ, может быть проще всего откусить подстроку до этого символа и после, и сконкатенировать.

Обратите внимание, что в коде у меня каждый раз создаётся новая строка, так что те, кто имел ссылку на старую строку, не увидят изменений.

*Ну то есть возможно через unsafe-код или там рефлексию, но если вы так сделаете, ваш тимлид и вся команда прибегут бить вас после первого же code review.

Answer 2

Можно использовать unsafe-код, если нужно менять строку. Редко когда такое действительно оправдано, но возможно вам нужно чтобы ваш код очень быстро работал.

В общем это можно делать на свой страх и риск, когда вы уверены, что вы всё предусмотрели и вам нужна действительно огромная производительность.

string s = "Машинная сила";
unsafe
{
    fixed (char* chars = s)
    {
        chars[9] = 'п';
    }
}

Чтобы это компилировалось в свойствах проекта следует отметить галочку Allow unsafe code.

Побочные эффекты

Однако из-за интернирования строк в C# также строки с тем же значением поменяются (спасибо @VladD за эту мысль):

public static void Main()
{
    A();
    Console.WriteLine("Hello world"); // Выведет "Hello bugs!"
}
public static unsafe void A()
{
    string s = string.Intern("Hello world");
    fixed (char* p = s)
    {
        p[6] = 'b'; p[7] = 'u'; p[8] = 'g'; p[9] = 's'; p[10] = '!';
    }
}

Без string.Intern данное поведение также сохраняется.

READ ALSO
C# + Access запись и чтение массива байт

C# + Access запись и чтение массива байт

Имеется программа которая шифрует пароли с помощью AESЭтот алгоритм шифрования использует массивы байт

232
Десериализация JSON в LiteDB

Десериализация JSON в LiteDB

В проекте нужно из JSON-строки получить экземпляр некоторого класса, используя библиотеку LiteDBJSON:

1185
Emgu C# [Unable to read from webcam c# emgu]

Emgu C# [Unable to read from webcam c# emgu]

Нашел на GitHub'e пример с использованием Emgu на C# (RedballTracker)Решил испытать этот пример, изучив код (учусь работать с Emgu)

298
WPF (C#) Splash экран прогресса загрузки в отдельном потоке

WPF (C#) Splash экран прогресса загрузки в отдельном потоке

Имеется приложениеПервый запуск

427