Как заменить часть строки по положению?
У меня есть эта строка: ABCDEFGHIJ
Мне нужно заменить с позиции 4 на позицию 5 строкой ZX
Он будет выглядеть так: ABCZXFGHIJ
Но не использовать с string.replace("DE","ZX")
- мне нужно использовать позицию
Как я могу это сделать?
Ответы
Ответ 1
Самый простой способ добавить и удалить диапазоны в строке - использовать StringBuilder
.
var theString = "ABCDEFGHIJ";
var aStringBuilder = new StringBuilder(theString);
aStringBuilder.Remove(3, 2);
aStringBuilder.Insert(3, "ZX");
theString = aStringBuilder.ToString();
Альтернативой является использование String.Substring
, но я думаю, что код StringBuilder
становится более читаемым.
Ответ 2
string s = "ABCDEFGH";
s= s.Remove(3, 2).Insert(3, "ZX");
Ответ 3
ReplaceAt (int index, int length, string replace)
Здесь используется метод расширения, который не использует StringBuilder или подстроку. Этот метод также позволяет заменяющей строке проходить за длину исходной строки.
//// str - the source string
//// index- the start location to replace at (0-based)
//// length - the number of characters to be removed before inserting
//// replace - the string that is replacing characters
public static string ReplaceAt(this string str, int index, int length, string replace)
{
return str.Remove(index, Math.Min(length, str.Length - index))
.Insert(index, replace);
}
При использовании этой функции, если вы хотите, чтобы вся строка замены заменяла как можно больше символов, установите длину в длину строки замены:
"0123456789".ReplaceAt(7, 5, "Hello") = "0123456Hello"
В противном случае вы можете указать количество символов, которые будут удалены:
"0123456789".ReplaceAt(2, 2, "Hello") = "01Hello456789"
Если вы указываете длину равным 0, эта функция действует так же, как функция вставки:
"0123456789".ReplaceAt(4, 0, "Hello") = "0123Hello456789"
Я думаю, что это более эффективно, поскольку класс StringBuilder не нужно инициализировать и поскольку он использует более основные операции. Пожалуйста, поправьте меня, если я ошибаюсь.:)
Ответ 4
Используйте String.Substring()
(подробнее здесь), чтобы вырезать левую часть, затем вашу замену, затем правую часть. Играйте с индексами, пока не получите правильное значение:)
Что-то вроде:
string replacement=original.Substring(0,start)+
rep+original.Substring(start+rep.Length);
Ответ 5
Как метод расширения.
public static class StringBuilderExtension
{
public static string SubsituteString(this string OriginalStr, int index, int length, string SubsituteStr)
{
return new StringBuilder(OriginalStr).Remove(index, length).Insert(index, SubsituteStr).ToString();
}
}
Ответ 6
string s = "ABCDEFG";
string t = "st";
s = s.Remove(4, t.Length);
s = s.Insert(4, t);
Ответ 7
Вы можете попробовать что-то связать это:
string str = "ABCDEFGHIJ";
str = str.Substring(0, 2) + "ZX" + str.Substring(5);
Ответ 8
Как и другие, упомянутая функция Substring()
существует по какой-то причине:
static void Main(string[] args)
{
string input = "ABCDEFGHIJ";
string output = input.Overwrite(3, "ZX"); // 4th position has index 3
// ABCZXFGHIJ
}
public static string Overwrite(this string text, int position, string new_text)
{
return text.Substring(0, position) + new_text + text.Substring(position + new_text.Length);
}
Также я приурочил это к решению StringBuilder
и получил 900 тиков против 875. Так что он немного медленнее.
Ответ 9
Все остальные ответы не работают, если строка содержит символ Unicode (например, Emojis), потому что символ Unicode весит больше байтов, чем символ.
Пример: смайлики '🎶', преобразованные в байты, будут весить эквивалент 2 символов. Таким образом, если символ unicode находится в начале вашей строки, параметр offset
будет смещен).
В этой теме я расширил класс StringInfo до Replace by position, сохраняя алгоритм Ника Миллера, чтобы избежать этого:
public static class StringInfoUtils
{
public static string ReplaceByPosition(this string str, string replaceBy, int offset, int count)
{
return new StringInfo(str).ReplaceByPosition(replaceBy, offset, count).String;
}
public static StringInfo ReplaceByPosition(this StringInfo str, string replaceBy, int offset, int count)
{
return str.RemoveByTextElements(offset, count).InsertByTextElements(offset, replaceBy);
}
public static StringInfo RemoveByTextElements(this StringInfo str, int offset, int count)
{
return new StringInfo(string.Concat(
str.SubstringByTextElements(0, offset),
offset + count < str.LengthInTextElements
? str.SubstringByTextElements(offset + count, str.LengthInTextElements - count - offset)
: ""
));
}
public static StringInfo InsertByTextElements(this StringInfo str, int offset, string insertStr)
{
if (string.IsNullOrEmpty(str?.String))
return new StringInfo(insertStr);
return new StringInfo(string.Concat(
str.SubstringByTextElements(0, offset),
insertStr,
str.LengthInTextElements - offset > 0 ? str.SubstringByTextElements(offset, str.LengthInTextElements - offset) : ""
));
}
}
Ответ 10
С помощью этого сообщения я создаю следующую функцию с дополнительными проверками длины
public string ReplaceStringByIndex(string original, string replaceWith, int replaceIndex)
{
if (original.Length >= (replaceIndex + replaceWith.Length))
{
StringBuilder rev = new StringBuilder(original);
rev.Remove(replaceIndex, replaceWith.Length);
rev.Insert(replaceIndex, replaceWith);
return rev.ToString();
}
else
{
throw new Exception("Wrong lengths for the operation");
}
}
Ответ 11
Еще один
public static string ReplaceAtPosition(this string self, int position, string newValue)
{
return self.Remove(position, newValue.Length).Insert(position, newValue);
}
Ответ 12
Если вы заботитесь о производительности, то здесь вам следует избегать распределения. А если вы используете .Net Core 2. 1+ (или, пока не выпущенный,.Net Standard 2.1), то вы можете, используя метод string.Create
:
public static string ReplaceAt(this string str, int index, int length, string replace)
{
return string.Create(str.Length - length + replace.Length, (str, index, length, replace),
(span, state) =>
{
state.str.AsSpan().Slice(0, state.index).CopyTo(span);
state.replace.AsSpan().CopyTo(span.Slice(state.index));
state.str.AsSpan().Slice(state.index + state.length).CopyTo(span.Slice(state.index + state.replace.Length));
});
}
Этот подход сложнее для понимания, чем альтернативы, но он единственный, который выделяет только один объект на вызов: вновь созданная строка.
Ответ 13
Я искал решение со следующими требованиями:
- использовать только одно однострочное выражение
- использовать только системные встроенные методы (нет пользовательских утилит)
Решение 1
Решение, которое лучше всего подходит мне, это:
// replace 'oldString[i]' with 'c'
string newString = new StringBuilder(oldString).Replace(oldString[i], c, i, 1).ToString();
Это использует StringBuilder.Replace(oldChar, newChar, position, count)
Решение 2
Другое решение, которое удовлетворяет моим требованиям, - использовать Substring
с конкатенацией:
string newString = oldStr.Substring(0, i) + c + oldString.Substring(i+1, oldString.Length);
Это тоже нормально. Я думаю, что это не так эффективно, как в первом по производительности (из-за ненужной конкатенации строк). Но преждевременная оптимизация - корень всего зла.
Так что выбирайте тот, который вам нравится больше всего :)
Ответ 14
Лучше использовать String.substr()
.
Вот так:
ReplString = GivenStr.substr(0, PostostarRelStr)
+ GivenStr(PostostarRelStr, ReplString.lenght());
Ответ 15
string myString = "ABCDEFGHIJ";
string modifiedString = new StringBuilder(myString){[3]='Z', [4]='X'}.ToString();
Позвольте мне объяснить мое решение.
Учитывая постановку задачи изменения строки в двух ее конкретных позициях ("от позиции 4 до позиции 5") с двумя символами "Z" и "X", и возникает вопрос об использовании индекса позиции для изменения строки, а не метода Replace() строки (может быть из-за возможности повторения некоторых символов в реальной строке), я бы предпочел использовать минималистский подход для достижения цели, используя подходы Substring()
и string Concat()
или string Remove()
и Insert()
. Хотя все эти решения будут служить цели в достижении той же цели, но это зависит только от личного выбора и философии урегулирования с минималистским подходом.
Возвращаясь к моему решению, о котором говорилось выше, если мы поближе рассмотрим string
и StringBuilder
, оба они внутренне воспринимают данную строку как массив символов. Если мы посмотрим на реализацию StringBuilder
, она поддерживает внутреннюю переменную, похожую на 'internal char[] m_ChunkChars;
', для захвата заданной строки. Теперь, поскольку это внутренняя переменная, мы не можем напрямую обращаться к ней. Для внешнего мира, чтобы иметь возможность получить доступ и изменить этот массив символов, StringBuilder
предоставляет их через свойство indexer, которое выглядит примерно так:
[IndexerName("Chars")]
public char this[int index]
{
get
{
StringBuilder stringBuilder = this;
do
{
// … some code
return stringBuilder.m_ChunkChars[index1];
// … some more code
}
}
set
{
StringBuilder stringBuilder = this;
do
{
//… some code
stringBuilder.m_ChunkChars[index1] = value;
return;
// …. Some more code
}
}
}
Мое решение, упомянутое выше, использует эту возможность индексатора для непосредственного изменения внутреннего символьного массива, который IMO эффективен и минималистичен.
КСТАТИ; мы можем переписать вышеприведенное решение более детально, как показано ниже
string myString = "ABCDEFGHIJ";
StringBuilder tempString = new StringBuilder(myString);
tempString[3] = 'Z';
tempString[4] = 'X';
string modifiedString = tempString.ToString();
В этом контексте также хотелось бы отметить, что в случае string
он также имеет свойство indexer как средство для представления своего внутреннего символьного массива, но в этом случае у него есть только свойство Getter (и нет Setter), поскольку строка неизменный в природе. И именно поэтому нам нужно использовать StringBuilder
для изменения массива символов.
[IndexerName("Chars")]
public extern char this[int index] { [SecuritySafeCritical, __DynamicallyInvokable, MethodImpl(MethodImplOptions.InternalCall)] get; }
И последнее, но не менее важное: это решение наилучшим образом подходит для этой конкретной проблемы, когда требуется заменить только несколько символов с заранее известным индексом позиции. Это может быть не лучшим вариантом, когда требуется изменить довольно длинную строку, т.е. количество символов для изменения велико.
Ответ 16
String timestamp = "2019-09-18 21.42.05.000705";
String sub1 = timestamp.substring(0, 19).replace('.', ':');
String sub2 = timestamp.substring(19, timestamp.length());
System.out.println("Original String "+ timestamp);
System.out.println("Replaced Value "+ sub1+sub2);
Ответ 17
Я считаю, что самым простым способом было бы это: (без stringbuilder)
string myString = "ABCDEFGHIJ";
char[] replacementChars = {'Z', 'X'};
byte j = 0;
for (byte i = 3; i <= 4; i++, j++)
{
myString = myString.Replace(myString[i], replacementChars[j]);
}
Это работает, потому что переменную типа string можно рассматривать как массив переменных char.
Вы можете, например, обратиться ко второму символу строковой переменной с именем "myString" как myString [1]