Редактирование изменяемой строки в C # / .NET

2

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

while (script.IndexOf("@Unique", StringComparison.InvariantCultureIgnoreCase) != -1)
{
   int Location = script.IndexOf("@Unique", StringComparison.InvariantCultureIgnoreCase);
   script = script.Remove(Location, 7);
   script = script.Insert(Location, Guid.NewGuid().ToString());
}

Как нет IndexOf в StringBuilder. Есть ли у кого-нибудь эффективный способ редактирования текстовой информации на месте?

Изменить # 1: Измененный образец, чтобы сделать более очевидным, что каждая "замена" должна иметь другой результат.

Теги:

8 ответов

5
Лучший ответ

Если ваш код действительно является таким простым, почему бы просто не использовать один из встроенных методов Replace, либо на string, StringBuilder или Regex?

ИЗМЕНИТЬ СЛЕДУЮЩИЙ КОММЕНТАРИЙ...

Вы можете заменить каждое вхождение отдельным значением, используя одну из перегрузок Regex.Replace, которая принимает аргумент MatchEvaluator:

string foo = "blah blah @Unique blah @Unique blah blah @Unique blah";

// replace each occurrence of "@Unique" with a separate guid
string bar = Regex.Replace(foo, "@Unique",
    new MatchEvaluator(m => Guid.NewGuid().ToString()),
    RegexOptions.IgnoreCase));
  • 0
    Моя проблема в том, что каждому экземпляру @Unique в приведенном выше примере требуется свое значение, поэтому я не могу выполнить глобальный поиск и замену в строке.
  • 0
    @JasonRShaver: это можно сделать с помощью Regex.Replace . Взгляните на мою правку.
Показать ещё 3 комментария
2

Сколько изменений вы будете делать?

Если это не четыре цифры, а просто принять новые экземпляры строк, вы можете преждевременно оптимизировать...

Другое решение... Разделите на "@uniqueID", затем присоединитесь к StringBuilder, добавив ваш seperator для каждой итерации.

  • 0
    Система будет обрабатывать около 300 000 единиц на ожидаемом пике.
  • 0
    @Jason - а какова спецификация производительности для этого метода при пиковой нагрузке? Сделайте реализацию и сравните ее при загрузке. Если он соответствует спецификациям, отправьте его. Если нет, профилируйте это. +1.
2

Как насчет StringBuilder " Replace" метод:

StringBuilder script;
script.Replace("@Unique", GetGuidString());
  • 2
    Если строка имеет два @ уникальных, то обе замены будут иметь одно и то же значение вместо уникальных значений. Вот почему он не хочет использовать IndexOf, поэтому для каждой замены создается новое уникальное значение.
  • 0
    Я не думаю, что StringBuilder может быть использован в этом сценарии тогда. Вы должны обрабатывать его только как строку, может быть, вы можете обработать его перед добавлением в StringBuilder.
1

Пользователь Dennis предоставил метод расширения IndexOf для StringBuilder. Таким образом, вы должны иметь возможность использовать StringBuilder таким образом.

1

StringBuilder создан таким образом, что вы можете легко добавить к нему, но при компромиссе, который трудно найти в нем - и тем более сложнее (т.е. медленнее) индексировать его. Если вам нужно изменить некоторые символы "на месте", лучше всего сделать это в результирующей строке.

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

0

но должен быть эффективным решением

    public StringBuilder Replace(this StringBuilder sb, string toReplace, Func<string> getReplacement)
    {
        for (int i = 0; i < sb.Length; i++)
        {
            bool replacementFound = true;
            for (int toReplaceIndex = 0; toReplaceIndex < toReplace.Length; toReplaceIndex++)
            {
                int sbIndex = toReplaceIndex + i;
                if (sbIndex < sb.Length)
                {
                    return sb;
                }
                if (sb[sbIndex] != toReplace[toReplaceIndex])
                {
                    replacementFound = false;
                    break;
                }
            }
            if (replacementFound)
            {
                string replacement = getReplacement();
                // reuse the space of the toReplace string
                for (int replacementIndex = 0; replacementIndex < toReplace.Length && replacementIndex < replacement.Length; replacementIndex++)
                {
                    int sbIndex = replacementIndex + i;
                    sb[sbIndex] = replacement[i];
                }
                // remove toReplace string remainders
                if (replacement.Length < toReplace.Length)
                {
                    sb.Remove(i + replacement.Length, replacement.Length - toReplace.Length)
                }
                // insert chars not yet inserted
                if (replacement.Length > toReplace.Length)
                {
                    sb.Insert(i + toReplace.Length, replacement.ToCharArray(toReplace.Length, toReplace.Length - replacement.Length));
                }
            }
        }
        return sb;
    }

случай использования

var sb = new StringBuilder(script);

script = sb.Replace("@Unique", () => Guid.NewGuid().ToString()).ToString();
0

Можете ли вы использовать разделение строк, чтобы сделать это эффективно?

Что-то вроде:

var sections = "a-@Unique-b-@Unique-c".Split(new string[] { "@Unique" }, StringSplitOptions.None);
int i;
StringBuilder builder = new StringBuilder();
for(i = 0; i < sections.Length - 1; i++)
{
    builder.Append(sections[i]);
    builder.Append(Guid.NewGuid().ToString());
}
builder.Append(sections[i]);

Console.WriteLine(builder.ToString());
Console.ReadKey(true);
-3

Вам понадобится использовать неуправляемый блок кода Так же просто, как объявить указатель на свою строку и манипулировать ею в памяти.

Пример

unsafe
{
  char* ip;
  ip = &to_your_string;
}
  • 0
    Похоже, небезопасный не позволяет объявить указатель на строку. К сожалению :(
  • 1
    -1. Это самая пугающая часть кода на C #, которую я видел за последние месяцы. Я бы никогда даже рассмотреть возможность сделать такую вещь. Я рад, что дизайнеры .NET застрахованы, что это не сработает.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню