Tôi có chuỗi này: ABCDEFGHIJ
Tôi cần thay thế từ vị trí 4 sang vị trí 5 bằng chuỗi ZX
Nó sẽ trông giống thế này: ABCZXFGHIJ
Nhưng không sử dụng với string.replace("DE","ZX")
- Tôi cần sử dụng với vị trí
Tôi làm nó như thế nào?
Tôi có chuỗi này: ABCDEFGHIJ
Tôi cần thay thế từ vị trí 4 sang vị trí 5 bằng chuỗi ZX
Nó sẽ trông giống thế này: ABCZXFGHIJ
Nhưng không sử dụng với string.replace("DE","ZX")
- Tôi cần sử dụng với vị trí
Tôi làm nó như thế nào?
Câu trả lời:
Cách dễ nhất để thêm và xóa phạm vi trong chuỗi là sử dụng StringBuilder
.
var theString = "ABCDEFGHIJ";
var aStringBuilder = new StringBuilder(theString);
aStringBuilder.Remove(3, 2);
aStringBuilder.Insert(3, "ZX");
theString = aStringBuilder.ToString();
Một cách khác là sử dụng String.Substring
, nhưng tôi nghĩ StringBuilder
mã dễ đọc hơn.
string s = "ABCDEFGH";
s= s.Remove(3, 2).Insert(3, "ZX");
Đây là một phương thức mở rộng không sử dụng StringBuilder hoặc Sub Chuỗi. Phương pháp này cũng cho phép chuỗi thay thế kéo dài quá độ dài của chuỗi nguồn.
//// 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);
}
Khi sử dụng chức năng này, nếu bạn muốn toàn bộ chuỗi thay thế thay thế càng nhiều ký tự càng tốt, thì hãy đặt độ dài thành độ dài của chuỗi thay thế:
"0123456789".ReplaceAt(7, 5, "Hello") = "0123456Hello"
Nếu không, bạn có thể chỉ định số lượng ký tự sẽ bị xóa:
"0123456789".ReplaceAt(2, 2, "Hello") = "01Hello456789"
Nếu bạn chỉ định độ dài là 0, thì hàm này hoạt động giống như hàm chèn:
"0123456789".ReplaceAt(4, 0, "Hello") = "0123Hello456789"
Tôi đoán điều này hiệu quả hơn vì lớp StringBuilder không cần phải được khởi tạo và vì nó sử dụng các hoạt động cơ bản hơn. Xin hãy sửa tôi nếu tôi sai. :)
Sử dụng String.Substring()
(chi tiết tại đây ) để cắt phần bên trái, sau đó thay thế phần của bạn, sau đó phần bên phải. Chơi với các chỉ mục cho đến khi bạn hiểu đúng :)
Cái gì đó như:
string replacement=original.Substring(0,start)+
rep+original.Substring(start+rep.Length);
Là một phương pháp mở rộng.
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();
}
}
string s = "ABCDEFG";
string t = "st";
s = s.Remove(4, t.Length);
s = s.Insert(4, t);
t
lại.
Nếu bạn quan tâm đến hiệu suất, thì điều bạn muốn tránh ở đây là phân bổ. Và nếu bạn đang ở trên Net Lõi 2.1 + (hoặc, như được nêu ra chưa được phát hành, Net Chuẩn 2.1), sau đó bạn có thể, bằng cách sử dụng các string.Create
phương pháp :
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));
});
}
Cách tiếp cận này khó hiểu hơn các lựa chọn thay thế, nhưng đó là cách duy nhất sẽ chỉ phân bổ một đối tượng cho mỗi cuộc gọi: chuỗi mới được tạo.
Giống như khác đã đề cập Substring()
chức năng là có vì một lý do:
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);
}
Ngoài ra tôi đã tính thời gian này với StringBuilder
giải pháp và nhận được 900 tics so với 875. Vì vậy, nó hơi chậm.
"ABCDEFGHIJ"
và "ZX"
có độ dài khác nhau.
Còn cái khác
public static string ReplaceAtPosition(this string self, int position, string newValue)
{
return self.Remove(position, newValue.Length).Insert(position, newValue);
}
Với sự giúp đỡ của bài đăng này, tôi tạo chức năng sau với các kiểm tra độ dài bổ sung
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");
}
}
Tất cả các câu trả lời khác không hoạt động nếu chuỗi chứa char char (như Biểu tượng cảm xúc) vì một char char có trọng lượng nhiều byte hơn một char.
Ví dụ : biểu tượng cảm xúc '' được chuyển đổi thành byte, sẽ có trọng số tương đương với 2 ký tự. Vì vậy, nếu char unicode được đặt ở đầu chuỗi của bạn,
offset
tham số sẽ được thay đổi).
Với chủ đề này , tôi mở rộng lớp StringInfo thành Thay thế bằng cách giữ vị trí thuật toán của Nick Miller để tránh điều đó:
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) : ""
));
}
}
Tôi đang tìm kiếm một giải pháp với các yêu cầu sau:
Giải pháp phù hợp nhất với tôi là:
// replace `oldString[i]` with `c`
string newString = new StringBuilder(oldString).Replace(oldString[i], c, i, 1).ToString();
Cái này dùng StringBuilder.Replace(oldChar, newChar, position, count)
Giải pháp khác thỏa mãn yêu cầu của tôi là sử dụng Substring
kết hợp:
string newString = oldStr.Substring(0, i) + c + oldString.Substring(i+1, oldString.Length);
Điều này cũng tốt Tôi đoán nó không hiệu quả như lần đầu tiên thực hiện (do nối chuỗi không cần thiết). Nhưng tối ưu hóa sớm là gốc rễ của mọi tội lỗi .
Vì vậy, chọn một trong đó bạn thích nhất :)
Tốt hơn là sử dụng String.substr()
.
Như thế này:
ReplString = GivenStr.substr(0, PostostarRelStr)
+ GivenStr(PostostarRelStr, ReplString.lenght());
string myString = "ABCDEFGHIJ";
string modifiedString = new StringBuilder(myString){[3]='Z', [4]='X'}.ToString();
Hãy để tôi giải thích giải pháp của tôi.
Đưa ra tuyên bố vấn đề về việc thay đổi một chuỗi ở hai vị trí cụ thể của nó (vị trí 4 đến vị trí 5) với hai ký tự 'Z' và 'X' và yêu cầu là sử dụng chỉ mục vị trí để thay đổi chuỗi và không thay thế chuỗi ( ) phương thức (có thể là do khả năng lặp lại của một số ký tự trong chuỗi thực tế), tôi thích sử dụng phương pháp tối giản để đạt được mục tiêu sử dụng Substring()
và chuỗi Concat()
hoặc chuỗi Remove()
và Insert()
cách tiếp cận. Mặc dù tất cả những giải pháp đó sẽ phục vụ mục đích đạt được cùng một mục tiêu, nhưng nó chỉ phụ thuộc vào lựa chọn cá nhân và triết lý giải quyết theo phương pháp tối giản.
Quay trở lại với giải pháp của tôi đã đề cập ở trên, nếu chúng ta xem xét kỹ hơn vềstring
vàStringBuilder
, cả hai bên trong đều coi một chuỗi đã cho là một mảng các ký tự. Nếu chúng ta nhìn vào việc thực hiện StringBuilder
thì nó sẽ duy trì một biến nội bộ giống như (cơ bản internal char[] m_ChunkChars;
) để nắm bắt chuỗi đã cho. Bây giờ vì đây là một biến nội bộ, chúng tôi không thể truy cập trực tiếp như vậy. Đối với thế giới bên ngoài, để có thể truy cập và thay đổi mảng ký tự đó, hãy StringBuilder
hiển thị chúng thông qua thuộc tính bộ chỉ mục trông giống như bên dưới
[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
}
}
}
Giải pháp của tôi được đề cập ở trên tận dụng khả năng lập chỉ mục này để thay đổi trực tiếp mảng ký tự được duy trì bên trong mà IMO là hiệu quả và tối giản.
BTW; chúng ta có thể viết lại giải pháp trên một cách công phu hơn
string myString = "ABCDEFGHIJ";
StringBuilder tempString = new StringBuilder(myString);
tempString[3] = 'Z';
tempString[4] = 'X';
string modifiedString = tempString.ToString();
Trong bối cảnh này cũng muốn đề cập rằng trong trường hợp string
nó cũng có thuộc tính bộ chỉ mục làm phương tiện để hiển thị mảng ký tự bên trong của nó, nhưng trong trường hợp này, nó chỉ có thuộc tính Getter (và không có Setter) vì bản chất chuỗi là bất biến. Và đó là lý do tại sao chúng ta cần sử dụng StringBuilder
để thay đổi mảng ký tự.
[IndexerName("Chars")]
public extern char this[int index] { [SecuritySafeCritical, __DynamicallyInvokable, MethodImpl(MethodImplOptions.InternalCall)] get; }
Và cuối cùng nhưng không kém phần quan trọng, giải pháp này chỉ phù hợp nhất cho vấn đề cụ thể này, trong đó yêu cầu là chỉ thay thế một vài ký tự bằng một chỉ số vị trí đã biết trước. Nó có thể không phù hợp nhất khi yêu cầu là thay đổi một chuỗi khá dài, tức là số lượng ký tự cần thay đổi là số lượng lớn.
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);
Đây là một phương pháp mở rộng đơn giản:
public static class StringBuilderExtensions
{
public static StringBuilder Replace(this StringBuilder sb, int position, string newString)
=> sb.Replace(position, newString.Length, newString);
public static StringBuilder Replace(this StringBuilder sb, int position, int length, string newString)
=> (newString.Length <= length)
? sb.Remove(position, newString.Length).Insert(position, newString)
: sb.Remove(position, length).Insert(position, newString.Substring(0, length));
}
Sử dụng nó như thế này:
var theString = new string(' ', 10);
var sb = new StringBuilder(theString);
sb.Replace(5, "foo");
return sb.ToString();
Tôi tin rằng cách đơn giản nhất sẽ là thế này: (không có người xây dựng chuỗi)
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]);
}
Điều này hoạt động vì một biến của chuỗi kiểu có thể được coi là một mảng các biến char. Ví dụ, bạn có thể tham khảo ký tự thứ hai của biến chuỗi có tên "myString" là myString [1]
string
các ký tự được thay thế chỉ xảy ra một lần. Nếu bạn chống lại điều này, giả sử, "DBCDEFGHIE"
sau đó bạn nhận được "ZBCZXFGHIX"
, đó không phải là kết quả mong muốn. Ngoài ra, tôi sẽ không đồng ý rằng việc này đơn giản hơn các StringBuilder
giải pháp không phải khác đã được đăng cách đây hai năm rưỡi.