Есть ли лучший способ, чем String.Replace для удаления backspaces из строки?
У меня есть строка, считанная из другого источника, такого как "\ b\bfoo\bx". В этом случае это будет означать слово "лиса", поскольку первые 2\b игнорируются, а последний "o" стирается, а затем заменяется на "x". Также будет рассмотрен другой случай: "patt\b\b\b\b\b\b\b\b\b\bfoo" должен быть переведен в "foo"
Я придумал что-то, используя String.Replace, но он сложный, и я беспокоюсь, что он работает некорректно, также он создает много новых строковых объектов, которые я бы хотел избежать.
Любые идеи?
Ответы
Ответ 1
Вероятно, проще всего просто перебрать всю строку. Учитывая ваши входы, следующий код делает трюк в 1 проход
public string ReplaceBackspace(string hasBackspace)
{
if( string.IsNullOrEmpty(hasBackspace) )
return hasBackspace;
StringBuilder result = new StringBuilder(hasBackspace.Length);
foreach (char c in hasBackspace)
{
if (c == '\b')
{
if (result.Length > 0)
result.Length--;
}
else
{
result.Append(c);
}
}
return result.ToString();
}
Ответ 2
То, как я это сделаю, является низкотехнологичным, но понятным.
Создайте стек символов. Затем перебираем строку от начала до конца. Если символ является нормальным символом (без косой черты), нажмите его в стек. Если это косая черта, а следующий символ - "b", поместите верхнюю часть стека. Если стек пуст, игнорируйте его.
В конце поместите каждый символ по очереди, добавьте его в StringBuilder и отмените результат.
Ответ 3
Версия регулярных выражений:
var data = @"patt\b\b\b\b\b\b\b\b\b\bfoo";
var regex = new Regex(@"(^|[^\\b])\\b");
while (regex.IsMatch(data))
{
data = regex.Replace(data, "");
}
Оптимизированная версия (и эта работает с backspace '\ b', а не с строкой "\ b" ):
var data = "patt\b\b\b\b\b\b\b\b\b\bfoo";
var regex = new Regex(@"[^\x08]\x08", RegexOptions.Compiled);
while (data.Contains('\b'))
{
data = regex.Replace(data.TrimStart('\b'), "");
}
Ответ 4
public static string ProcessBackspaces(string source)
{
char[] buffer = new char[source.Length];
int idx = 0;
foreach (char c in source)
{
if (c != '\b')
{
buffer[idx] = c;
idx++;
}
else if (idx > 0)
{
idx--;
}
}
return new string(buffer, 0, idx);
}
ИЗМЕНИТЬ
Я сделал быструю и грубую оценку кода, опубликованного в ответах до сих пор (обработка двух примерных строк из вопроса, по миллиону раз каждый):
ANSWER | TIME (ms)
------------------------|-----------
Luke (this one) | 318
Alexander Taran | 567
Robert Paulson | 683
Markus Nigbur | 2100
Kamarey (new version) | 7075
Kamarey (old version) | 30902
Ответ 5
Вы можете перебирать строку назад, делая массив символов, когда идете. Каждый раз, когда вы нажимаете backspace, увеличивайте счетчик и каждый раз, когда вы нажимаете обычный символ, пропустите его, если ваш счетчик не равен нулю и уменьшает счетчик.
Я не уверен, какая лучшая структура данных С# должна управлять этим, а затем быстро получить строку в правильном порядке. StringBuilder
имеет метод Insert
, но я не знаю, будет ли он работать, чтобы вставлять символы в начале или нет. Вы можете поместить символы в стек и нажать ToArray()
в конце - это может быть или не быть быстрее.
Ответ 6
String myString = "patt\b\b\b\b\b\b\b\b\b\bfoo";
List<char> chars = myString.ToCharArray().ToList();
int delCount = 0;
for (int i = chars.Count -1; i >= 0; i--)
{
if (chars[i] == '\b')
{
delCount++;
chars.RemoveAt(i);
} else {
if (delCount > 0 && chars[i] != null) {
chars.RemoveAt(i);
delCount--;
}
}
}
Ответ 7
я бы сказал:
код не проверен
char[] result = new char[input.Length()];
int r =0;
for (i=0; i<input.Length(); i++){
if (input[i] == '\b' && r>0) r--;
else result[r]=input[i];
}
string resultsring = result.take(r);
Ответ 8
Создайте StringBuilder и скопируйте все, кроме символов backspace.